mirror of
				https://github.com/TeaOSLab/EdgeAdmin.git
				synced 2025-11-04 13:10:26 +08:00 
			
		
		
		
	增加套餐相关代码
This commit is contained in:
		@@ -19,6 +19,7 @@ const (
 | 
				
			|||||||
	AdminModuleCodeAdmin     AdminModuleCode = "admin"     // 系统用户
 | 
						AdminModuleCodeAdmin     AdminModuleCode = "admin"     // 系统用户
 | 
				
			||||||
	AdminModuleCodeUser      AdminModuleCode = "user"      // 平台用户
 | 
						AdminModuleCodeUser      AdminModuleCode = "user"      // 平台用户
 | 
				
			||||||
	AdminModuleCodeFinance   AdminModuleCode = "finance"   // 财务
 | 
						AdminModuleCodeFinance   AdminModuleCode = "finance"   // 财务
 | 
				
			||||||
 | 
						AdminModuleCodePlan      AdminModuleCode = "plan"      // 套餐
 | 
				
			||||||
	AdminModuleCodeLog       AdminModuleCode = "log"       // 日志
 | 
						AdminModuleCodeLog       AdminModuleCode = "log"       // 日志
 | 
				
			||||||
	AdminModuleCodeSetting   AdminModuleCode = "setting"   // 设置
 | 
						AdminModuleCodeSetting   AdminModuleCode = "setting"   // 设置
 | 
				
			||||||
	AdminModuleCodeCommon    AdminModuleCode = "common"    // 只要登录就可以访问的模块
 | 
						AdminModuleCodeCommon    AdminModuleCode = "common"    // 只要登录就可以访问的模块
 | 
				
			||||||
@@ -203,6 +204,11 @@ func AllModuleMaps() []maps.Map {
 | 
				
			|||||||
			"code": AdminModuleCodeFinance,
 | 
								"code": AdminModuleCodeFinance,
 | 
				
			||||||
			"url":  "/finance",
 | 
								"url":  "/finance",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"name": "套餐管理",
 | 
				
			||||||
 | 
								"code": AdminModuleCodePlan,
 | 
				
			||||||
 | 
								"url":  "/plans",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"name": "日志审计",
 | 
								"name": "日志审计",
 | 
				
			||||||
			"code": AdminModuleCodeLog,
 | 
								"code": AdminModuleCodeLog,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -464,6 +464,14 @@ 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())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Context 构造Admin上下文
 | 
					// Context 构造Admin上下文
 | 
				
			||||||
func (this *RPCClient) Context(adminId int64) context.Context {
 | 
					func (this *RPCClient) Context(adminId int64) context.Context {
 | 
				
			||||||
	ctx := context.Background()
 | 
						ctx := context.Background()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,8 @@ type ParentAction struct {
 | 
				
			|||||||
	actions.ActionObject
 | 
						actions.ActionObject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rpcClient *rpc.RPCClient
 | 
						rpcClient *rpc.RPCClient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx context.Context
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Parent 可以调用自身的一个简便方法
 | 
					// Parent 可以调用自身的一个简便方法
 | 
				
			||||||
@@ -117,6 +119,10 @@ func (this *ParentAction) RPC() *rpc.RPCClient {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// AdminContext 获取Context
 | 
					// AdminContext 获取Context
 | 
				
			||||||
func (this *ParentAction) AdminContext() context.Context {
 | 
					func (this *ParentAction) AdminContext() context.Context {
 | 
				
			||||||
 | 
						if this.ctx != nil {
 | 
				
			||||||
 | 
							return this.ctx
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if this.rpcClient == nil {
 | 
						if this.rpcClient == nil {
 | 
				
			||||||
		rpcClient, err := rpc.SharedRPC()
 | 
							rpcClient, err := rpc.SharedRPC()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -125,7 +131,8 @@ func (this *ParentAction) AdminContext() context.Context {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		this.rpcClient = rpcClient
 | 
							this.rpcClient = rpcClient
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return this.rpcClient.Context(this.AdminId())
 | 
						this.ctx = this.rpcClient.Context(this.AdminId())
 | 
				
			||||||
 | 
						return this.ctx
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ViewData 视图里可以使用的数据
 | 
					// ViewData 视图里可以使用的数据
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -374,6 +374,21 @@ func (this *userMustAuth) modules(actionPtr actions.ActionWrapper, adminId int64
 | 
				
			|||||||
			"icon":   "yen sign",
 | 
								"icon":   "yen sign",
 | 
				
			||||||
			"isOn":   teaconst.IsPlus,
 | 
								"isOn":   teaconst.IsPlus,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							/**{
 | 
				
			||||||
 | 
								"code":   "plans",
 | 
				
			||||||
 | 
								"module": configloaders.AdminModuleCodePlan,
 | 
				
			||||||
 | 
								"name":   "套餐管理",
 | 
				
			||||||
 | 
								"icon":   "puzzle piece",
 | 
				
			||||||
 | 
								"isOn":   teaconst.IsPlus,
 | 
				
			||||||
 | 
								"subItems": []maps.Map{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "已购套餐",
 | 
				
			||||||
 | 
										"url":  "/plans/userPlans",
 | 
				
			||||||
 | 
										"code": "userPlans",
 | 
				
			||||||
 | 
										"isOn": teaconst.IsPlus,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},**/
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"code":     "admins",
 | 
								"code":     "admins",
 | 
				
			||||||
			"module":   configloaders.AdminModuleCodeAdmin,
 | 
								"module":   configloaders.AdminModuleCodeAdmin,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										34
									
								
								web/public/js/components/common/datepicker.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								web/public/js/components/common/datepicker.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					Vue.component("datepicker", {
 | 
				
			||||||
 | 
						props: ["v-name", "v-value", "v-bottom-left"],
 | 
				
			||||||
 | 
						mounted: function () {
 | 
				
			||||||
 | 
							let that = this
 | 
				
			||||||
 | 
							teaweb.datepicker(this.$refs.dayInput, function (v) {
 | 
				
			||||||
 | 
								that.day = v
 | 
				
			||||||
 | 
								that.change()
 | 
				
			||||||
 | 
							}, !!this.vBottomLeft)
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						data: function () {
 | 
				
			||||||
 | 
							let name = this.vName
 | 
				
			||||||
 | 
							if (name == null) {
 | 
				
			||||||
 | 
								name = "day"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let day = this.vValue
 | 
				
			||||||
 | 
							if (day == null) {
 | 
				
			||||||
 | 
								day = ""
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return {
 | 
				
			||||||
 | 
								name: name,
 | 
				
			||||||
 | 
								day: day
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						methods: {
 | 
				
			||||||
 | 
							change: function () {
 | 
				
			||||||
 | 
								this.$emit("change", this.day)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						template: `<div style="display: inline-block">
 | 
				
			||||||
 | 
						<input type="text" :name="name" v-model="day" placeholder="YYYY-MM-DD" style="width:8.6em" maxlength="10" @input="change" ref="dayInput" autocomplete="off"/>
 | 
				
			||||||
 | 
					</div>`
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										166
									
								
								web/public/js/components/plans/plan-price-config-box.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								web/public/js/components/plans/plan-price-config-box.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,166 @@
 | 
				
			|||||||
 | 
					// 套餐价格配置
 | 
				
			||||||
 | 
					Vue.component("plan-price-config-box", {
 | 
				
			||||||
 | 
						props: ["v-price-type", "v-monthly-price", "v-seasonally-price", "v-yearly-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) {
 | 
				
			||||||
 | 
								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 bandwidthPrice = this.vBandwidthPrice
 | 
				
			||||||
 | 
							let bandwidthPriceBaseNumber = 0
 | 
				
			||||||
 | 
							if (bandwidthPrice != null) {
 | 
				
			||||||
 | 
								bandwidthPriceBaseNumber = bandwidthPrice.base
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								bandwidthPrice = {
 | 
				
			||||||
 | 
									base: 0
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							let bandwidthPriceBase = ""
 | 
				
			||||||
 | 
							if (bandwidthPriceBaseNumber > 0) {
 | 
				
			||||||
 | 
								bandwidthPriceBase = bandwidthPriceBaseNumber.toString()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return {
 | 
				
			||||||
 | 
								priceType: priceType,
 | 
				
			||||||
 | 
								monthlyPrice: monthlyPrice,
 | 
				
			||||||
 | 
								seasonallyPrice: seasonallyPrice,
 | 
				
			||||||
 | 
								yearlyPrice: yearlyPrice,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								monthlyPriceNumber: monthlyPriceNumber,
 | 
				
			||||||
 | 
								seasonallyPriceNumber: seasonallyPriceNumber,
 | 
				
			||||||
 | 
								yearlyPriceNumber: yearlyPriceNumber,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								bandwidthPriceBase: bandwidthPriceBase,
 | 
				
			||||||
 | 
								bandwidthPrice: bandwidthPrice
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						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
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							bandwidthPriceBase: function (v) {
 | 
				
			||||||
 | 
								let price = parseFloat(v)
 | 
				
			||||||
 | 
								if (isNaN(price)) {
 | 
				
			||||||
 | 
									price = 0
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								this.bandwidthPrice.base = price
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						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="bandwidthPriceJSON" :value="JSON.stringify(bandwidthPrice)"/>
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						<div>
 | 
				
			||||||
 | 
							<radio :v-value="'period'" :value="priceType" v-model="priceType"> 按时间周期</radio>    
 | 
				
			||||||
 | 
							<radio :v-value="'bandwidth'" :value="priceType" v-model="priceType"> 按带宽用量</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 =='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" v-model="bandwidthPriceBase" maxlength="10" style="width: 7em"/>
 | 
				
			||||||
 | 
											<span class="ui label">元/GB</span>
 | 
				
			||||||
 | 
										</div>
 | 
				
			||||||
 | 
									</td>
 | 
				
			||||||
 | 
								</tr>
 | 
				
			||||||
 | 
							</table>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					</div>`
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										18
									
								
								web/public/js/components/plans/plan-price-view.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								web/public/js/components/plans/plan-price-view.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					Vue.component("plan-price-view", {
 | 
				
			||||||
 | 
						props: ["v-plan"],
 | 
				
			||||||
 | 
						data: function () {
 | 
				
			||||||
 | 
							return {
 | 
				
			||||||
 | 
								plan: this.vPlan
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						template: `<div>
 | 
				
			||||||
 | 
						 <span v-if="plan.priceType == 'period'">
 | 
				
			||||||
 | 
							<span v-if="plan.monthlyPrice > 0">月度:¥{{plan.monthlyPrice}}元<br/></span>
 | 
				
			||||||
 | 
							<span v-if="plan.seasonallyPrice > 0">季度:¥{{plan.seasonallyPrice}}元<br/></span>
 | 
				
			||||||
 | 
							<span v-if="plan.yearlyPrice > 0">年度:¥{{plan.yearlyPrice}}元</span>
 | 
				
			||||||
 | 
						</span>
 | 
				
			||||||
 | 
						<span v-if="plan.priceType == 'bandwidth'">
 | 
				
			||||||
 | 
							基础价格:¥{{plan.bandwidthPrice.base}}元/GB
 | 
				
			||||||
 | 
						</span>
 | 
				
			||||||
 | 
					</div>`
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										28
									
								
								web/public/js/components/plans/plan-user-selector.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								web/public/js/components/plans/plan-user-selector.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					Vue.component("plan-user-selector", {
 | 
				
			||||||
 | 
						mounted: function () {
 | 
				
			||||||
 | 
							let that = this
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Tea.action("/plans/users/options")
 | 
				
			||||||
 | 
								.post()
 | 
				
			||||||
 | 
								.success(function (resp) {
 | 
				
			||||||
 | 
									that.users = resp.data.users
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						props: ["v-user-id"],
 | 
				
			||||||
 | 
						data: function () {
 | 
				
			||||||
 | 
							let userId = this.vUserId
 | 
				
			||||||
 | 
							if (userId == null) {
 | 
				
			||||||
 | 
								userId = 0
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return {
 | 
				
			||||||
 | 
								users: [],
 | 
				
			||||||
 | 
								userId: userId
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						template: `<div>
 | 
				
			||||||
 | 
						<select class="ui dropdown auto-width" name="userId" v-model="userId">
 | 
				
			||||||
 | 
							<option value="0">[选择用户]</option>
 | 
				
			||||||
 | 
							<option v-for="user in users" :value="user.id">{{user.fullname}} ({{user.username}})</option>
 | 
				
			||||||
 | 
						</select>
 | 
				
			||||||
 | 
					</div>`
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										16
									
								
								web/public/js/components/server/bandwidth-limit-view.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								web/public/js/components/server/bandwidth-limit-view.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					// 显示带宽限制说明
 | 
				
			||||||
 | 
					Vue.component("bandwidth-limit-view", {
 | 
				
			||||||
 | 
						props: ["v-bandwidth-limit"],
 | 
				
			||||||
 | 
						data: function () {
 | 
				
			||||||
 | 
							return {
 | 
				
			||||||
 | 
								config: this.vBandwidthLimit
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						template: `<div>
 | 
				
			||||||
 | 
						<div v-if="config.isOn">
 | 
				
			||||||
 | 
							<span v-if="config.dailySize != null && config.dailySize.count > 0">日带宽限制:{{config.dailySize.count}}{{config.dailySize.unit.toUpperCase()}}<br/></span>
 | 
				
			||||||
 | 
							<span v-if="config.monthlySize != null && config.monthlySize.count > 0">月带宽限制:{{config.monthlySize.count}}{{config.monthlySize.unit.toUpperCase()}}<br/></span>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
						<span v-else class="disabled">没有限制。</span>
 | 
				
			||||||
 | 
					</div>`
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
@@ -69,13 +69,13 @@ window.teaweb = {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		document.head.append(element)
 | 
							document.head.append(element)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	datepicker: function (element, callback) {
 | 
						datepicker: function (element, callback, bottomLeft) {
 | 
				
			||||||
		// 加载
 | 
							// 加载
 | 
				
			||||||
		if (typeof Pikaday == "undefined") {
 | 
							if (typeof Pikaday == "undefined") {
 | 
				
			||||||
			let that = this
 | 
								let that = this
 | 
				
			||||||
			this.loadJS("/js/moment.min.js", function () {
 | 
								this.loadJS("/js/moment.min.js", function () {
 | 
				
			||||||
				that.loadJS("/js/pikaday.js", function () {
 | 
									that.loadJS("/js/pikaday.js", function () {
 | 
				
			||||||
					that.datepicker(element, callback)
 | 
										that.datepicker(element, callback, bottomLeft)
 | 
				
			||||||
				})
 | 
									})
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			this.loadCSS("/js/pikaday.css")
 | 
								this.loadCSS("/js/pikaday.css")
 | 
				
			||||||
@@ -89,8 +89,8 @@ window.teaweb = {
 | 
				
			|||||||
		if (typeof (element) == "string") {
 | 
							if (typeof (element) == "string") {
 | 
				
			||||||
			element = document.getElementById(element);
 | 
								element = document.getElementById(element);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		var year = new Date().getFullYear();
 | 
							let year = new Date().getFullYear();
 | 
				
			||||||
		var picker = new Pikaday({
 | 
							let picker = new Pikaday({
 | 
				
			||||||
			field: element,
 | 
								field: element,
 | 
				
			||||||
			firstDay: 1,
 | 
								firstDay: 1,
 | 
				
			||||||
			minDate: new Date(year - 1, 0, 1),
 | 
								minDate: new Date(year - 1, 0, 1),
 | 
				
			||||||
@@ -109,8 +109,9 @@ window.teaweb = {
 | 
				
			|||||||
				if (typeof (callback) == "function") {
 | 
									if (typeof (callback) == "function") {
 | 
				
			||||||
					callback.call(Tea.Vue, picker.toString());
 | 
										callback.call(Tea.Vue, picker.toString());
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								},
 | 
				
			||||||
		});
 | 
								reposition: !bottomLeft
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	formatBytes: function (bytes) {
 | 
						formatBytes: function (bytes) {
 | 
				
			||||||
@@ -256,6 +257,21 @@ window.teaweb = {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
						popupSuccess: function (url, width, height) {
 | 
				
			||||||
 | 
							let options = {}
 | 
				
			||||||
 | 
							if (width != null) {
 | 
				
			||||||
 | 
								options["width"] = width
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (height != null) {
 | 
				
			||||||
 | 
								options["height"] = height
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							options["callback"] = function () {
 | 
				
			||||||
 | 
								teaweb.success("保存成功", function () {
 | 
				
			||||||
 | 
									teaweb.reload()
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							this.popup(url, options)
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
	popupFinish: function () {
 | 
						popupFinish: function () {
 | 
				
			||||||
		if (window.POPUP_CALLBACK != null) {
 | 
							if (window.POPUP_CALLBACK != null) {
 | 
				
			||||||
			window.POPUP_CALLBACK.apply(window, arguments);
 | 
								window.POPUP_CALLBACK.apply(window, arguments);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@
 | 
				
			|||||||
        <menu-item :href="'/servers/certs/acme?type=available&keyword=' + keyword" :active="type == 'available'">有效证书({{countAvailable}})</menu-item>
 | 
					        <menu-item :href="'/servers/certs/acme?type=available&keyword=' + keyword" :active="type == 'available'">有效证书({{countAvailable}})</menu-item>
 | 
				
			||||||
        <menu-item :href="'/servers/certs/acme?type=expired&keyword=' + keyword" :active="type == 'expired'">过期证书<span :class="{red: countExpired > 0}">({{countExpired}})</span></menu-item>
 | 
					        <menu-item :href="'/servers/certs/acme?type=expired&keyword=' + keyword" :active="type == 'expired'">过期证书<span :class="{red: countExpired > 0}">({{countExpired}})</span></menu-item>
 | 
				
			||||||
        <menu-item :href="'/servers/certs/acme?type=7days&keyword=' + keyword" :active="type == '7days'">7天内过期<span :class="{red: count7Days > 0}">({{count7Days}})</span></menu-item>
 | 
					        <menu-item :href="'/servers/certs/acme?type=7days&keyword=' + keyword" :active="type == '7days'">7天内过期<span :class="{red: count7Days > 0}">({{count7Days}})</span></menu-item>
 | 
				
			||||||
        <menu-item :href="'/servers/certs/acme?type=30days&keyword=' + keyword" :active="type == '30days'">30天过期({{count30Days}})</menu-item>
 | 
					        <menu-item :href="'/servers/certs/acme?type=30days&keyword=' + keyword" :active="type == '30days'">30天内过期({{count30Days}})</menu-item>
 | 
				
			||||||
        <div class="item right">
 | 
					        <div class="item right">
 | 
				
			||||||
            <form class="ui form">
 | 
					            <form class="ui form">
 | 
				
			||||||
                <div class="ui fields inline">
 | 
					                <div class="ui fields inline">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,8 +8,8 @@
 | 
				
			|||||||
		<menu-item :href="'/servers/certs?type=available&keyword=' + keyword" :active="type == 'available'">有效证书({{countAvailable}})</menu-item>
 | 
							<menu-item :href="'/servers/certs?type=available&keyword=' + keyword" :active="type == 'available'">有效证书({{countAvailable}})</menu-item>
 | 
				
			||||||
		<menu-item :href="'/servers/certs?type=expired&keyword=' + keyword" :active="type == 'expired'">过期证书<span :class="{red: countExpired > 0}">({{countExpired}})</span></menu-item>
 | 
							<menu-item :href="'/servers/certs?type=expired&keyword=' + keyword" :active="type == 'expired'">过期证书<span :class="{red: countExpired > 0}">({{countExpired}})</span></menu-item>
 | 
				
			||||||
		<menu-item :href="'/servers/certs?type=7days&keyword=' + keyword" :active="type == '7days'">7天内过期<span :class="{red: count7Days > 0}">({{count7Days}})</span></menu-item>
 | 
							<menu-item :href="'/servers/certs?type=7days&keyword=' + keyword" :active="type == '7days'">7天内过期<span :class="{red: count7Days > 0}">({{count7Days}})</span></menu-item>
 | 
				
			||||||
		<menu-item :href="'/servers/certs?type=30days&keyword=' + keyword" :active="type == '30days'">30天过期({{count30Days}})</menu-item>
 | 
							<menu-item :href="'/servers/certs?type=30days&keyword=' + keyword" :active="type == '30days'">30天内过期({{count30Days}})</menu-item>
 | 
				
			||||||
		<span class="item">|</span>
 | 
							<span class="item disabled">|</span>
 | 
				
			||||||
		<a href="" class="item" @click.prevent="uploadCert">[上传证书]</a>
 | 
							<a href="" class="item" @click.prevent="uploadCert">[上传证书]</a>
 | 
				
			||||||
	</second-menu>
 | 
						</second-menu>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user