Files
flvx/vite-frontend/src/pages/tunnel/form.ts
T
sagitchu 103290ed35 fix: 节点离线时允许删除隧道关联,但禁止新增隧道 (#342)
- prepareTunnelCreateState: 更新隧道时允许已关联的离线节点,仅拒绝新增的离线节点
- syncForwardServicesWithWarnings: 离线节点跳过下发并返回警告,不再硬性失败
- applyTunnelRuntime: 所有节点类型均支持离线错误延迟处理
- 前端 validateTunnelForm: 编辑模式下跳过离线节点验证

Closes #342
2026-03-28 19:30:30 +08:00

116 lines
2.9 KiB
TypeScript

interface TunnelChainNode {
nodeId: number;
}
interface TunnelFormInput {
name: string;
type: number;
inNodeId: TunnelChainNode[];
outNodeId?: TunnelChainNode[];
trafficRatio: number;
}
interface TunnelNodeInput {
id: number;
status: number;
}
export const createTunnelFormDefaults = () => {
return {
name: "",
type: 1,
inNodeId: [],
outNodeId: [],
chainNodes: [],
flow: 1,
trafficRatio: 1.0,
inIp: "",
ipPreference: "",
status: 1,
};
};
export const validateTunnelForm = (
form: TunnelFormInput,
nodes: TunnelNodeInput[],
isEdit = false,
): Record<string, string> => {
const errors: Record<string, string> = {};
if (!form.name.trim()) {
errors.name = "请输入隧道名称";
} else if (form.name.length < 2 || form.name.length > 50) {
errors.name = "隧道名称长度应在2-50个字符之间";
}
if (!form.inNodeId || form.inNodeId.length === 0) {
errors.inNodeId = "请至少选择一个入口节点";
} else if (!isEdit) {
// Only enforce online check for new tunnels. During edit the backend
// allows existing offline nodes (user may be removing them).
const offlineInNodes = form.inNodeId.filter((item) => {
const node = nodes.find((n) => n.id === item.nodeId);
return node && node.status !== 1;
});
if (offlineInNodes.length > 0) {
errors.inNodeId = "所有入口节点必须在线";
}
}
if (form.trafficRatio <= 0 || form.trafficRatio > 100.0) {
errors.trafficRatio = "流量倍率须大于0,支持小数(如 0.5)";
}
if (form.type === 2) {
if (!form.outNodeId || form.outNodeId.length === 0) {
errors.outNodeId = "请至少选择一个出口节点";
} else {
if (!isEdit) {
const offlineOutNodes = form.outNodeId.filter((item) => {
const node = nodes.find((n) => n.id === item.nodeId);
return node && node.status !== 1;
});
if (offlineOutNodes.length > 0) {
errors.outNodeId = "所有出口节点必须在线";
}
}
const inNodeIds = form.inNodeId.map((item) => item.nodeId);
const outNodeIds = form.outNodeId.map((item) => item.nodeId);
const overlap = inNodeIds.filter((id) => outNodeIds.includes(id));
if (overlap.length > 0) {
errors.outNodeId = "隧道转发模式下,入口和出口不能有相同节点";
}
}
}
return errors;
};
export const getTunnelTypeDisplay = (type: number) => {
switch (type) {
case 1:
return { text: "端口转发", color: "primary" };
case 2:
return { text: "隧道转发", color: "secondary" };
default:
return { text: "未知", color: "default" };
}
};
export const getTunnelFlowDisplay = (flow: number) => {
switch (flow) {
case 1:
return "单向计算";
case 2:
return "双向计算";
default:
return "未知";
}
};