505 lines
18 KiB
Vue
505 lines
18 KiB
Vue
<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>
|