526 lines
18 KiB
Vue
526 lines
18 KiB
Vue
<script>
|
|
/**
|
|
* 每 IP 防御调整面板:父级提供实例、模块、IP 集合及操作权限,订单通过 pay 事件交回父级支付。
|
|
* 配置加载、取价、下单分别计数;IP/实例/目标档位变化时旧报价立即失效。
|
|
*/
|
|
import "~/assets/styles/MfCloudDefence.B2vl5Yip.css";
|
|
import { toDisplayString } from "vue";
|
|
import { onMounted } from "vue";
|
|
import { useId } 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 { isRef } from "vue";
|
|
import { createElementBlock } 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 dialog from "primevue/dialog";
|
|
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 select from "primevue/select";
|
|
import { n as cloud_instance_management_n } from "~/lib/cloud-instance-management.js";
|
|
import { s as cloud_instance_management_s } from "~/lib/cloud-instance-management.js";
|
|
import { t as cloud_instance_management_t } from "~/lib/cloud-instance-management.js";
|
|
// 恢复渲染函数的静态节点属性;保留 scopeId 和既有 class 与样式文件的对应关系。
|
|
var E = {
|
|
class: `defence network-section`,
|
|
},
|
|
D = {
|
|
class: `network-head`,
|
|
},
|
|
O = {
|
|
class: `network-actions`,
|
|
},
|
|
te = {
|
|
key: 0,
|
|
},
|
|
ne = {
|
|
key: 1,
|
|
class: `muted`,
|
|
},
|
|
re = {
|
|
key: 2,
|
|
class: `muted`,
|
|
},
|
|
ie = {
|
|
key: 3,
|
|
class: `muted`,
|
|
},
|
|
ae = {
|
|
key: 4,
|
|
class: `muted`,
|
|
},
|
|
oe = {
|
|
class: `form`,
|
|
},
|
|
se = {
|
|
key: 0,
|
|
},
|
|
k = Object.assign(
|
|
_plugin_vue_export_helper_t(
|
|
defineComponent({
|
|
__name: `MfCloudDefence`,
|
|
props: {
|
|
hostId: {},
|
|
module: {},
|
|
ips: {},
|
|
active: {
|
|
type: Boolean,
|
|
},
|
|
upgradeAllowed: {
|
|
type: Boolean,
|
|
},
|
|
},
|
|
emits: [`pay`],
|
|
setup(h, { emit: b }) {
|
|
let k = h,
|
|
ce = b,
|
|
A = useApi(),
|
|
le = useId(),
|
|
j = ref(k.ips[0] ?? ``),
|
|
M = ref(``),
|
|
N = ref(``),
|
|
P = ref([]),
|
|
F = ref(!1),
|
|
I = ref(!1),
|
|
L = ref(``),
|
|
R = ref(``),
|
|
z = ref(!1),
|
|
B = ref(!1),
|
|
V = ref(``),
|
|
H = ref(``),
|
|
// 报价快照同时包含权限和弹窗状态,不能把关闭前或另一实例的价格继续用于下单。
|
|
U = computed(() =>
|
|
JSON.stringify([
|
|
k.hostId,
|
|
k.module,
|
|
j.value,
|
|
M.value,
|
|
z.value,
|
|
k.upgradeAllowed,
|
|
]),
|
|
),
|
|
W = ref(``),
|
|
// 不把当前档位再次当作可购买目标;K 要求当前选择确实存在且报价快照一致。
|
|
G = computed(() =>
|
|
P.value.filter((e) => String(e.value) !== String(N.value)),
|
|
),
|
|
K = computed(
|
|
() =>
|
|
!!W.value &&
|
|
W.value === U.value &&
|
|
!B.value &&
|
|
!I.value &&
|
|
k.upgradeAllowed &&
|
|
k.active &&
|
|
G.value.some((e) => String(e.value) === String(M.value)),
|
|
),
|
|
q = 0,
|
|
J = 0,
|
|
Y = 0,
|
|
X = !1;
|
|
// 同步 watcher 调用此函数,使配置变化与按钮禁用发生在同一个更新周期。
|
|
function Z() {
|
|
(J++,
|
|
(W.value = ``),
|
|
(V.value = ``),
|
|
(H.value = ``),
|
|
(B.value = !1));
|
|
}
|
|
watch(U, Z, {
|
|
flush: `sync`,
|
|
});
|
|
/** 按选中 IP 取防御配置,通过统一适配器校验列表和当前值,空 IP 不发请求。 */
|
|
async function Q() {
|
|
let e = ++q,
|
|
t = j.value,
|
|
n = k.hostId,
|
|
r = k.module;
|
|
if (
|
|
((P.value = []),
|
|
(L.value = ``),
|
|
(F.value = !0),
|
|
(N.value = ``),
|
|
Z(),
|
|
!t)
|
|
) {
|
|
F.value = !1;
|
|
return;
|
|
}
|
|
try {
|
|
let i = await A.get(`/${r}/${n}/upgrade_defence_config`, {
|
|
ip: t,
|
|
});
|
|
if (X || e !== q) return;
|
|
let a = cloud_instance_management_n(i);
|
|
((P.value = a.options), (N.value = a.current));
|
|
} catch (t) {
|
|
!X &&
|
|
e === q &&
|
|
(L.value = t instanceof Error ? t.message : `加载防御配置失败`);
|
|
} finally {
|
|
!X && e === q && (F.value = !1);
|
|
}
|
|
}
|
|
// 只有实例活动、允许升级且存在其他档位时才打开空白调整表单。
|
|
function ue() {
|
|
k.upgradeAllowed &&
|
|
k.active &&
|
|
!I.value &&
|
|
!F.value &&
|
|
G.value.length &&
|
|
((M.value = ``), (R.value = ``), (z.value = !0));
|
|
}
|
|
/** 取得本次费用与续费差价;只接受序号和快照仍属于当前选择的结果。 */
|
|
async function $() {
|
|
if (
|
|
(Z(),
|
|
!z.value ||
|
|
!k.upgradeAllowed ||
|
|
!G.value.some((e) => String(e.value) === String(M.value)))
|
|
)
|
|
return;
|
|
let e = ++J,
|
|
t = U.value;
|
|
((B.value = !0), (R.value = ``));
|
|
try {
|
|
let n = await A.get(
|
|
`/${k.module}/${k.hostId}/upgrade_defence/price`,
|
|
{
|
|
ip: j.value,
|
|
peak_defence: M.value,
|
|
},
|
|
);
|
|
if (X || e !== J || t !== U.value) return;
|
|
((V.value = cloud_instance_management_t(n.price)),
|
|
(H.value = String(n.renew_price_difference ?? ``)),
|
|
(W.value = t));
|
|
} catch (t) {
|
|
!X &&
|
|
e === J &&
|
|
(R.value = t instanceof Error ? t.message : `报价失败`);
|
|
} finally {
|
|
!X && e === J && (B.value = !1);
|
|
}
|
|
}
|
|
/** 先核验有效报价再创建订单;只把合法订单号及金额发给父级,不在这里执行支付。 */
|
|
async function de() {
|
|
if (!K.value || X) return;
|
|
let e = U.value,
|
|
t = V.value,
|
|
n = ++Y;
|
|
((I.value = !0), (R.value = ``));
|
|
try {
|
|
let n = await A.post(
|
|
`/${k.module}/${k.hostId}/upgrade_defence/order`,
|
|
{
|
|
ip: j.value,
|
|
peak_defence: M.value,
|
|
},
|
|
);
|
|
if (X || e !== U.value) return;
|
|
let r = cloud_instance_management_s(n.id);
|
|
((z.value = !1),
|
|
ce(`pay`, {
|
|
order_id: r,
|
|
amount:
|
|
n.amount == null
|
|
? t
|
|
: cloud_instance_management_t(n.amount),
|
|
}));
|
|
} catch (t) {
|
|
!X &&
|
|
e === U.value &&
|
|
(R.value = t instanceof Error ? t.message : `创建订单失败`);
|
|
} finally {
|
|
!X && n === Y && (I.value = !1);
|
|
}
|
|
}
|
|
return (
|
|
watch(j, () => {
|
|
((z.value = !1), Q());
|
|
}),
|
|
watch(
|
|
() => [k.hostId, k.module, k.ips.join(`,`)],
|
|
() => {
|
|
(Y++,
|
|
(z.value = !1),
|
|
(I.value = !1),
|
|
(j.value = k.ips.includes(j.value)
|
|
? j.value
|
|
: (k.ips[0] ?? ``)),
|
|
Q());
|
|
},
|
|
),
|
|
onMounted(Q),
|
|
// HTTP 请求未必即时取消,因此卸载标记和递增序号共同阻止迟到响应回填。
|
|
onBeforeUnmount(() => {
|
|
((X = !0), q++, Z());
|
|
}),
|
|
// UI 分为 IP/档位状态、加载错误与调整弹窗;提交期间禁用选择和关闭操作。
|
|
(t, n) => {
|
|
let r = select,
|
|
i = button,
|
|
o = message,
|
|
l = dialog;
|
|
return (
|
|
openBlock(),
|
|
createElementBlock(`section`, E, [
|
|
createElementVNode(`div`, D, [
|
|
(n[4] ||= createElementVNode(`h4`, null, `每 IP 防御`, -1)),
|
|
createElementVNode(`div`, O, [
|
|
createVNode(
|
|
r,
|
|
{
|
|
class: `defence-ip`,
|
|
modelValue: unref(j),
|
|
"onUpdate:modelValue": (n[0] ||= (e) =>
|
|
isRef(j) ? (j.value = e) : null),
|
|
options: h.ips,
|
|
"input-id": `${unref(le)}-ip`,
|
|
"aria-label": `防御 IP`,
|
|
disabled: unref(I) || !h.ips.length,
|
|
},
|
|
null,
|
|
8,
|
|
[`modelValue`, `options`, `input-id`, `disabled`],
|
|
),
|
|
createVNode(
|
|
i,
|
|
{
|
|
label: `刷新`,
|
|
text: ``,
|
|
size: `small`,
|
|
loading: unref(F),
|
|
disabled: unref(I),
|
|
onClick: Q,
|
|
},
|
|
null,
|
|
8,
|
|
[`loading`, `disabled`],
|
|
),
|
|
createVNode(
|
|
i,
|
|
{
|
|
label: `调整防御`,
|
|
size: `small`,
|
|
disabled:
|
|
!h.upgradeAllowed ||
|
|
!h.active ||
|
|
unref(I) ||
|
|
unref(F) ||
|
|
!unref(G).length,
|
|
onClick: ue,
|
|
},
|
|
null,
|
|
8,
|
|
[`disabled`],
|
|
),
|
|
]),
|
|
]),
|
|
unref(N) === ``
|
|
? createCommentVNode(``, !0)
|
|
: (openBlock(),
|
|
createElementBlock(
|
|
`p`,
|
|
te,
|
|
`当前防御:` + toDisplayString(unref(N)) + ` Gbps`,
|
|
1,
|
|
)),
|
|
h.ips.length
|
|
? !unref(F) && !unref(L) && !unref(P).length
|
|
? (openBlock(),
|
|
createElementBlock(`p`, re, `当前 IP 未开放防御调整。`))
|
|
: !unref(F) && !unref(L) && !unref(G).length
|
|
? (openBlock(),
|
|
createElementBlock(
|
|
`p`,
|
|
ie,
|
|
`当前 IP 没有其他可选防御档位。`,
|
|
))
|
|
: createCommentVNode(``, !0)
|
|
: (openBlock(),
|
|
createElementBlock(
|
|
`p`,
|
|
ne,
|
|
`暂无可调整防御的 IP 地址。`,
|
|
)),
|
|
h.upgradeAllowed
|
|
? createCommentVNode(``, !0)
|
|
: (openBlock(),
|
|
createElementBlock(`p`, ae, `当前实例不允许升降级。`)),
|
|
unref(L)
|
|
? (openBlock(),
|
|
createBlock(
|
|
o,
|
|
{
|
|
key: 5,
|
|
severity: `error`,
|
|
closable: !1,
|
|
},
|
|
{
|
|
default: withCtx(() => [
|
|
createTextVNode(toDisplayString(unref(L)), 1),
|
|
createVNode(i, {
|
|
label: `重试`,
|
|
text: ``,
|
|
size: `small`,
|
|
onClick: Q,
|
|
}),
|
|
]),
|
|
_: 1,
|
|
},
|
|
))
|
|
: createCommentVNode(``, !0),
|
|
createVNode(
|
|
l,
|
|
{
|
|
visible: unref(z),
|
|
"onUpdate:visible": (n[3] ||= (e) =>
|
|
isRef(z) ? (z.value = e) : null),
|
|
header: `调整 IP 防御`,
|
|
modal: ``,
|
|
closable: !unref(I),
|
|
"close-on-escape": !unref(I),
|
|
},
|
|
{
|
|
footer: withCtx(() => [
|
|
createVNode(
|
|
i,
|
|
{
|
|
label: `取消`,
|
|
text: ``,
|
|
severity: `secondary`,
|
|
disabled: unref(I),
|
|
onClick: (n[2] ||= (e) => (z.value = !1)),
|
|
},
|
|
null,
|
|
8,
|
|
[`disabled`],
|
|
),
|
|
createVNode(
|
|
i,
|
|
{
|
|
label: `创建订单`,
|
|
loading: unref(I),
|
|
disabled: !unref(K),
|
|
onClick: de,
|
|
},
|
|
null,
|
|
8,
|
|
[`loading`, `disabled`],
|
|
),
|
|
]),
|
|
default: withCtx(() => [
|
|
createElementVNode(`div`, oe, [
|
|
createElementVNode(
|
|
`p`,
|
|
null,
|
|
toDisplayString(unref(j)),
|
|
1,
|
|
),
|
|
createVNode(
|
|
r,
|
|
{
|
|
modelValue: unref(M),
|
|
"onUpdate:modelValue": (n[1] ||= (e) =>
|
|
isRef(M) ? (M.value = e) : null),
|
|
options: unref(G),
|
|
"option-label": `desc`,
|
|
"option-value": `value`,
|
|
"aria-label": `目标防御峰值`,
|
|
disabled: unref(I),
|
|
onChange: $,
|
|
},
|
|
null,
|
|
8,
|
|
[`modelValue`, `options`, `disabled`],
|
|
),
|
|
createElementVNode(
|
|
`p`,
|
|
null,
|
|
`本次费用:` +
|
|
toDisplayString(
|
|
unref(B)
|
|
? `正在计算…`
|
|
: unref(V) === ``
|
|
? `待确认`
|
|
: `¥${unref(V)}`,
|
|
),
|
|
1,
|
|
),
|
|
unref(H) === ``
|
|
? createCommentVNode(``, !0)
|
|
: (openBlock(),
|
|
createElementBlock(
|
|
`p`,
|
|
se,
|
|
`续费差价:¥` + toDisplayString(unref(H)),
|
|
1,
|
|
)),
|
|
unref(R)
|
|
? (openBlock(),
|
|
createBlock(
|
|
o,
|
|
{
|
|
key: 1,
|
|
severity: `error`,
|
|
closable: !1,
|
|
},
|
|
{
|
|
default: withCtx(() => [
|
|
createTextVNode(
|
|
toDisplayString(unref(R)),
|
|
1,
|
|
),
|
|
createVNode(
|
|
i,
|
|
{
|
|
label: `重新报价`,
|
|
text: ``,
|
|
size: `small`,
|
|
disabled: unref(I),
|
|
onClick: $,
|
|
},
|
|
null,
|
|
8,
|
|
[`disabled`],
|
|
),
|
|
]),
|
|
_: 1,
|
|
},
|
|
))
|
|
: createCommentVNode(``, !0),
|
|
]),
|
|
]),
|
|
_: 1,
|
|
},
|
|
8,
|
|
[`visible`, `closable`, `close-on-escape`],
|
|
),
|
|
])
|
|
);
|
|
}
|
|
);
|
|
},
|
|
}),
|
|
[[`__scopeId`, `data-v-b0c2bd86`]],
|
|
),
|
|
{
|
|
__name: `MfCloudDefence`,
|
|
},
|
|
);
|
|
export {};
|
|
export default k;
|
|
</script>
|