285 lines
7.1 KiB
Vue
285 lines
7.1 KiB
Vue
<template>
|
|
<Card
|
|
title="Plan"
|
|
:subtitle="
|
|
site.status == 'Suspended'
|
|
? 'Set a plan to activate your suspended site'
|
|
: 'Upgrade or downgrade your plan based on your usage'
|
|
"
|
|
v-if="site.status != 'Inactive'"
|
|
>
|
|
<template #actions>
|
|
<Tooltip
|
|
:text="
|
|
!permissions.changePlan
|
|
? `You don't have enough permissions to perform this action`
|
|
: 'Change Plan'
|
|
"
|
|
>
|
|
<Button
|
|
:disabled="!permissions.changePlan"
|
|
v-if="['Active', 'Suspended'].includes(site.status) && canChangePlan"
|
|
@click="
|
|
() => {
|
|
showChangePlanDialog = true;
|
|
!plans.length && $resources.plans.fetch();
|
|
}
|
|
"
|
|
>
|
|
{{ site.status == 'Suspended' ? 'Set Plan' : 'Change Plan' }}
|
|
</Button>
|
|
</Tooltip>
|
|
</template>
|
|
|
|
<div v-if="!plan" class="flex items-center justify-center py-20">
|
|
<Button :loading="true" loading-text="Loading" />
|
|
</div>
|
|
<div v-else>
|
|
<div
|
|
v-if="plan.current_plan"
|
|
class="flex items-center rounded-lg bg-gray-50 p-5"
|
|
>
|
|
<PlanIcon />
|
|
<div class="ml-4">
|
|
<h4 class="text-4xl font-semibold text-gray-900">
|
|
{{ $planTitle(plan.current_plan) }}
|
|
<span v-if="plan.current_plan.price_usd > 0" class="text-lg">
|
|
/mo
|
|
</span>
|
|
</h4>
|
|
<p
|
|
class="text-base text-gray-700"
|
|
v-if="plan.current_plan.dedicated_server_plan"
|
|
>
|
|
{{ plan.current_plan.cpu_time_per_day }}
|
|
{{ $plural(plan.current_plan.cpu_time_per_day, 'hour', 'hours') }}
|
|
of CPU / day
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div v-else class="flex rounded-lg bg-gray-50 p-5">
|
|
<div>
|
|
<h4 class="font-semibold text-gray-600">No Plan Set</h4>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="plan.current_plan" class="mt-4 grid grid-cols-3 gap-12">
|
|
<div v-for="d in usage" :key="d.label">
|
|
<ProgressArc
|
|
:percentage="
|
|
plan.current_plan.dedicated_server_plan ? 33 : d.percentage
|
|
"
|
|
/>
|
|
<div class="mt-2 text-base font-medium text-gray-900">
|
|
{{ d.label }}
|
|
{{
|
|
isNaN(d.percentage) || plan.current_plan.dedicated_server_plan
|
|
? ''
|
|
: `(${Number(d.percentage).toFixed(1)}%)`
|
|
}}
|
|
</div>
|
|
<div class="mt-1 text-xs text-gray-600">{{ d.value }}</div>
|
|
</div>
|
|
</div>
|
|
<div v-else class="ml-2 mt-4 grid grid-cols-3 gap-12">
|
|
<div v-for="d in usage" :key="d.label">
|
|
<div class="text-base font-medium text-gray-900">
|
|
{{ d.label }}
|
|
</div>
|
|
<div class="mt-1 text-xs text-gray-600">{{ d.value }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<SitePlansDialog
|
|
:site="site"
|
|
:plan="plan"
|
|
v-model="showChangePlanDialog"
|
|
@plan-change="() => $emit('plan-change')"
|
|
/>
|
|
</div>
|
|
</Card>
|
|
</template>
|
|
<script>
|
|
import { defineAsyncComponent } from 'vue';
|
|
import SitePlansTable from '@/components/SitePlansTable.vue';
|
|
import ProgressArc from '@/components/ProgressArc.vue';
|
|
import PlanIcon from '@/components/PlanIcon.vue';
|
|
|
|
export default {
|
|
name: 'SiteOverviewPlan',
|
|
props: ['site', 'plan'],
|
|
components: {
|
|
SitePlansTable,
|
|
ProgressArc,
|
|
SitePlansDialog: defineAsyncComponent(() =>
|
|
import('./SitePlansDialog.vue')
|
|
),
|
|
PlanIcon
|
|
},
|
|
data() {
|
|
return {
|
|
showChangePlanDialog: false,
|
|
selectedPlan: null,
|
|
validationMessage: null
|
|
};
|
|
},
|
|
watch: {
|
|
async selectedPlan(value) {
|
|
if (!value) return;
|
|
|
|
try {
|
|
// custom plan validation for jingrow support
|
|
let result = await this.$call('validate_plan_change', {
|
|
current_plan: this.plan.current_plan,
|
|
new_plan: value,
|
|
currency: this.$account.team.currency
|
|
});
|
|
this.validationMessage = result;
|
|
} catch (e) {
|
|
this.validationMessage = null;
|
|
}
|
|
}
|
|
},
|
|
resources: {
|
|
plans() {
|
|
return {
|
|
url: 'jcloud.api.site.get_plans',
|
|
params: {
|
|
name: this.site?.name
|
|
},
|
|
initialData: []
|
|
};
|
|
}
|
|
},
|
|
methods: {
|
|
plan_title(plan) {
|
|
let china = this.$account.team.country == 'china';
|
|
let currency = china ? '¥' : '$';
|
|
let price_field = china ? 'price_cny' : 'price_usd';
|
|
let price = plan.current_plan[price_field];
|
|
return price > 0 ? `${currency}${price}` : plan.current_plan.plan_title;
|
|
},
|
|
|
|
belowCurrentUsage(plan) {
|
|
return (
|
|
this.plan.total_storage_usage > plan.max_storage_usage ||
|
|
this.plan.total_database_usage > plan.max_database_usage
|
|
);
|
|
},
|
|
|
|
getCurrentFormattedUsage() {
|
|
let f = value => {
|
|
return this.formatBytes(value, 0, 2);
|
|
};
|
|
|
|
return [
|
|
{
|
|
label: 'CPU',
|
|
value: `${this.plan.total_cpu_usage_hours} hours`
|
|
},
|
|
{
|
|
label: 'Database',
|
|
value: f(this.plan.total_database_usage)
|
|
},
|
|
{
|
|
label: 'Storage',
|
|
value: f(this.plan.total_storage_usage)
|
|
}
|
|
];
|
|
}
|
|
},
|
|
computed: {
|
|
permissions() {
|
|
return {
|
|
changePlan: this.$account.hasPermission(
|
|
this.site.name,
|
|
'jcloud.api.site.change_plan'
|
|
)
|
|
};
|
|
},
|
|
canChangePlan() {
|
|
return this.site.can_change_plan;
|
|
},
|
|
plans() {
|
|
let processedPlans = this.$resources.plans.data.map(plan => {
|
|
if (this.belowCurrentUsage(plan)) {
|
|
plan.disabled = true;
|
|
}
|
|
|
|
if (this.site.status === 'Suspended') {
|
|
return plan;
|
|
}
|
|
|
|
// If this `plan` is currently in use
|
|
if (this.plan.current_plan.name === plan.name) {
|
|
plan.disabled = true;
|
|
}
|
|
|
|
return plan;
|
|
});
|
|
|
|
if (this.site.status === 'Suspended') {
|
|
processedPlans = processedPlans.filter(p => !p.disabled);
|
|
}
|
|
|
|
return processedPlans;
|
|
},
|
|
usage() {
|
|
let f = value => {
|
|
return this.formatBytes(value, 2, 2);
|
|
};
|
|
|
|
if (!this.plan.current_plan || this.site.status === 'Suspended') {
|
|
return this.getCurrentFormattedUsage();
|
|
}
|
|
return [
|
|
{
|
|
label: 'CPU',
|
|
value: this.plan.current_plan.dedicated_server_plan
|
|
? `${this.plan.total_cpu_usage_hours} ${this.$plural(
|
|
this.plan.current_plan.cpu_time_per_day,
|
|
'hour',
|
|
'hours'
|
|
)}`
|
|
: `${this.plan.total_cpu_usage_hours} / ${
|
|
this.plan.current_plan.cpu_time_per_day
|
|
} ${this.$plural(
|
|
this.plan.current_plan.cpu_time_per_day,
|
|
'hour',
|
|
'hours'
|
|
)}`,
|
|
percentage:
|
|
(this.plan.total_cpu_usage_hours /
|
|
this.plan.current_plan.cpu_time_per_day) *
|
|
100
|
|
},
|
|
{
|
|
label: 'Database',
|
|
value: this.plan.current_plan.dedicated_server_plan
|
|
? f(this.plan.total_database_usage)
|
|
: `${f(this.plan.total_database_usage)} / ${f(
|
|
this.plan.current_plan.max_database_usage
|
|
)}`,
|
|
percentage:
|
|
(this.plan.total_database_usage /
|
|
this.plan.current_plan.max_database_usage) *
|
|
100
|
|
},
|
|
{
|
|
label: 'Storage',
|
|
value: this.plan.current_plan.dedicated_server_plan
|
|
? f(this.plan.total_storage_usage)
|
|
: `${f(this.plan.total_storage_usage)} / ${f(
|
|
this.plan.current_plan.max_storage_usage
|
|
)}`,
|
|
percentage:
|
|
(this.plan.total_storage_usage /
|
|
this.plan.current_plan.max_storage_usage) *
|
|
100
|
|
}
|
|
];
|
|
}
|
|
}
|
|
};
|
|
</script>
|