171 lines
5.1 KiB
JavaScript
171 lines
5.1 KiB
JavaScript
/** 云实例管理表单的协议校验:防御报价、订单、NAT、VPC 和磁盘规格。 */
|
||
var e = (e) => e === `mf_cloud` || e === `remf_cloud`;
|
||
// 空对象表示没有防御选项;非空配置须有合法 defence 列表,当前防御值可缺省,非空时须合法。
|
||
function t(e) {
|
||
let t = () => {
|
||
throw Error(`防御配置无效,请重试`);
|
||
};
|
||
if (!e || typeof e != `object` || Array.isArray(e)) return t();
|
||
let n = e;
|
||
if (!Object.keys(n).length)
|
||
return {
|
||
options: [],
|
||
current: ``,
|
||
};
|
||
let r = n.defence;
|
||
if (
|
||
!r ||
|
||
typeof r != `object` ||
|
||
(!Array.isArray(r) && Object.keys(r).some((e) => !/^(0|[1-9]\d*)$/.test(e)))
|
||
)
|
||
return t();
|
||
let i = Object.values(r).map((e) => {
|
||
if (!e || typeof e != `object`) return t();
|
||
let { value: n, desc: r } = e;
|
||
return ![`string`, `number`].includes(typeof n) ||
|
||
String(n).trim() === `` ||
|
||
!Number.isFinite(Number(n)) ||
|
||
Number(n) < 0 ||
|
||
![`string`, `number`].includes(typeof r) ||
|
||
String(r).trim() === ``
|
||
? t()
|
||
: {
|
||
value: String(n),
|
||
desc: String(r),
|
||
};
|
||
}),
|
||
a = n.current_defence == null ? `` : String(n.current_defence);
|
||
return a !== `` && (!Number.isFinite(Number(a)) || Number(a) < 0 || !a.trim())
|
||
? t()
|
||
: {
|
||
options: i,
|
||
current: a,
|
||
};
|
||
}
|
||
// 允许价格为 0,但不能把缺失值或空串转换成免费报价。
|
||
function n(e) {
|
||
if (
|
||
e == null ||
|
||
String(e).trim() === `` ||
|
||
!Number.isFinite(Number(e)) ||
|
||
Number(e) < 0
|
||
)
|
||
throw Error(`未获得有效报价,请重试`);
|
||
return String(e);
|
||
}
|
||
// 未取得明确订单号时阻止进入支付;提示先核对订单,避免用户重复下单。
|
||
function r(e) {
|
||
if (
|
||
(typeof e != `string` && typeof e != `number`) ||
|
||
!/^[1-9]\d*$/.test(String(e))
|
||
)
|
||
throw Error(`订单编号未返回,请先在订单管理中检查,避免重复下单`);
|
||
return e;
|
||
}
|
||
/** web 转发只提交域名/内部端口;其他转发使用协议码,null 外部端口表示由后端分配。 */
|
||
function i(e, t) {
|
||
if (!Number.isInteger(t.int_port) || t.int_port < 1 || t.int_port > 65535)
|
||
throw Error(`内部端口应为 1–65535 的整数`);
|
||
if (e === `web`) {
|
||
let e = t.domain.trim().toLowerCase();
|
||
if (
|
||
!/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(
|
||
e,
|
||
)
|
||
)
|
||
throw Error(`请输入有效域名,不含协议和路径`);
|
||
return {
|
||
domain: e,
|
||
int_port: t.int_port,
|
||
};
|
||
}
|
||
if (!t.name.trim()) throw Error(`请输入转发名称`);
|
||
if (![1, 2, 3].includes(t.protocol)) throw Error(`请选择有效协议`);
|
||
if (
|
||
t.ext_port !== null &&
|
||
(!Number.isInteger(t.ext_port) ||
|
||
t.ext_port < 0 ||
|
||
t.ext_port > 65535 ||
|
||
[22, 80, 443].includes(t.ext_port))
|
||
)
|
||
throw Error(`外部端口应为 0–65535,且不能使用 22、80、443`);
|
||
return {
|
||
name: t.name.trim(),
|
||
int_port: t.int_port,
|
||
protocol: t.protocol,
|
||
...(t.ext_port === null
|
||
? {}
|
||
: {
|
||
ext_port: t.ext_port,
|
||
}),
|
||
};
|
||
}
|
||
/** VPC 名称必填;网段可留空由后端处理,填写时须满足 IPv4 CIDR 及允许掩码。 */
|
||
function a(e, t, n = []) {
|
||
if (!e.trim()) throw Error(`请输入 VPC 名称`);
|
||
if (!t.trim())
|
||
return {
|
||
name: e.trim(),
|
||
};
|
||
let r = t.trim().match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)$/);
|
||
if (!r) throw Error(`请输入有效 IPv4 CIDR 网段`);
|
||
let i = r.slice(1, 5).map(Number),
|
||
a = Number(r[5]);
|
||
if (
|
||
i.some((e) => e < 0 || e > 255) ||
|
||
a < 1 ||
|
||
a > 32 ||
|
||
(n.length && !n.includes(a))
|
||
)
|
||
throw Error(`网段地址或掩码不在允许范围内`);
|
||
return {
|
||
name: e.trim(),
|
||
ips: t.trim(),
|
||
};
|
||
}
|
||
// 将磁盘档位转换为可选范围,并向内对齐步长;无合法容量区间的档位不展示。
|
||
function o(e, t = {}) {
|
||
return e.flatMap((e, n) => {
|
||
let r = e.type === `step` || e.type === `total`,
|
||
i =
|
||
Number(t.disk_range_limit_switch) === 1 &&
|
||
Number(t.disk_range_limit) > 0
|
||
? Number(t.disk_range_limit)
|
||
: 1,
|
||
a = r
|
||
? Math.ceil(Number(e.min_value ?? e.value) / i) * i
|
||
: Number(e.value),
|
||
o = r
|
||
? Math.floor(Number(e.max_value ?? e.value) / i) * i
|
||
: Number(e.value),
|
||
s = String(e.other_config?.disk_type ?? ``);
|
||
return !Number.isInteger(a) ||
|
||
!Number.isInteger(o) ||
|
||
a < 1 ||
|
||
o < a ||
|
||
!Number.isFinite(i) ||
|
||
i <= 0
|
||
? []
|
||
: [
|
||
{
|
||
id: n,
|
||
type: s,
|
||
min: a,
|
||
max: o,
|
||
step: i,
|
||
label: `${s || `默认类型`} · ${a === o ? a : `${a}–${o}`} GB`,
|
||
},
|
||
];
|
||
});
|
||
}
|
||
// 同时检查整数、上下界和步长;浮点容差仅用于除法误差,不放宽容量边界。
|
||
function s(e, t) {
|
||
return (
|
||
Number.isInteger(e) &&
|
||
e >= t.min &&
|
||
e <= t.max &&
|
||
Math.abs((e - t.min) / t.step - Math.round((e - t.min) / t.step)) < 1e-7
|
||
);
|
||
}
|
||
export { i as a, a as c, e as i, t as n, s as o, o as r, r as s, n as t };
|