Files
console-dev/app/components/mfcloud/MfCloudUpgrade.vue
T

505 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script>
/**
* 云实例推荐套餐升降级;与自选资源面板不同,这里提交 recommend_config_id。
* 父级控制 upgradeAllowed 并消费 pay 事件;费用和续费差价均来自后端报价,不本地估算。
*/
import "~/assets/styles/MfCloudUpgrade.N7TNG8F1.css";
import { toDisplayString } from "vue";
import { renderList } from "vue";
import { onMounted } from "vue";
import { normalizeClass } from "vue";
import { onBeforeUnmount } from "vue";
import { watch } from "vue";
import { createBlock } from "vue";
import { ref } from "vue";
import { withCtx } from "vue";
import { createCommentVNode } from "vue";
import { computed } from "vue";
import { createElementBlock } from "vue";
import { Fragment } from "vue";
import { createElementVNode } from "vue";
import { createTextVNode } from "vue";
import { unref } from "vue";
import { defineComponent } from "vue";
import { createVNode } from "vue";
import { openBlock } from "vue";
import { useApi } from "~/lib/auth.js";
import button from "primevue/button";
import { t as _plugin_vue_export_helper_t } from "~/lib/_plugin-vue_export-helper.js";
import message from "primevue/message";
import OperationNotice from "~/components/OperationNotice.vue";
import skeleton from "primevue/skeleton";
var w = {
key: 0,
class: `up`,
},
T = {
key: 0,
class: `current`,
},
te = {
class: `current-spec`,
},
ne = {
key: 2,
class: `grid`,
},
re = {
key: 3,
class: `grid`,
},
ie = [`disabled`, `aria-pressed`, `onClick`],
E = {
class: `plan-head`,
},
D = {
class: `plan-name`,
},
O = {
key: 0,
class: `pi pi-check-circle plan-check`,
},
k = {
key: 0,
class: `plan-desc`,
},
A = {
class: `plan-spec`,
},
j = {
key: 5,
class: `bar`,
},
M = {
class: `bar-price`,
},
N = {
class: `bar-value`,
},
P = {
key: 0,
class: `pi pi-spin pi-spinner`,
},
F = {
key: 0,
class: `bar-sub`,
},
I = {
key: 1,
class: `bar-sub`,
},
L = Object.assign(
_plugin_vue_export_helper_t(
defineComponent({
__name: `MfCloudUpgrade`,
props: {
hostId: {},
module: {
default: `mf_cloud`,
},
upgradeAllowed: {
type: Boolean,
default: !0,
},
current: {},
},
emits: [`pay`],
setup(g, { emit: b }) {
let L = g,
R = computed(() => L.module || `mf_cloud`),
z = b,
B = useApi(),
V = ref(``),
H = ref([]),
U = ref(!1),
W = ref(``),
G = ref(null),
K = ref(null),
q = ref(!1),
J = ref(!1),
Y = 0,
X = 0,
Z = null;
/** 刷新可升级套餐同时清空选择和报价,过滤隐藏项及明确禁止升级的套餐。 */
async function Q() {
if (L.upgradeAllowed === !1) return;
let e = ++X;
(++Y,
(G.value = null),
(K.value = null),
(Z = null),
(H.value = []),
(U.value = !0),
(W.value = ``));
try {
let t = await B.get(`/${R.value}/${L.hostId}/recommend_config`);
if (e !== X) return;
H.value = (t.list ?? []).filter(
(e) => Number(e.hidden) !== 1 && Number(e.upgrade_range) !== 0,
);
} catch (t) {
e === X &&
(W.value = t instanceof Error ? t.message : `加载失败`);
} finally {
e === X && (U.value = !1);
}
}
/** 选套餐后先清旧报价;请求序号 Y 与套餐 id 一起阻止较早的询价覆盖新选择。 */
async function ae(e) {
if (L.upgradeAllowed === !1 || J.value) return;
let t = ++Y;
((Z = null),
(G.value = e.id),
(K.value = null),
(q.value = !0),
(W.value = ``));
try {
let n = await B.get(
`/${R.value}/${L.hostId}/recommend_config/price`,
{
recommend_config_id: e.id,
},
);
if (t !== Y || G.value !== e.id) return;
if (
n.price == null ||
String(n.price).trim() === `` ||
!Number.isFinite(Number(n.price))
)
throw Error(`报价无效,请重试`);
((K.value = n), (Z = e.id));
} catch (e) {
t === Y &&
(W.value = e instanceof Error ? e.message : `询价失败`);
} finally {
t === Y && (q.value = !1);
}
}
/** 只有当前套餐已有对应有效报价才下单,提交锁阻止重复点击;返回订单后交接支付。 */
async function oe() {
if (
L.upgradeAllowed === !1 ||
J.value ||
q.value ||
!K.value ||
!G.value ||
Z !== G.value
)
return;
J.value = !0;
let e = X,
t = K.value.price;
((W.value = ``), (V.value = ``));
try {
let n = await B.post(
`/${R.value}/${L.hostId}/recommend_config/order`,
{
recommend_config_id: G.value,
},
);
if (e !== X) return;
if (!Number.isSafeInteger(Number(n?.id)) || Number(n.id) <= 0)
throw Error(`订单信息无效,请重试`);
((K.value = null),
(Z = null),
z(`pay`, {
order_id: n.id,
amount: t,
}));
} catch (e) {
V.value = e instanceof Error ? e.message : `下单失败`;
} finally {
J.value = !1;
}
}
// 将套餐已有规格组合为文本,缺失项不编造默认值;GPU 数量缺失按现有约定显示 1。
function se(e) {
return [
e.cpu ? `${e.cpu} 核` : ``,
e.memory ? `${e.memory} GB 内存` : ``,
e.system_disk_size ? `${e.system_disk_size} GB 系统盘` : ``,
e.data_disk_size ? `${e.data_disk_size} GB 数据盘` : ``,
e.bw ? `${e.bw} Mbps` : ``,
e.flow ? `${e.flow} GB 流量` : ``,
e.peak_defence ? `${e.peak_defence} G 防御` : ``,
e.gpu_name ? `${e.gpu_num ?? 1}× ${e.gpu_name}` : ``,
].filter(Boolean);
}
// 当前规格摘要来自父级实例信息,仅作对照,不作为目标套餐请求体。
let $ = computed(() =>
[
L.current.cpu ? `${L.current.cpu} 核` : ``,
L.current.memory ? `${L.current.memory} GB 内存` : ``,
L.current.system_disk?.size
? `${L.current.system_disk.size} GB 系统盘`
: ``,
L.current.bw ? `${L.current.bw} Mbps` : ``,
]
.filter(Boolean)
.join(` · `),
);
return (
onMounted(Q),
watch(() => [L.hostId, L.module], Q),
// 作废列表与报价在途序号,避免离开后仍接受这些异步结果。
onBeforeUnmount(() => {
(Y++, X++);
}),
// 套餐列表、无可升级提示和取价/下单栏分层展示;提交期间锁定套餐选择。
(n, i) => {
let a = OperationNotice,
s = message,
u = skeleton,
y = button;
return g.upgradeAllowed === !1
? createCommentVNode(``, !0)
: (openBlock(),
createElementBlock(`div`, w, [
createVNode(
a,
{
message: unref(V),
severity: `error`,
},
null,
8,
[`message`],
),
unref($)
? (openBlock(),
createElementBlock(`div`, T, [
(i[0] ||= createElementVNode(
`span`,
{
class: `current-label`,
},
`当前配置`,
-1,
)),
createElementVNode(
`span`,
te,
toDisplayString(unref($)),
1,
),
]))
: createCommentVNode(``, !0),
unref(W)
? (openBlock(),
createBlock(
s,
{
key: 1,
severity: `error`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(W)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
unref(U)
? (openBlock(),
createElementBlock(`div`, ne, [
(openBlock(),
createElementBlock(
Fragment,
null,
renderList(3, (e) =>
createElementVNode(
`div`,
{
key: e,
class: `plan`,
},
[
createVNode(u, {
height: `90px`,
}),
],
),
),
64,
)),
]))
: unref(H).length
? (openBlock(),
createElementBlock(`div`, re, [
(openBlock(!0),
createElementBlock(
Fragment,
null,
renderList(
unref(H),
(t) => (
openBlock(),
createElementBlock(
`button`,
{
key: t.id,
type: `button`,
class: normalizeClass([
`plan`,
{
active: unref(G) === t.id,
},
]),
disabled: unref(J),
"aria-pressed": unref(G) === t.id,
onClick: (e) => ae(t),
},
[
createElementVNode(`div`, E, [
createElementVNode(
`span`,
D,
toDisplayString(t.name),
1,
),
unref(G) === t.id
? (openBlock(),
createElementBlock(`i`, O))
: createCommentVNode(``, !0),
]),
t.description
? (openBlock(),
createElementBlock(
`div`,
k,
toDisplayString(t.description),
1,
))
: createCommentVNode(``, !0),
createElementVNode(
`div`,
A,
toDisplayString(se(t).join(` · `)),
1,
),
],
10,
ie,
)
),
),
128,
)),
]))
: unref(W)
? createCommentVNode(``, !0)
: (openBlock(),
createBlock(
s,
{
key: 4,
severity: `info`,
closable: !1,
},
{
default: withCtx(() => [
...(i[1] ||= [
createTextVNode(
`当前实例没有可升级的套餐。`,
-1,
),
]),
]),
_: 1,
},
)),
unref(G)
? (openBlock(),
createElementBlock(`div`, j, [
createElementVNode(`div`, M, [
(i[2] ||= createElementVNode(
`span`,
{
class: `bar-label`,
},
`升级费用`,
-1,
)),
createElementVNode(`span`, N, [
unref(q)
? (openBlock(), createElementBlock(`i`, P))
: (openBlock(),
createElementBlock(
Fragment,
{
key: 1,
},
[
createTextVNode(
toDisplayString(
unref(K) ? `¥${unref(K).price}` : `—`,
),
1,
),
],
64,
)),
]),
unref(K)?.price_difference
? (openBlock(),
createElementBlock(
`span`,
F,
`差价 ¥` +
toDisplayString(unref(K).price_difference),
1,
))
: createCommentVNode(``, !0),
unref(K)?.renew_price_difference
? (openBlock(),
createElementBlock(
`span`,
I,
`续费差价 ¥` +
toDisplayString(
unref(K).renew_price_difference,
),
1,
))
: createCommentVNode(``, !0),
]),
createVNode(
y,
{
label: `确认升降级`,
icon: `pi pi-arrow-up`,
loading: unref(J),
disabled: !unref(K) || unref(q) || unref(J),
onClick: oe,
},
null,
8,
[`loading`, `disabled`],
),
]))
: createCommentVNode(``, !0),
(i[3] ||= createElementVNode(
`p`,
{
class: `hint`,
},
`升级为变更配置,原配置将被替换;部分套餐可能要求实例处于运行中状态。`,
-1,
)),
]));
}
);
},
}),
[[`__scopeId`, `data-v-b98b2e63`]],
),
{
__name: `MfCloudUpgrade`,
},
);
export {};
export default L;
</script>