init: init proj
This commit is contained in:
184
web/src/components/NodeFormModal.vue
Normal file
184
web/src/components/NodeFormModal.vue
Normal file
@@ -0,0 +1,184 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, watch } from 'vue';
|
||||
import {
|
||||
NModal,
|
||||
NForm,
|
||||
NFormItem,
|
||||
NInput,
|
||||
NInputNumber,
|
||||
NSelect,
|
||||
NSwitch,
|
||||
NButton,
|
||||
NSpace,
|
||||
useMessage,
|
||||
} from 'naive-ui';
|
||||
import { nodeInputSchema, PROTOCOLS, type NodeDto, type NodeInput } from '@proxy-station/shared';
|
||||
|
||||
const props = defineProps<{ show: boolean; node?: NodeDto | null }>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:show', v: boolean): void;
|
||||
(e: 'submit', input: NodeInput, id?: string): void;
|
||||
(e: 'delete', id: string): void;
|
||||
}>();
|
||||
|
||||
const message = useMessage();
|
||||
|
||||
const blank = (): NodeInput => ({
|
||||
name: '',
|
||||
protocol: 'vmess',
|
||||
server: '',
|
||||
port: 443,
|
||||
network: 'ws',
|
||||
wsPath: '/',
|
||||
wsHost: null,
|
||||
tls: true,
|
||||
sni: null,
|
||||
skipCertVerify: false,
|
||||
uuid: null,
|
||||
alterId: 0,
|
||||
security: 'auto',
|
||||
password: null,
|
||||
method: 'chacha20-poly1305',
|
||||
obfsType: null,
|
||||
obfsPassword: null,
|
||||
region: null,
|
||||
tags: [],
|
||||
enabled: true,
|
||||
sortOrder: 0,
|
||||
});
|
||||
|
||||
const form = reactive<NodeInput>(blank());
|
||||
|
||||
watch(
|
||||
() => props.show,
|
||||
(show) => {
|
||||
if (!show) return;
|
||||
Object.assign(form, blank(), props.node ?? {});
|
||||
}
|
||||
);
|
||||
|
||||
const isEdit = computed(() => !!props.node);
|
||||
const protocolOptions = PROTOCOLS.map((p) => ({ label: p, value: p }));
|
||||
const tagOptions = [
|
||||
{ label: 'direct(直连出口)', value: 'direct' },
|
||||
{ label: 'warp(WARP 出口)', value: 'warp' },
|
||||
];
|
||||
|
||||
const showWs = computed(() => form.protocol !== 'hysteria2');
|
||||
const showVmess = computed(() => form.protocol === 'vmess');
|
||||
const showPassword = computed(() => form.protocol !== 'vmess');
|
||||
const showSs = computed(() => form.protocol === 'shadowsocks');
|
||||
const showHy2 = computed(() => form.protocol === 'hysteria2');
|
||||
|
||||
function submit() {
|
||||
const result = nodeInputSchema.safeParse({ ...form });
|
||||
if (!result.success) {
|
||||
message.error(result.error.issues[0]?.message || '表单校验失败');
|
||||
return;
|
||||
}
|
||||
emit('submit', { ...form }, props.node?.id);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NModal
|
||||
:show="show"
|
||||
preset="card"
|
||||
:title="isEdit ? `编辑节点 · ${node?.name}` : '添加节点'"
|
||||
style="max-width: 560px"
|
||||
@update:show="emit('update:show', $event)"
|
||||
>
|
||||
<NForm label-placement="left" label-width="92">
|
||||
<NFormItem label="名称" required>
|
||||
<NInput v-model:value="form.name" placeholder="如 SG-vmess-warp" />
|
||||
</NFormItem>
|
||||
<NFormItem label="协议" required>
|
||||
<NSelect v-model:value="form.protocol" :options="protocolOptions" :disabled="isEdit" />
|
||||
</NFormItem>
|
||||
<NFormItem label="服务器" required>
|
||||
<NInput v-model:value="form.server" placeholder="域名或 IP" class="mono" />
|
||||
</NFormItem>
|
||||
<NFormItem label="端口" required>
|
||||
<NInputNumber v-model:value="form.port" :min="1" :max="65535" style="width: 100%" />
|
||||
</NFormItem>
|
||||
|
||||
<template v-if="showVmess">
|
||||
<NFormItem label="UUID" required>
|
||||
<NInput v-model:value="form.uuid" class="mono" />
|
||||
</NFormItem>
|
||||
</template>
|
||||
<template v-if="showPassword">
|
||||
<NFormItem label="密码" required>
|
||||
<NInput v-model:value="form.password" type="password" show-password-on="click" class="mono" />
|
||||
</NFormItem>
|
||||
</template>
|
||||
<template v-if="showSs">
|
||||
<NFormItem label="加密方式" required>
|
||||
<NInput v-model:value="form.method" placeholder="chacha20-poly1305" class="mono" />
|
||||
</NFormItem>
|
||||
</template>
|
||||
<template v-if="showHy2">
|
||||
<NFormItem label="混淆">
|
||||
<NSelect
|
||||
v-model:value="form.obfsType"
|
||||
:options="[
|
||||
{ label: '无', value: null as any },
|
||||
{ label: 'salamander', value: 'salamander' },
|
||||
]"
|
||||
/>
|
||||
</NFormItem>
|
||||
<NFormItem v-if="form.obfsType === 'salamander'" label="混淆密码" required>
|
||||
<NInput v-model:value="form.obfsPassword" type="password" show-password-on="click" class="mono" />
|
||||
</NFormItem>
|
||||
</template>
|
||||
|
||||
<template v-if="showWs">
|
||||
<NFormItem label="传输">
|
||||
<NSelect
|
||||
v-model:value="form.network"
|
||||
:options="[
|
||||
{ label: 'TCP', value: 'tcp' },
|
||||
{ label: 'WebSocket', value: 'ws' },
|
||||
]"
|
||||
/>
|
||||
</NFormItem>
|
||||
<template v-if="form.network === 'ws'">
|
||||
<NFormItem label="WS 路径" required>
|
||||
<NInput v-model:value="form.wsPath" placeholder="/xxxxxx" class="mono" />
|
||||
</NFormItem>
|
||||
<NFormItem label="WS Host">
|
||||
<NInput v-model:value="form.wsHost" placeholder="默认与服务器相同" class="mono" />
|
||||
</NFormItem>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<NFormItem label="TLS">
|
||||
<NSwitch v-model:value="form.tls" :disabled="form.protocol === 'hysteria2'" />
|
||||
</NFormItem>
|
||||
<NFormItem v-if="form.tls" label="SNI">
|
||||
<NInput v-model:value="form.sni" placeholder="默认与服务器相同" class="mono" />
|
||||
</NFormItem>
|
||||
|
||||
<NFormItem label="出口标签">
|
||||
<NSelect v-model:value="form.tags" multiple :options="tagOptions" placeholder="direct / warp,用于线路矩阵归位" />
|
||||
</NFormItem>
|
||||
<NFormItem label="站点代号">
|
||||
<NInput v-model:value="form.region" placeholder="如 SG/LA/RN,留空则按域名推断" />
|
||||
</NFormItem>
|
||||
<NFormItem label="启用">
|
||||
<NSwitch v-model:value="form.enabled" />
|
||||
</NFormItem>
|
||||
</NForm>
|
||||
|
||||
<template #footer>
|
||||
<NSpace justify="space-between">
|
||||
<NButton v-if="isEdit" type="error" quaternary @click="emit('delete', node!.id)">删除节点</NButton>
|
||||
<span v-else />
|
||||
<NSpace>
|
||||
<NButton @click="emit('update:show', false)">取消</NButton>
|
||||
<NButton type="primary" @click="submit">{{ isEdit ? '保存' : '添加' }}</NButton>
|
||||
</NSpace>
|
||||
</NSpace>
|
||||
</template>
|
||||
</NModal>
|
||||
</template>
|
||||
Reference in New Issue
Block a user