feat: split rate limits with configurable per-endpoint controls

This commit is contained in:
MengMengCode
2026-06-12 15:53:31 +08:00
parent 01c14ecba6
commit c7742319b2
17 changed files with 746 additions and 141 deletions
+8 -1
View File
@@ -90,7 +90,7 @@ export default function ContainerCard({ container, onRefresh }: ContainerCardPro
</div>
<div className="flex items-center gap-2 text-sm text-gray-600">
<Globe className="w-3.5 h-3.5" />
<span>{container.network_bw_mbps} Mbps</span>
<span>{formatNetworkLimit(container)}</span>
</div>
</div>
@@ -140,3 +140,10 @@ export default function ContainerCard({ container, onRefresh }: ContainerCardPro
</div>
)
}
function formatNetworkLimit(container: { network_bw_mbps?: number; network_down_mbps?: number; network_up_mbps?: number }) {
const down = Math.max(0, Number(container.network_down_mbps || container.network_bw_mbps || 0))
const up = Math.max(0, Number(container.network_up_mbps || container.network_bw_mbps || 0))
if (down === 0 && up === 0) return '不限速'
return `${down || '不限'} / 上 ${up || '不限'} Mbps`
}
@@ -21,11 +21,15 @@ const defaultForm: CreateContainerRequest = {
ram_mb: 512,
disk_gb: 10,
network_bw_mbps: 0,
network_down_mbps: 0,
network_up_mbps: 0,
monthly_traffic_gb: 0,
traffic_mode: 'total',
traffic_in_gb: 0,
traffic_out_gb: 0,
io_speed_mbps: 0,
io_read_mbps: 0,
io_write_mbps: 0,
extra_ports: [],
port_mapping_count: 2,
assign_nat: true,
@@ -498,7 +502,7 @@ export default function CreateContainerModal({ isOpen, onClose, onSuccess, exist
</Field>
</div>
<div className="grid grid-cols-3 gap-3">
<div className="grid grid-cols-1 gap-3 md:grid-cols-3">
<Field label="磁盘 (GB)">
<NumberInput
value={form.disk_gb}
@@ -509,12 +513,20 @@ export default function CreateContainerModal({ isOpen, onClose, onSuccess, exist
/>
{resourceErrors.disk_gb && <p className="mt-1 text-xs text-red-500">{resourceErrors.disk_gb}</p>}
</Field>
<Field label="带宽 (Mbps)">
<NumberInput value={form.network_bw_mbps} min={0} onChange={(value) => setForm({ ...form, network_bw_mbps: value })} />
</Field>
<Field label="IO 速度 (MB/s)">
<NumberInput value={form.io_speed_mbps} min={0} onChange={(value) => setForm({ ...form, io_speed_mbps: value })} />
</Field>
<div className="grid grid-cols-2 gap-3 md:col-span-2">
<Field label="下行带宽 (Mbps)">
<NumberInput value={form.network_down_mbps} min={0} onChange={(value) => setForm({ ...form, network_down_mbps: value, network_bw_mbps: symmetricLimit(value, form.network_up_mbps) })} />
</Field>
<Field label="上行带宽 (Mbps)">
<NumberInput value={form.network_up_mbps} min={0} onChange={(value) => setForm({ ...form, network_up_mbps: value, network_bw_mbps: symmetricLimit(form.network_down_mbps, value) })} />
</Field>
<Field label="读取 IO (MB/s)">
<NumberInput value={form.io_read_mbps} min={0} onChange={(value) => setForm({ ...form, io_read_mbps: value, io_speed_mbps: symmetricLimit(value, form.io_write_mbps) })} />
</Field>
<Field label="写入 IO (MB/s)">
<NumberInput value={form.io_write_mbps} min={0} onChange={(value) => setForm({ ...form, io_write_mbps: value, io_speed_mbps: symmetricLimit(form.io_read_mbps, value) })} />
</Field>
</div>
</div>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
@@ -779,5 +791,14 @@ function formatNATPortCount(count: number, language: Language) {
: `将分配 ${count} 个 NAT 端口`
}
function symmetricLimit(a: number, b: number) {
const left = Math.max(0, Number(a) || 0)
const right = Math.max(0, Number(b) || 0)
if (left === right) return left
if (left === 0) return right
if (right === 0) return left
return Math.min(left, right)
}
const inputClass =
'w-full px-3 py-2 border border-gray-300 rounded-md text-sm text-black bg-white focus:outline-none focus:ring-2 focus:ring-black focus:border-black'