Files
console-dev/app/components/config/ConfigBandwidth.vue
T

311 lines
10 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>
/** 带宽输入/滑块:按后端 options 的合法区间和步长吸附,单位为 Mbps,固定带宽不可调。 */
import "~/assets/styles/ConfigBandwidth.CWSH1WJZ.css";
import { nextTick } from "vue";
import { normalizeClass } from "vue";
import { computed } from "vue";
import { createElementBlock } from "vue";
import { withDirectives } from "vue";
import { createElementVNode } from "vue";
import { unref } from "vue";
import { defineComponent } from "vue";
import { createVNode } from "vue";
import { openBlock } from "vue";
import { t as _plugin_vue_export_helper_t } from "~/lib/_plugin-vue_export-helper.js";
import inputnumber from "primevue/inputnumber";
import tooltip from "primevue/tooltip";
var p = {
class: `bandwidth-field`,
},
m = {
class: `bandwidth-label`,
},
h = [`aria-label`],
g = [`aria-valuetext`, `disabled`, `value`, `min`, `max`],
_ = Object.assign(
_plugin_vue_export_helper_t(
defineComponent({
__name: `ConfigBandwidth`,
props: {
modelValue: {},
options: {},
disabled: {
type: Boolean,
},
},
emits: [`update:modelValue`, `change`],
setup(s, { emit: u }) {
let _ = s,
v = u,
y = computed(() =>
_.options
.map((e) => {
let t = e.type === `step` || e.type === `total`,
n = Number(t ? (e.min_value ?? e.value) : e.value),
r = Number(
t ? (e.max_value ?? e.min_value ?? e.value) : e.value,
),
i = Number(e.step),
a = Number.isFinite(i) && i > 0 ? i : 1;
return {
min: n,
max: Number(
(n + Math.floor((r - n) / a + 1e-7) * a).toFixed(8),
),
step: a,
};
})
.filter(
(e) =>
Number.isFinite(e.min) &&
Number.isFinite(e.max) &&
e.max >= e.min,
),
),
b = computed(() =>
y.value.length ? Math.min(...y.value.map((e) => e.min)) : 0,
),
x = computed(() =>
y.value.length ? Math.max(...y.value.map((e) => e.max)) : 0,
),
S = computed(() => b.value === x.value),
C = computed(() =>
_.modelValue == null ||
_.modelValue === `` ||
!Number.isFinite(Number(_.modelValue))
? null
: Number(_.modelValue),
),
w = computed(() =>
y.value.length
? S.value
? `当前线路带宽固定为 ${b.value} Mbps。`
: `设置服务器的带宽上限,可输入数值或拖动滑块。可选范围 ${b.value}–${x.value} Mbps,数值会自动匹配可用档位。`
: `当前线路暂无可用带宽。`,
);
function T(e) {
// 将任意输入映射到最近合法档位,并限制浮点小数精度,避免步长计算产生漂移。
let t = b.value,
n = 1 / 0;
for (let r of y.value) {
let i = Number(
Math.min(
r.max,
Math.max(
r.min,
r.min + Math.round((e - r.min) / r.step) * r.step,
),
).toFixed(8),
),
a = Math.abs(i - e);
a < n && ((t = i), (n = a));
}
return t;
}
let E = !1;
function D(e, t = !0) {
if (
_.disabled ||
S.value ||
e === null ||
!Number.isFinite(e) ||
!y.value.length
)
return;
let n = T(e);
C.value !== n &&
(v(`update:modelValue`, n), t ? v(`change`) : (E = !0));
}
function O(e) {
let t = e.target;
_.disabled ||
S.value ||
(D(Number(t.value), !1), (t.value = String(T(Number(t.value)))));
}
function k() {
// E 记录滑块期间是否真正改值,松开后只触发一次报价重算。
(E && !_.disabled && !S.value && v(`change`), (E = !1));
}
function A(e) {
// Home/End 选边界,方向键与翻页键选择跨区间的相邻有效档位。
if (_.disabled || S.value) return;
if (e.key === `Home` || e.key === `End`) {
(e.preventDefault(), D(e.key === `Home` ? b.value : x.value));
return;
}
let t = [`ArrowRight`, `ArrowUp`, `PageUp`].includes(e.key)
? 1
: [`ArrowLeft`, `ArrowDown`, `PageDown`].includes(e.key)
? -1
: 0;
if (!t) return;
e.preventDefault();
let n = C.value ?? b.value,
r = y.value.flatMap((e) => {
let r =
t > 0
? Math.max(
e.min,
e.min +
(Math.floor((n - e.min) / e.step + 1e-7) + 1) *
e.step,
)
: Math.min(
e.max,
e.min +
(Math.ceil((n - e.min) / e.step - 1e-7) - 1) * e.step,
);
return r >= e.min && r <= e.max ? [r] : [];
});
r.length && D(t > 0 ? Math.min(...r) : Math.max(...r));
}
async function j(t) {
// 等待组件内部事件结束,再把已归一化数值同步回输入框和读屏属性。
(await Promise.resolve(), await nextTick());
let n = t.originalEvent.target;
((n.value = C.value === null ? `` : String(C.value)),
C.value === null
? n.removeAttribute(`aria-valuenow`)
: n.setAttribute(`aria-valuenow`, String(C.value)));
}
function M(e) {
if (e.key === `ArrowUp` || e.key === `ArrowDown`)
return (
e.stopPropagation(),
A(e),
j({
originalEvent: e,
})
);
if (e.key === `Enter`)
return new Promise((t) => {
setTimeout(() => {
j({
originalEvent: e,
}).then(t);
}, 0);
});
}
return (e, n) => {
let u = inputnumber,
_ = tooltip;
return (
openBlock(),
createElementBlock(`div`, p, [
createElementVNode(`div`, m, [
(n[1] ||= createElementVNode(`span`, null, `带宽上限`, -1)),
withDirectives(
(openBlock(),
createElementBlock(
`button`,
{
class: `bandwidth-help`,
type: `button`,
"aria-label": unref(w),
},
[
...(n[0] ||= [
createElementVNode(
`i`,
{
class: `pi pi-question-circle`,
"aria-hidden": `true`,
},
null,
-1,
),
]),
],
8,
h,
)),
[
[
_,
{
value: unref(w),
autoHide: !1,
},
void 0,
{
top: !0,
},
],
],
),
]),
createElementVNode(
`div`,
{
class: normalizeClass([
`bandwidth-capacity`,
{
"is-disabled": s.disabled,
},
]),
onKeydownCapture: M,
},
[
createVNode(
u,
{
"aria-label": `带宽上限`,
disabled: s.disabled || unref(S),
"model-value": unref(C),
min: unref(b),
max: unref(x),
"use-grouping": !1,
"onUpdate:modelValue": D,
onBlur: j,
},
null,
8,
[`disabled`, `model-value`, `min`, `max`],
),
(n[2] ||= createElementVNode(
`span`,
{
class: `bandwidth-unit`,
"aria-hidden": `true`,
},
`Mbps`,
-1,
)),
],
34,
),
createElementVNode(
`input`,
{
class: `bandwidth-slider`,
type: `range`,
"aria-label": `带宽上限滑块`,
"aria-valuetext": `${unref(C) ?? unref(b)} Mbps`,
disabled: s.disabled || unref(S),
value: unref(C) ?? unref(b),
min: unref(b),
max: unref(x),
step: `any`,
onInput: O,
onChange: k,
onKeydown: A,
},
null,
40,
g,
),
])
);
};
},
}),
[[`__scopeId`, `data-v-45a9c613`]],
),
{
__name: `ConfigBandwidth`,
},
);
export {};
export default _;
</script>