587 lines
24 KiB
Vue
587 lines
24 KiB
Vue
<script>
|
|
/**
|
|
* 云实例自选资源升降级:父级给出当前规格、商品和实例,前端加载可选资源后分别询价/下单。
|
|
* 成功仅发 pay 事件交给父级支付;本面板不直接修改实例资源,也不自行推算升级费用。
|
|
*/
|
|
import "~/assets/styles/ConfigBandwidth.CWSH1WJZ.css";
|
|
import "~/assets/styles/MfCloudResourceUpgrade.bSwLWjPg.css";
|
|
import { toDisplayString } from "vue";
|
|
import { renderList } from "vue";
|
|
import { onMounted } from "vue";
|
|
import { useId } 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 { reactive } 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 inputnumber from "primevue/inputnumber";
|
|
import OperationNotice from "~/components/OperationNotice.vue";
|
|
import skeleton from "primevue/skeleton";
|
|
import ConfigBandwidth from "~/components/config/ConfigBandwidth.vue";
|
|
var ne = {
|
|
key: 0,
|
|
class: `resource-upgrade`,
|
|
},
|
|
re = {
|
|
class: `config-field`,
|
|
},
|
|
ie = {
|
|
class: `choices`,
|
|
},
|
|
ae = [`aria-pressed`, `disabled`, `onClick`],
|
|
oe = {
|
|
class: `config-field`,
|
|
},
|
|
se = [`for`],
|
|
ce = {
|
|
key: 1,
|
|
class: `choices`,
|
|
},
|
|
le = [`aria-pressed`, `disabled`, `onClick`],
|
|
ue = {
|
|
key: 0,
|
|
class: `config-field`,
|
|
},
|
|
de = {
|
|
class: `choices`,
|
|
},
|
|
fe = [`aria-pressed`, `disabled`, `onClick`],
|
|
D = {
|
|
class: `upgrade-total`,
|
|
},
|
|
O = {
|
|
key: 2,
|
|
class: `muted`,
|
|
},
|
|
k = Object.assign(
|
|
_plugin_vue_export_helper_t(
|
|
defineComponent({
|
|
__name: `MfCloudResourceUpgrade`,
|
|
props: {
|
|
hostId: {},
|
|
productId: {},
|
|
current: {},
|
|
upgradeAllowed: {
|
|
type: Boolean,
|
|
default: !0,
|
|
},
|
|
module: {
|
|
default: `mf_cloud`,
|
|
},
|
|
},
|
|
emits: [`pay`],
|
|
setup(_, { emit: S }) {
|
|
let k = _,
|
|
A = computed(() => k.module || `mf_cloud`),
|
|
pe = S,
|
|
j = useApi(),
|
|
M = ref(``),
|
|
N = useId(),
|
|
P = ref(null),
|
|
F = ref(null),
|
|
I = ref(!1),
|
|
L = ref(!1),
|
|
R = ref(!1),
|
|
z = ref(``),
|
|
// 表单初始化为实例当前值;K 比较是否真的发生变更,未变更时不创建订单。
|
|
B = reactive({
|
|
cpu: Number(k.current.cpu || 0),
|
|
memory: Number(k.current.memory || 0),
|
|
bw: Number(k.current.bw || 0),
|
|
flow: Number(k.current.flow || 0),
|
|
peak_defence: Number(k.current.peak_defence || 0),
|
|
}),
|
|
V = ref(null),
|
|
H = 0,
|
|
U = 0,
|
|
W = ``,
|
|
G = () => JSON.stringify([k.hostId, A.value, B]),
|
|
K = computed(() =>
|
|
Object.entries(B).some(
|
|
([e, t]) => t !== Number(k.current[e] || 0),
|
|
),
|
|
);
|
|
/** CPU/离散内存候选展开并去重;步进候选最多收集 1000 项,避免巨大范围阻塞页面。 */
|
|
function q(e) {
|
|
let t = [];
|
|
for (let n of e || [])
|
|
if (
|
|
n.type === `step` ||
|
|
(n.min_value != null &&
|
|
n.max_value != null &&
|
|
n.type !== `radio`)
|
|
) {
|
|
let e = Math.max(1, Number(n.step || 1));
|
|
for (
|
|
let r = Number(n.min_value);
|
|
r <= Number(n.max_value) && t.length < 1e3;
|
|
r += e
|
|
)
|
|
t.push(r);
|
|
} else
|
|
Number.isFinite(Number(n.value)) && t.push(Number(n.value));
|
|
return [...new Set(t)];
|
|
}
|
|
let me = computed(() => q(P.value?.cpu)),
|
|
he = computed(() => q(P.value?.memory));
|
|
// 连续内存使用数值控件;全为单选档位时返回 null,改用下方离散按钮。
|
|
function ge(e) {
|
|
return !e?.length ||
|
|
e.every((e) => e.type === `radio` || e.min_value == null)
|
|
? null
|
|
: {
|
|
min: Math.min(
|
|
...e.map((e) => Number(e.min_value ?? e.value)),
|
|
),
|
|
max: Math.max(
|
|
...e.map((e) => Number(e.max_value ?? e.value)),
|
|
),
|
|
step: Math.max(
|
|
1,
|
|
Math.min(...e.map((e) => Number(e.step || 1))),
|
|
),
|
|
};
|
|
}
|
|
let J = computed(() => ge(P.value?.memory)),
|
|
Y = computed(() =>
|
|
(F.value?.bw || []).map((e) => ({
|
|
...e,
|
|
type:
|
|
e.type !== `radio` &&
|
|
e.min_value != null &&
|
|
e.max_value != null
|
|
? `step`
|
|
: e.type,
|
|
})),
|
|
),
|
|
X = computed(() =>
|
|
(F.value?.flow || []).map((e) => Number(e.value)),
|
|
);
|
|
/** 商品订购配置与当前线路并行加载,H 隔离实例/商品切换后的旧配置响应。 */
|
|
async function Z() {
|
|
if (k.upgradeAllowed === !1) return;
|
|
let e = ++H;
|
|
((I.value = !0), (z.value = ``), (V.value = null));
|
|
try {
|
|
let t = Number(k.current.line?.id || k.current.line_id),
|
|
[n, r] = await Promise.all([
|
|
j.get(`/product/${k.productId}/${A.value}/order_page`),
|
|
t
|
|
? j.get(`/product/${k.productId}/${A.value}/line/${t}`)
|
|
: Promise.resolve(null),
|
|
]);
|
|
if (e !== H) return;
|
|
((P.value = n), (F.value = r));
|
|
} catch (t) {
|
|
e === H &&
|
|
(z.value = t instanceof Error ? t.message : `升级配置加载失败`);
|
|
} finally {
|
|
e === H && (I.value = !1);
|
|
}
|
|
}
|
|
/** 每次询价先清旧价格,保存 host/module/表单快照;不接受无数值报价或过期响应。 */
|
|
async function Q() {
|
|
if (k.upgradeAllowed === !1) return;
|
|
let e = ++U,
|
|
t = G();
|
|
if (((V.value = null), (W = ``), (z.value = ``), !K.value)) {
|
|
L.value = !1;
|
|
return;
|
|
}
|
|
L.value = !0;
|
|
try {
|
|
let n = await j.get(`/${A.value}/${k.hostId}/common_config`, {
|
|
...B,
|
|
});
|
|
if (e !== U || G() !== t) return;
|
|
if (
|
|
n.price == null ||
|
|
n.price === `` ||
|
|
!Number.isFinite(Number(n.price))
|
|
)
|
|
throw Error(`报价无效,请重试`);
|
|
((V.value = n), (W = t));
|
|
} catch (t) {
|
|
e === U &&
|
|
(z.value = t instanceof Error ? t.message : `询价失败`);
|
|
} finally {
|
|
e === U && (L.value = !1);
|
|
}
|
|
}
|
|
// 普通档位选择后直接询价,下单期间不允许修改表单。
|
|
function $(e, t) {
|
|
k.upgradeAllowed === !1 || R.value || ((B[e] = t), Q());
|
|
}
|
|
// 带宽控件输入中先作废旧报价,等 change 确认后才询价,避免拖动每一步都发请求。
|
|
function _e(e) {
|
|
k.upgradeAllowed === !1 ||
|
|
R.value ||
|
|
((B.bw = e), U++, (V.value = null), (W = ``), (L.value = !1));
|
|
}
|
|
/** 下单要求实际变更且报价属于当前快照;后端返回合法订单号后交给父级。 */
|
|
async function ve() {
|
|
if (
|
|
k.upgradeAllowed === !1 ||
|
|
R.value ||
|
|
L.value ||
|
|
!V.value ||
|
|
W !== G() ||
|
|
!K.value
|
|
)
|
|
return;
|
|
((R.value = !0), (z.value = ``), (M.value = ``));
|
|
let e = H,
|
|
t = G(),
|
|
n = V.value.price;
|
|
try {
|
|
let r = await j.post(
|
|
`/${A.value}/${k.hostId}/common_config/order`,
|
|
{
|
|
...B,
|
|
},
|
|
);
|
|
if (e !== H || t !== G()) return;
|
|
if (!Number.isSafeInteger(Number(r.id)) || Number(r.id) <= 0)
|
|
throw Error(`订单信息无效,请重试`);
|
|
((V.value = null),
|
|
(W = ``),
|
|
pe(`pay`, {
|
|
order_id: r.id,
|
|
amount: n,
|
|
}));
|
|
} catch (e) {
|
|
M.value = e instanceof Error ? e.message : `提交失败`;
|
|
} finally {
|
|
R.value = !1;
|
|
}
|
|
}
|
|
return (
|
|
onMounted(Z),
|
|
watch(() => [k.hostId, k.module, k.productId], Z),
|
|
// 使仍在加载的配置/报价结果失效,不将卸载前的结果应用到后续面板。
|
|
onBeforeUnmount(() => {
|
|
(H++, U++);
|
|
}),
|
|
// 渲染 CPU、内存及线路对应的带宽/流量配置,统一在末尾展示报价与下单入口。
|
|
(n, r) => {
|
|
let a = OperationNotice,
|
|
o = skeleton,
|
|
c = inputnumber,
|
|
u = ConfigBandwidth,
|
|
d = button,
|
|
b = message;
|
|
return _.upgradeAllowed === !1
|
|
? createCommentVNode(``, !0)
|
|
: (openBlock(),
|
|
createElementBlock(`div`, ne, [
|
|
createVNode(
|
|
a,
|
|
{
|
|
message: unref(M),
|
|
severity: `error`,
|
|
},
|
|
null,
|
|
8,
|
|
[`message`],
|
|
),
|
|
unref(I)
|
|
? (openBlock(),
|
|
createBlock(o, {
|
|
key: 0,
|
|
height: `240px`,
|
|
}))
|
|
: unref(P)
|
|
? (openBlock(),
|
|
createElementBlock(
|
|
Fragment,
|
|
{
|
|
key: 1,
|
|
},
|
|
[
|
|
createElementVNode(`div`, re, [
|
|
(r[2] ||= createElementVNode(
|
|
`span`,
|
|
null,
|
|
`CPU`,
|
|
-1,
|
|
)),
|
|
createElementVNode(`div`, ie, [
|
|
(openBlock(!0),
|
|
createElementBlock(
|
|
Fragment,
|
|
null,
|
|
renderList(
|
|
unref(me),
|
|
(t) => (
|
|
openBlock(),
|
|
createElementBlock(
|
|
`button`,
|
|
{
|
|
key: t,
|
|
type: `button`,
|
|
class: normalizeClass({
|
|
selected: unref(B).cpu === t,
|
|
}),
|
|
"aria-pressed": unref(B).cpu === t,
|
|
disabled: unref(R),
|
|
onClick: (e) => $(`cpu`, t),
|
|
},
|
|
toDisplayString(t) + ` 核`,
|
|
11,
|
|
ae,
|
|
)
|
|
),
|
|
),
|
|
128,
|
|
)),
|
|
]),
|
|
]),
|
|
createElementVNode(`div`, oe, [
|
|
createElementVNode(
|
|
`label`,
|
|
{
|
|
for: `${unref(N)}-memory`,
|
|
},
|
|
`内存`,
|
|
8,
|
|
se,
|
|
),
|
|
unref(J)
|
|
? (openBlock(),
|
|
createBlock(
|
|
c,
|
|
{
|
|
key: 0,
|
|
"input-id": `${unref(N)}-memory`,
|
|
"model-value": unref(B).memory,
|
|
min: unref(J).min,
|
|
max: unref(J).max,
|
|
step: unref(J).step,
|
|
suffix: ` ${unref(P).config?.memory_unit || `GB`}`,
|
|
disabled: unref(R),
|
|
"show-buttons": ``,
|
|
"onUpdate:modelValue": (r[0] ||= (
|
|
e,
|
|
) => {
|
|
e != null && $(`memory`, e);
|
|
}),
|
|
},
|
|
null,
|
|
8,
|
|
[
|
|
`input-id`,
|
|
`model-value`,
|
|
`min`,
|
|
`max`,
|
|
`step`,
|
|
`suffix`,
|
|
`disabled`,
|
|
],
|
|
))
|
|
: (openBlock(),
|
|
createElementBlock(`div`, ce, [
|
|
(openBlock(!0),
|
|
createElementBlock(
|
|
Fragment,
|
|
null,
|
|
renderList(
|
|
unref(he),
|
|
(t) => (
|
|
openBlock(),
|
|
createElementBlock(
|
|
`button`,
|
|
{
|
|
key: t,
|
|
type: `button`,
|
|
class: normalizeClass({
|
|
selected:
|
|
unref(B).memory === t,
|
|
}),
|
|
"aria-pressed":
|
|
unref(B).memory === t,
|
|
disabled: unref(R),
|
|
onClick: (e) => $(`memory`, t),
|
|
},
|
|
toDisplayString(t) +
|
|
` ` +
|
|
toDisplayString(
|
|
unref(P).config
|
|
?.memory_unit || `GB`,
|
|
),
|
|
11,
|
|
le,
|
|
)
|
|
),
|
|
),
|
|
128,
|
|
)),
|
|
])),
|
|
]),
|
|
unref(F)?.bill_type === `flow` && unref(X).length
|
|
? (openBlock(),
|
|
createElementBlock(`div`, ue, [
|
|
(r[3] ||= createElementVNode(
|
|
`span`,
|
|
null,
|
|
`流量配额`,
|
|
-1,
|
|
)),
|
|
createElementVNode(`div`, de, [
|
|
(openBlock(!0),
|
|
createElementBlock(
|
|
Fragment,
|
|
null,
|
|
renderList(
|
|
unref(X),
|
|
(t) => (
|
|
openBlock(),
|
|
createElementBlock(
|
|
`button`,
|
|
{
|
|
key: t,
|
|
type: `button`,
|
|
class: normalizeClass({
|
|
selected: unref(B).flow === t,
|
|
}),
|
|
"aria-pressed":
|
|
unref(B).flow === t,
|
|
disabled: unref(R),
|
|
onClick: (e) => $(`flow`, t),
|
|
},
|
|
toDisplayString(
|
|
t > 0 ? `${t} GB` : `不限量`,
|
|
),
|
|
11,
|
|
fe,
|
|
)
|
|
),
|
|
),
|
|
128,
|
|
)),
|
|
]),
|
|
]))
|
|
: createCommentVNode(``, !0),
|
|
unref(F)?.bill_type === `bw` && unref(Y).length
|
|
? (openBlock(),
|
|
createBlock(
|
|
u,
|
|
{
|
|
key: 1,
|
|
"model-value": unref(B).bw,
|
|
options: unref(Y),
|
|
disabled: unref(R),
|
|
"onUpdate:modelValue": _e,
|
|
onChange: Q,
|
|
},
|
|
null,
|
|
8,
|
|
[`model-value`, `options`, `disabled`],
|
|
))
|
|
: createCommentVNode(``, !0),
|
|
createElementVNode(`div`, D, [
|
|
createElementVNode(`span`, null, [
|
|
(r[4] ||= createTextVNode(`所需费用:`, -1)),
|
|
createElementVNode(
|
|
`b`,
|
|
null,
|
|
toDisplayString(
|
|
unref(L)
|
|
? `正在计算…`
|
|
: unref(V)
|
|
? `¥${unref(V).price}`
|
|
: unref(K)
|
|
? `等待有效报价`
|
|
: `未变更配置`,
|
|
),
|
|
1,
|
|
),
|
|
]),
|
|
createVNode(
|
|
d,
|
|
{
|
|
label: `确认升降级`,
|
|
icon: `pi pi-check`,
|
|
loading: unref(R),
|
|
disabled:
|
|
!unref(K) ||
|
|
!unref(V) ||
|
|
unref(L) ||
|
|
unref(R),
|
|
onClick: ve,
|
|
},
|
|
null,
|
|
8,
|
|
[`loading`, `disabled`],
|
|
),
|
|
]),
|
|
unref(V)?.renew_price_difference
|
|
? (openBlock(),
|
|
createElementBlock(
|
|
`p`,
|
|
O,
|
|
`续费差价:¥` +
|
|
toDisplayString(
|
|
unref(V).renew_price_difference,
|
|
),
|
|
1,
|
|
))
|
|
: createCommentVNode(``, !0),
|
|
],
|
|
64,
|
|
))
|
|
: createCommentVNode(``, !0),
|
|
unref(z)
|
|
? (openBlock(),
|
|
createBlock(
|
|
b,
|
|
{
|
|
key: 2,
|
|
severity: `error`,
|
|
closable: !1,
|
|
},
|
|
{
|
|
default: withCtx(() => [
|
|
createTextVNode(toDisplayString(unref(z)), 1),
|
|
createVNode(d, {
|
|
label: `重试`,
|
|
severity: `secondary`,
|
|
text: ``,
|
|
onClick: (r[1] ||= (e) =>
|
|
unref(P) ? Q() : Z()),
|
|
}),
|
|
]),
|
|
_: 1,
|
|
},
|
|
))
|
|
: createCommentVNode(``, !0),
|
|
]));
|
|
}
|
|
);
|
|
},
|
|
}),
|
|
[[`__scopeId`, `data-v-c9212028`]],
|
|
),
|
|
{
|
|
__name: `MfCloudResourceUpgrade`,
|
|
},
|
|
);
|
|
export {};
|
|
export default k;
|
|
</script>
|