2023-11-27 15:03:25 +08:00
|
|
|
|
<script lang="ts" setup>
|
2024-08-16 23:59:40 +08:00
|
|
|
|
import { defineComponent, onMounted, onUnmounted, reactive, ref } from "vue";
|
2023-11-27 15:03:25 +08:00
|
|
|
|
import Breadcrumb from "@/layout/compoenets/Breadcrumb.vue";
|
2024-08-16 23:59:40 +08:00
|
|
|
|
import { ElMessage, FormInstance, FormRules } from "element-plus";
|
|
|
|
|
import { ipcRenderer } from "electron";
|
|
|
|
|
import { clone } from "@/utils/clone";
|
|
|
|
|
import { useDebounceFn } from "@vueuse/core";
|
2024-08-16 16:23:20 +08:00
|
|
|
|
import IconifyIconOffline from "@/components/IconifyIcon/src/iconifyIconOffline";
|
|
|
|
|
|
2023-11-27 15:03:25 +08:00
|
|
|
|
defineComponent({
|
|
|
|
|
name: "Proxy"
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 代理列表
|
|
|
|
|
*/
|
|
|
|
|
const proxys = ref<Array<Proxy>>([]);
|
|
|
|
|
/**
|
|
|
|
|
* loading
|
|
|
|
|
*/
|
|
|
|
|
const loading = ref({
|
|
|
|
|
list: 1,
|
2024-08-11 18:19:45 +08:00
|
|
|
|
form: 0,
|
|
|
|
|
localPorts: 1
|
2023-11-27 15:03:25 +08:00
|
|
|
|
});
|
|
|
|
|
|
2024-08-11 18:19:45 +08:00
|
|
|
|
const localPorts = ref<Array<LocalPort>>([]);
|
|
|
|
|
const listPortsVisible = ref(false);
|
|
|
|
|
|
2023-11-27 15:03:25 +08:00
|
|
|
|
/**
|
|
|
|
|
* 弹出层属性
|
|
|
|
|
*/
|
|
|
|
|
const edit = ref({
|
|
|
|
|
title: "新增代理",
|
|
|
|
|
visible: false
|
|
|
|
|
});
|
|
|
|
|
|
2024-08-16 23:59:40 +08:00
|
|
|
|
const defaultForm = ref<Proxy>({
|
2023-11-27 15:03:25 +08:00
|
|
|
|
_id: "",
|
|
|
|
|
name: "",
|
|
|
|
|
type: "http",
|
|
|
|
|
localIp: "",
|
|
|
|
|
localPort: 8080,
|
|
|
|
|
remotePort: 8080,
|
2024-08-16 23:59:40 +08:00
|
|
|
|
customDomains: [""],
|
2024-08-17 00:20:47 +08:00
|
|
|
|
stcpModel: "visitors",
|
2024-08-16 23:59:40 +08:00
|
|
|
|
serverName: "",
|
|
|
|
|
secretKey: "",
|
|
|
|
|
bindAddr: "",
|
|
|
|
|
bindPort: null
|
2023-11-27 15:03:25 +08:00
|
|
|
|
});
|
|
|
|
|
|
2024-08-16 23:59:40 +08:00
|
|
|
|
/**
|
|
|
|
|
* 表单内容
|
|
|
|
|
*/
|
|
|
|
|
const editForm = ref<Proxy>(defaultForm.value);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 代理类型
|
|
|
|
|
*/
|
|
|
|
|
const proxyTypes = ref(["http", "https", "tcp", "udp", "stcp"]);
|
|
|
|
|
|
|
|
|
|
const stcpModels = ref([
|
|
|
|
|
{
|
|
|
|
|
label: "访问者",
|
2024-08-17 00:20:47 +08:00
|
|
|
|
value: "visitors"
|
2024-08-16 23:59:40 +08:00
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "被访问者",
|
|
|
|
|
value: "visited"
|
|
|
|
|
}
|
|
|
|
|
]);
|
|
|
|
|
|
2023-11-27 15:03:25 +08:00
|
|
|
|
/**
|
|
|
|
|
* 表单校验
|
|
|
|
|
*/
|
|
|
|
|
const editFormRules = reactive<FormRules>({
|
|
|
|
|
name: [
|
2024-08-16 23:59:40 +08:00
|
|
|
|
{ required: true, message: "请输入名称", trigger: "blur" }
|
2023-11-27 15:03:25 +08:00
|
|
|
|
// {
|
|
|
|
|
// pattern: /^[a-zA-Z]+$/,
|
|
|
|
|
// message: "名称只能是英文",
|
|
|
|
|
// trigger: "blur"
|
|
|
|
|
// }
|
|
|
|
|
],
|
2024-08-16 23:59:40 +08:00
|
|
|
|
type: [{ required: true, message: "请选择类型", trigger: "blur" }],
|
2023-11-27 15:03:25 +08:00
|
|
|
|
localIp: [
|
2024-08-16 23:59:40 +08:00
|
|
|
|
{ required: true, message: "请输入内网地址", trigger: "blur" },
|
|
|
|
|
{
|
|
|
|
|
pattern: /^[\w-]+(\.[\w-]+)+$/,
|
|
|
|
|
message: "请输入正确的内网地址",
|
|
|
|
|
trigger: "blur"
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
localPort: [{ required: true, message: "请输入本地端口", trigger: "blur" }],
|
|
|
|
|
remotePort: [{ required: true, message: "请输入远程端口", trigger: "blur" }],
|
|
|
|
|
stcpModel: [{ required: true, message: "请选择stcp模式", trigger: "blur" }],
|
|
|
|
|
secretKey: [
|
|
|
|
|
{ required: true, message: "请输入stcp共享密钥", trigger: "blur" }
|
|
|
|
|
],
|
|
|
|
|
serverName: [
|
|
|
|
|
{ required: true, message: "请输入stcp被访问者代理名称", trigger: "blur" }
|
|
|
|
|
],
|
|
|
|
|
bindAddr: [
|
|
|
|
|
{ required: true, message: "请输入绑定的地址", trigger: "blur" },
|
2023-11-27 15:03:25 +08:00
|
|
|
|
{
|
|
|
|
|
pattern: /^[\w-]+(\.[\w-]+)+$/,
|
|
|
|
|
message: "请输入正确的内网地址",
|
|
|
|
|
trigger: "blur"
|
|
|
|
|
}
|
|
|
|
|
],
|
2024-08-16 23:59:40 +08:00
|
|
|
|
bindPort: [{ required: true, message: "请输入绑定的端口", trigger: "blur" }]
|
2023-11-27 15:03:25 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 表单dom
|
|
|
|
|
*/
|
|
|
|
|
const editFormRef = ref<FormInstance>();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 提交表单
|
|
|
|
|
*/
|
|
|
|
|
const handleSubmit = async () => {
|
|
|
|
|
if (!editFormRef.value) return;
|
|
|
|
|
await editFormRef.value.validate(valid => {
|
|
|
|
|
if (valid) {
|
|
|
|
|
loading.value.form = 1;
|
|
|
|
|
const data = clone(editForm.value);
|
|
|
|
|
if (data._id) {
|
|
|
|
|
ipcRenderer.send("proxy.updateProxy", data);
|
|
|
|
|
} else {
|
|
|
|
|
ipcRenderer.send("proxy.insertProxy", data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 添加代理域名
|
|
|
|
|
*/
|
|
|
|
|
const handleAddDomain = () => {
|
|
|
|
|
editForm.value.customDomains.push("");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 删除代理列表
|
|
|
|
|
* @param index
|
|
|
|
|
*/
|
|
|
|
|
const handleDeleteDomain = (index: number) => {
|
|
|
|
|
editForm.value.customDomains.splice(index, 1);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 加载代理
|
|
|
|
|
*/
|
|
|
|
|
const handleLoadProxys = () => {
|
|
|
|
|
ipcRenderer.send("proxy.getProxys");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 删除代理
|
|
|
|
|
* @param proxy
|
|
|
|
|
*/
|
|
|
|
|
const handleDeleteProxy = (proxy: Proxy) => {
|
|
|
|
|
ipcRenderer.send("proxy.deleteProxyById", proxy._id);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 重置表单
|
|
|
|
|
*/
|
|
|
|
|
const handleResetForm = () => {
|
2024-08-16 23:59:40 +08:00
|
|
|
|
editForm.value = defaultForm.value;
|
2023-11-27 15:03:25 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 初始化回调
|
|
|
|
|
*/
|
|
|
|
|
const handleInitHook = () => {
|
|
|
|
|
const InsertOrUpdateHook = (message: string, args: any) => {
|
|
|
|
|
loading.value.form--;
|
2024-08-16 23:59:40 +08:00
|
|
|
|
const { err } = args;
|
2023-11-27 15:03:25 +08:00
|
|
|
|
if (!err) {
|
|
|
|
|
ElMessage({
|
|
|
|
|
type: "success",
|
|
|
|
|
message: message
|
|
|
|
|
});
|
|
|
|
|
handleResetForm();
|
|
|
|
|
handleLoadProxys();
|
|
|
|
|
edit.value.visible = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ipcRenderer.on("Proxy.insertProxy.hook", (event, args) => {
|
|
|
|
|
InsertOrUpdateHook("新增成功", args);
|
|
|
|
|
});
|
|
|
|
|
ipcRenderer.on("Proxy.updateProxy.hook", (event, args) => {
|
|
|
|
|
InsertOrUpdateHook("修改成功", args);
|
|
|
|
|
});
|
2024-08-11 18:19:45 +08:00
|
|
|
|
|
|
|
|
|
ipcRenderer.on("local.getLocalPorts.hook", (event, args) => {
|
|
|
|
|
loading.value.localPorts--;
|
|
|
|
|
localPorts.value = args.data;
|
2024-08-16 23:59:40 +08:00
|
|
|
|
console.log("本地端口", localPorts.value);
|
|
|
|
|
});
|
2023-11-27 15:03:25 +08:00
|
|
|
|
// ipcRenderer.on("Proxy.updateProxy.hook", (event, args) => {
|
|
|
|
|
// loading.value.form--;
|
|
|
|
|
// const { err } = args;
|
|
|
|
|
// if (!err) {
|
|
|
|
|
// ElMessage({
|
|
|
|
|
// type: "success",
|
|
|
|
|
// message: "修改成功"
|
|
|
|
|
// });
|
|
|
|
|
// handleResetForm();
|
|
|
|
|
// handleLoadProxys();
|
|
|
|
|
// edit.value.visible = false;
|
|
|
|
|
// }
|
|
|
|
|
// });
|
|
|
|
|
ipcRenderer.on("Proxy.getProxys.hook", (event, args) => {
|
|
|
|
|
loading.value.list--;
|
2024-08-16 23:59:40 +08:00
|
|
|
|
const { err, data } = args;
|
2023-11-27 15:03:25 +08:00
|
|
|
|
if (!err) {
|
|
|
|
|
proxys.value = data;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
ipcRenderer.on("Proxy.deleteProxyById.hook", (event, args) => {
|
2024-08-16 23:59:40 +08:00
|
|
|
|
const { err, data } = args;
|
2023-11-27 15:03:25 +08:00
|
|
|
|
if (!err) {
|
|
|
|
|
handleLoadProxys();
|
|
|
|
|
ElMessage({
|
|
|
|
|
type: "success",
|
|
|
|
|
message: "删除成功"
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
const handleOpenInsert = () => {
|
|
|
|
|
edit.value = {
|
|
|
|
|
title: "新增代理",
|
|
|
|
|
visible: true
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleOpenUpdate = (proxy: Proxy) => {
|
|
|
|
|
editForm.value = clone(proxy);
|
|
|
|
|
edit.value = {
|
|
|
|
|
title: "修改代理",
|
|
|
|
|
visible: true
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2024-08-11 18:19:45 +08:00
|
|
|
|
const handleLoadLocalPorts = () => {
|
|
|
|
|
loading.value.localPorts = 1;
|
2024-08-16 23:59:40 +08:00
|
|
|
|
ipcRenderer.send("local.getLocalPorts");
|
|
|
|
|
};
|
2024-08-11 18:19:45 +08:00
|
|
|
|
|
|
|
|
|
const handleSelectLocalPort = useDebounceFn((port: number) => {
|
|
|
|
|
editForm.value.localPort = port;
|
|
|
|
|
handleCloseLocalPortDialog();
|
2024-08-16 23:59:40 +08:00
|
|
|
|
});
|
2024-08-11 18:19:45 +08:00
|
|
|
|
|
|
|
|
|
const handleCloseLocalPortDialog = () => {
|
|
|
|
|
listPortsVisible.value = false;
|
2024-08-16 23:59:40 +08:00
|
|
|
|
};
|
2024-08-11 18:19:45 +08:00
|
|
|
|
|
|
|
|
|
const handleOpenLocalPortDialog = () => {
|
|
|
|
|
listPortsVisible.value = true;
|
|
|
|
|
handleLoadLocalPorts();
|
|
|
|
|
};
|
|
|
|
|
|
2024-08-16 17:06:54 +08:00
|
|
|
|
interface RestaurantItem {
|
2024-08-16 23:59:40 +08:00
|
|
|
|
value: string;
|
2024-08-16 17:06:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-16 23:59:40 +08:00
|
|
|
|
const commonIp = ref<Array<RestaurantItem>>([]);
|
2024-08-16 17:06:54 +08:00
|
|
|
|
|
|
|
|
|
const handleIpFetchSuggestions = (queryString: string, cb: any) => {
|
|
|
|
|
const results = queryString
|
2024-08-16 23:59:40 +08:00
|
|
|
|
? commonIp.value.filter(f => {
|
|
|
|
|
return f.value.toLowerCase().indexOf(queryString.toLowerCase()) !== -1;
|
2024-08-16 17:06:54 +08:00
|
|
|
|
})
|
2024-08-16 23:59:40 +08:00
|
|
|
|
: commonIp.value;
|
|
|
|
|
console.log(results, "results");
|
|
|
|
|
cb(commonIp.value);
|
|
|
|
|
};
|
2024-08-16 17:06:54 +08:00
|
|
|
|
|
2023-11-27 15:03:25 +08:00
|
|
|
|
onMounted(() => {
|
|
|
|
|
handleInitHook();
|
|
|
|
|
handleLoadProxys();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
ipcRenderer.removeAllListeners("Proxy.insertProxy.hook");
|
|
|
|
|
ipcRenderer.removeAllListeners("Proxy.updateProxy.hook");
|
|
|
|
|
ipcRenderer.removeAllListeners("Proxy.deleteProxyById.hook");
|
|
|
|
|
ipcRenderer.removeAllListeners("Proxy.getProxys.hook");
|
2024-08-11 18:19:45 +08:00
|
|
|
|
ipcRenderer.removeAllListeners("local.getLocalPorts.hook");
|
2023-11-27 15:03:25 +08:00
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
<template>
|
|
|
|
|
<!-- <coming-soon />-->
|
|
|
|
|
<div class="main">
|
|
|
|
|
<breadcrumb>
|
2024-08-22 14:28:06 +08:00
|
|
|
|
<el-button class="mr-2" type="primary" @click="handleOpenInsert">
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<IconifyIconOffline icon="add" />
|
2024-08-21 22:31:12 +08:00
|
|
|
|
</el-button>
|
2023-11-27 15:03:25 +08:00
|
|
|
|
</breadcrumb>
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<div class="app-container-breadcrumb pr-2" v-loading="loading.list > 0">
|
2023-11-27 15:03:25 +08:00
|
|
|
|
<template v-if="proxys && proxys.length > 0">
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
<el-col
|
2024-08-16 23:59:40 +08:00
|
|
|
|
v-for="proxy in proxys"
|
|
|
|
|
:key="proxy._id"
|
|
|
|
|
:lg="6"
|
|
|
|
|
:md="8"
|
|
|
|
|
:sm="12"
|
|
|
|
|
:xl="6"
|
2024-08-21 13:46:14 +08:00
|
|
|
|
:xs="12"
|
2024-08-16 23:59:40 +08:00
|
|
|
|
class="mb-[20px]"
|
2023-11-27 15:03:25 +08:00
|
|
|
|
>
|
|
|
|
|
<div class="bg-white w-full rounded drop-shadow-xl p-4">
|
|
|
|
|
<div class="w-full flex justify-between">
|
|
|
|
|
<div class="flex">
|
|
|
|
|
<div
|
2024-08-16 23:59:40 +08:00
|
|
|
|
class="w-12 h-12 rounded mr-4 flex justify-center items-center font-bold"
|
|
|
|
|
:class="proxy.type"
|
2023-11-27 15:03:25 +08:00
|
|
|
|
>
|
|
|
|
|
<span class="text-white text-sm">{{ proxy.type }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="h-12 relative">
|
|
|
|
|
<div class="text-sm font-bold">{{ proxy.name }}</div>
|
2024-08-17 00:34:23 +08:00
|
|
|
|
<el-tag
|
|
|
|
|
v-if="
|
|
|
|
|
proxy.type === 'stcp' && proxy.stcpModel === 'visitors'
|
|
|
|
|
"
|
|
|
|
|
size="small"
|
|
|
|
|
>
|
|
|
|
|
访问者
|
|
|
|
|
</el-tag>
|
|
|
|
|
<el-tag
|
|
|
|
|
size="small"
|
|
|
|
|
v-if="
|
|
|
|
|
proxy.type === 'stcp' && proxy.stcpModel === 'visited'
|
|
|
|
|
"
|
|
|
|
|
>被访问者
|
|
|
|
|
</el-tag>
|
2024-08-11 15:12:45 +08:00
|
|
|
|
<!-- <el-tag-->
|
|
|
|
|
<!-- size="small"-->
|
|
|
|
|
<!-- class="absolute bottom-0"-->
|
|
|
|
|
<!-- type="success"-->
|
|
|
|
|
<!-- effect="plain"-->
|
|
|
|
|
<!-- >正常-->
|
|
|
|
|
<!-- </el-tag>-->
|
2023-11-27 15:03:25 +08:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<el-dropdown size="small">
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<a
|
|
|
|
|
href="javascript:void(0)"
|
|
|
|
|
class="text-xl text-[#ADADAD] hover:text-[#5A3DAA]"
|
2023-11-27 15:03:25 +08:00
|
|
|
|
>
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<IconifyIconOffline icon="more-vert" />
|
2023-11-27 15:03:25 +08:00
|
|
|
|
</a>
|
|
|
|
|
<template #dropdown>
|
|
|
|
|
<el-dropdown-menu>
|
|
|
|
|
<el-dropdown-item @click="handleOpenUpdate(proxy)">
|
2024-08-16 16:23:20 +08:00
|
|
|
|
<IconifyIconOffline
|
2024-08-16 23:59:40 +08:00
|
|
|
|
icon="edit"
|
|
|
|
|
class="primary-text text-[14px]"
|
2023-11-27 15:03:25 +08:00
|
|
|
|
/>
|
|
|
|
|
<span class="ml-1">修 改</span>
|
|
|
|
|
</el-dropdown-item>
|
|
|
|
|
<el-dropdown-item @click="handleDeleteProxy(proxy)">
|
2024-08-16 16:23:20 +08:00
|
|
|
|
<IconifyIconOffline
|
2024-08-16 23:59:40 +08:00
|
|
|
|
icon="delete-rounded"
|
|
|
|
|
class="text-red-500 text-[14px]"
|
2023-11-27 15:03:25 +08:00
|
|
|
|
/>
|
|
|
|
|
<span class="ml-1">删 除</span>
|
|
|
|
|
</el-dropdown-item>
|
|
|
|
|
</el-dropdown-menu>
|
|
|
|
|
</template>
|
|
|
|
|
</el-dropdown>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex justify-between mt-4">
|
2024-08-17 00:34:23 +08:00
|
|
|
|
<div
|
|
|
|
|
class="text-sm text-left"
|
|
|
|
|
v-if="proxy.type !== 'stcp' || proxy.stcpModel !== 'visitors'"
|
|
|
|
|
>
|
2023-11-27 15:03:25 +08:00
|
|
|
|
<p class="text-[#ADADAD] font-bold">内网地址</p>
|
|
|
|
|
<p>{{ proxy.localIp }}</p>
|
|
|
|
|
</div>
|
2024-08-17 00:34:23 +08:00
|
|
|
|
|
2023-11-27 15:03:25 +08:00
|
|
|
|
<div class="text-sm text-center" v-if="proxy.type === 'tcp'">
|
|
|
|
|
<p class="text-[#ADADAD] font-bold">外网端口</p>
|
|
|
|
|
<p>{{ proxy.remotePort }}</p>
|
|
|
|
|
</div>
|
2024-08-17 00:34:23 +08:00
|
|
|
|
<div
|
|
|
|
|
class="text-sm text-center"
|
|
|
|
|
v-if="proxy.type !== 'stcp' || proxy.stcpModel !== 'visitors'"
|
|
|
|
|
>
|
2023-11-27 15:03:25 +08:00
|
|
|
|
<p class="text-[#ADADAD] font-bold">内网端口</p>
|
|
|
|
|
<p>{{ proxy.localPort }}</p>
|
|
|
|
|
</div>
|
2024-08-17 00:34:23 +08:00
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
class="text-sm text-center"
|
|
|
|
|
v-if="proxy.type === 'stcp' && proxy.stcpModel === 'visitors'"
|
|
|
|
|
>
|
|
|
|
|
<p class="text-[#ADADAD] font-bold">访问者名称</p>
|
|
|
|
|
<p>{{ proxy.serverName }}</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
class="text-sm text-center"
|
|
|
|
|
v-if="proxy.type === 'stcp' && proxy.stcpModel === 'visitors'"
|
|
|
|
|
>
|
|
|
|
|
<p class="text-[#ADADAD] font-bold">绑定地址</p>
|
|
|
|
|
<p>{{ proxy.bindAddr }}</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
class="text-sm text-center"
|
|
|
|
|
v-if="proxy.type === 'stcp' && proxy.stcpModel === 'visitors'"
|
|
|
|
|
>
|
|
|
|
|
<p class="text-[#ADADAD] font-bold">绑定端口</p>
|
|
|
|
|
<p>{{ proxy.bindPort }}</p>
|
|
|
|
|
</div>
|
2023-11-27 15:03:25 +08:00
|
|
|
|
</div>
|
|
|
|
|
<!-- <div class="text-sm text-[#ADADAD] py-2">本地地址 本地端口</div>-->
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
</template>
|
|
|
|
|
<div
|
2024-08-16 23:59:40 +08:00
|
|
|
|
v-else
|
|
|
|
|
class="w-full h-full bg-white rounded p-2 overflow-hidden drop-shadow-xl flex justify-center items-center"
|
2023-11-27 15:03:25 +08:00
|
|
|
|
>
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<el-empty description="暂无代理" />
|
2023-11-27 15:03:25 +08:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<el-dialog
|
2024-08-16 23:59:40 +08:00
|
|
|
|
v-model="edit.visible"
|
|
|
|
|
:title="edit.title"
|
|
|
|
|
class="sm:w-[500px] md:w-[600px] lg:w-[800px]"
|
|
|
|
|
top="5%"
|
2023-11-27 15:03:25 +08:00
|
|
|
|
>
|
|
|
|
|
<el-form
|
2024-08-16 23:59:40 +08:00
|
|
|
|
v-loading="loading.form"
|
|
|
|
|
label-position="top"
|
|
|
|
|
:model="editForm"
|
|
|
|
|
:rules="editFormRules"
|
|
|
|
|
ref="editFormRef"
|
2023-11-27 15:03:25 +08:00
|
|
|
|
>
|
|
|
|
|
<el-row :gutter="10">
|
|
|
|
|
<el-col :span="24">
|
2024-08-16 17:06:54 +08:00
|
|
|
|
<el-form-item label="代理类型:" prop="type">
|
2023-11-27 15:03:25 +08:00
|
|
|
|
<el-radio-group v-model="editForm.type">
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<el-radio-button
|
|
|
|
|
v-for="p in proxyTypes"
|
|
|
|
|
:key="p"
|
|
|
|
|
:label="p"
|
|
|
|
|
:value="p"
|
|
|
|
|
/>
|
2023-11-27 15:03:25 +08:00
|
|
|
|
</el-radio-group>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<template v-if="editForm.type === 'stcp'">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="stcp模式:" prop="stcpModel">
|
|
|
|
|
<el-radio-group v-model="editForm.stcpModel">
|
|
|
|
|
<el-radio
|
|
|
|
|
v-for="p in stcpModels"
|
|
|
|
|
:key="p.value"
|
|
|
|
|
:label="p.label"
|
|
|
|
|
:value="p.value"
|
|
|
|
|
/>
|
|
|
|
|
</el-radio-group>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="共享密钥:" prop="secretKey">
|
|
|
|
|
<template #label>
|
|
|
|
|
<div class="inline-block">
|
|
|
|
|
<div class="flex items-center">
|
|
|
|
|
<div class="mr-1">
|
|
|
|
|
<el-popover placement="top" trigger="hover" width="300">
|
|
|
|
|
<template #default>
|
|
|
|
|
对应参数:<span class="font-black text-[#5A3DAA]"
|
|
|
|
|
>secretKey</span
|
|
|
|
|
>
|
|
|
|
|
只有访问者与被访问者共享密钥一致的用户才能访问该服务
|
|
|
|
|
</template>
|
|
|
|
|
<template #reference>
|
|
|
|
|
<IconifyIconOffline
|
|
|
|
|
class="text-base"
|
|
|
|
|
color="#5A3DAA"
|
|
|
|
|
icon="info"
|
|
|
|
|
/>
|
|
|
|
|
</template>
|
|
|
|
|
</el-popover>
|
|
|
|
|
</div>
|
|
|
|
|
共享密钥:
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
<el-input
|
|
|
|
|
type="password"
|
|
|
|
|
v-model="editForm.secretKey"
|
|
|
|
|
placeholder="密钥"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
</template>
|
2024-08-17 00:20:47 +08:00
|
|
|
|
<el-col :span="editForm.stcpModel === 'visitors' ? 12 : 24">
|
2024-08-16 17:06:54 +08:00
|
|
|
|
<el-form-item label="代理名称:" prop="name">
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<el-input
|
|
|
|
|
v-model="editForm.name"
|
|
|
|
|
placeholder="代理名称"
|
|
|
|
|
clearable
|
|
|
|
|
/>
|
2023-11-27 15:03:25 +08:00
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<template
|
|
|
|
|
v-if="
|
|
|
|
|
editForm.type !== 'stcp' ||
|
|
|
|
|
(editForm.type === 'stcp' && editForm.stcpModel === 'visited')
|
|
|
|
|
"
|
|
|
|
|
>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="内网地址:" prop="localIp">
|
|
|
|
|
<!-- <el-autocomplete-->
|
|
|
|
|
<!-- v-model="editForm.localIp"-->
|
|
|
|
|
<!-- :fetch-suggestions="handleIpFetchSuggestions"-->
|
|
|
|
|
<!-- clearable-->
|
|
|
|
|
<!-- placeholder="127.0.0.1"-->
|
|
|
|
|
<!-- />-->
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="editForm.localIp"
|
|
|
|
|
placeholder="127.0.0.1"
|
|
|
|
|
clearable
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="内网端口:" prop="localPort">
|
|
|
|
|
<el-input-number
|
2024-08-11 15:12:45 +08:00
|
|
|
|
placeholder="8080"
|
2024-08-11 18:19:45 +08:00
|
|
|
|
class="local-port-input"
|
2024-08-11 15:12:45 +08:00
|
|
|
|
:min="0"
|
|
|
|
|
:max="65535"
|
|
|
|
|
v-model="editForm.localPort"
|
|
|
|
|
controls-position="right"
|
2024-08-16 23:59:40 +08:00
|
|
|
|
/>
|
|
|
|
|
<el-button
|
|
|
|
|
class="ml-[10px]"
|
|
|
|
|
plain
|
|
|
|
|
type="primary"
|
|
|
|
|
@click="handleOpenLocalPortDialog"
|
|
|
|
|
>
|
|
|
|
|
<IconifyIconOffline
|
|
|
|
|
class="cursor-pointer mr-2"
|
|
|
|
|
icon="bring-your-own-ip-rounded"
|
|
|
|
|
/>
|
|
|
|
|
本地端口
|
|
|
|
|
</el-button>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
</template>
|
2024-08-11 15:12:45 +08:00
|
|
|
|
<template v-if="editForm.type === 'tcp' || editForm.type === 'udp'">
|
2023-11-27 15:03:25 +08:00
|
|
|
|
<el-col :span="8">
|
|
|
|
|
<el-form-item label="外网端口:" prop="remotePort">
|
|
|
|
|
<el-input-number
|
2024-08-16 23:59:40 +08:00
|
|
|
|
:min="0"
|
|
|
|
|
:max="65535"
|
|
|
|
|
placeholder="8080"
|
|
|
|
|
v-model="editForm.remotePort"
|
|
|
|
|
controls-position="right"
|
2023-11-27 15:03:25 +08:00
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
</template>
|
|
|
|
|
<template
|
2024-08-16 23:59:40 +08:00
|
|
|
|
v-if="editForm.type === 'http' || editForm.type === 'https'"
|
2023-11-27 15:03:25 +08:00
|
|
|
|
>
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
<el-form-item
|
2024-08-16 23:59:40 +08:00
|
|
|
|
v-for="(d, di) in editForm.customDomains"
|
|
|
|
|
:key="'domain' + di"
|
|
|
|
|
:label="di === 0 ? '自定义域名:' : ''"
|
|
|
|
|
:prop="`customDomains.${di}`"
|
|
|
|
|
:rules="[
|
2023-11-27 15:03:25 +08:00
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
message: `自定义域名不能为空`,
|
|
|
|
|
trigger: 'blur'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
pattern:
|
|
|
|
|
/^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/,
|
|
|
|
|
message: '请输入正确的域名',
|
|
|
|
|
trigger: 'blur'
|
|
|
|
|
}
|
|
|
|
|
]"
|
|
|
|
|
>
|
2024-08-16 18:19:34 +08:00
|
|
|
|
<template #label>
|
|
|
|
|
<div class="inline-block">
|
|
|
|
|
<div class="flex items-center">
|
|
|
|
|
<div class="mr-1">
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<el-popover placement="top" trigger="hover">
|
2024-08-16 18:19:34 +08:00
|
|
|
|
<template #default>
|
2024-08-16 23:59:40 +08:00
|
|
|
|
对应参数:<span class="font-black text-[#5A3DAA]"
|
|
|
|
|
>customDomains</span
|
|
|
|
|
>
|
2024-08-16 18:19:34 +08:00
|
|
|
|
</template>
|
|
|
|
|
<template #reference>
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<IconifyIconOffline
|
|
|
|
|
class="text-base"
|
|
|
|
|
color="#5A3DAA"
|
|
|
|
|
icon="info"
|
|
|
|
|
/>
|
2024-08-16 18:19:34 +08:00
|
|
|
|
</template>
|
|
|
|
|
</el-popover>
|
|
|
|
|
</div>
|
|
|
|
|
自定义域名:
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<!-- <el-popover-->
|
|
|
|
|
<!-- placement="top"-->
|
|
|
|
|
<!-- trigger="hover"-->
|
|
|
|
|
<!-- >-->
|
|
|
|
|
<!-- <template #default>-->
|
|
|
|
|
<!-- 对应参数:<span class="font-black text-[#5A3DAA]">customDomains</span>-->
|
|
|
|
|
<!-- </template>-->
|
|
|
|
|
<!-- <template #reference>-->
|
|
|
|
|
<!-- <IconifyIconOffline class="text-base" color="#5A3DAA" icon="info"/>-->
|
|
|
|
|
<!-- </template>-->
|
|
|
|
|
<!-- </el-popover>-->
|
|
|
|
|
<!-- <div class="flex items-center inin">-->
|
|
|
|
|
<!-- <div class="h-full flex items-center mr-1">-->
|
|
|
|
|
<!-- -->
|
|
|
|
|
<!-- </div>-->
|
|
|
|
|
<!-- <div>自定义域名:</div>-->
|
|
|
|
|
<!-- </div>-->
|
2024-08-16 18:19:34 +08:00
|
|
|
|
</template>
|
2023-11-27 15:03:25 +08:00
|
|
|
|
<el-input
|
2024-08-16 23:59:40 +08:00
|
|
|
|
class="domain-input"
|
|
|
|
|
placeholder="github.com"
|
|
|
|
|
v-model="editForm.customDomains[di]"
|
2023-11-27 15:03:25 +08:00
|
|
|
|
/>
|
|
|
|
|
<el-button
|
2024-08-16 23:59:40 +08:00
|
|
|
|
class="ml-[10px]"
|
|
|
|
|
type="primary"
|
|
|
|
|
plain
|
|
|
|
|
@click="handleAddDomain"
|
2023-11-27 15:03:25 +08:00
|
|
|
|
>
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<IconifyIconOffline icon="add" />
|
2023-11-27 15:03:25 +08:00
|
|
|
|
</el-button>
|
|
|
|
|
<el-button
|
2024-08-16 23:59:40 +08:00
|
|
|
|
type="danger"
|
|
|
|
|
plain
|
|
|
|
|
@click="handleDeleteDomain(di)"
|
|
|
|
|
:disabled="editForm.customDomains.length === 1"
|
2023-11-27 15:03:25 +08:00
|
|
|
|
>
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<IconifyIconOffline icon="delete-rounded" />
|
2023-11-27 15:03:25 +08:00
|
|
|
|
</el-button>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
</template>
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<template
|
2024-08-17 00:20:47 +08:00
|
|
|
|
v-if="editForm.type === 'stcp' && editForm.stcpModel === 'visitors'"
|
2024-08-16 23:59:40 +08:00
|
|
|
|
>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="被访问者代理名称:" prop="serverName">
|
|
|
|
|
<el-input
|
|
|
|
|
type="text"
|
|
|
|
|
v-model="editForm.serverName"
|
|
|
|
|
placeholder="stcp被访问者代理名称"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="绑定地址:" prop="bindAddr">
|
|
|
|
|
<template #label>
|
|
|
|
|
<div class="inline-block">
|
|
|
|
|
<div class="flex items-center">
|
|
|
|
|
<div class="mr-1">
|
|
|
|
|
<el-popover placement="top" trigger="hover" width="300">
|
|
|
|
|
<template #default>
|
|
|
|
|
对应参数:<span class="font-black text-[#5A3DAA]"
|
|
|
|
|
>bindAddr</span
|
|
|
|
|
>
|
|
|
|
|
要将被访问者的服务绑定到本地哪个<span
|
|
|
|
|
class="font-black text-[#5A3DAA]"
|
|
|
|
|
>IP</span
|
|
|
|
|
>
|
|
|
|
|
<br />
|
|
|
|
|
仅本机访问:<span class="font-black text-[#5A3DAA]"
|
|
|
|
|
>127.0.0.1</span
|
|
|
|
|
>
|
|
|
|
|
<br />
|
|
|
|
|
支持局域网其他设备访问:<span
|
|
|
|
|
class="font-black text-[#5A3DAA]"
|
|
|
|
|
>0.0.0.0</span
|
|
|
|
|
>
|
|
|
|
|
<br />
|
|
|
|
|
</template>
|
|
|
|
|
<template #reference>
|
|
|
|
|
<IconifyIconOffline
|
|
|
|
|
class="text-base"
|
|
|
|
|
color="#5A3DAA"
|
|
|
|
|
icon="info"
|
|
|
|
|
/>
|
|
|
|
|
</template>
|
|
|
|
|
</el-popover>
|
|
|
|
|
</div>
|
|
|
|
|
绑定地址:
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
<el-input
|
|
|
|
|
type="text"
|
|
|
|
|
v-model="editForm.bindAddr"
|
|
|
|
|
placeholder="127.0.0.1"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="绑定端口:" prop="bindPort">
|
|
|
|
|
<template #label>
|
|
|
|
|
<div class="inline-block">
|
|
|
|
|
<div class="flex items-center">
|
|
|
|
|
<div class="mr-1">
|
|
|
|
|
<el-popover placement="top" trigger="hover" width="300">
|
|
|
|
|
<template #default>
|
|
|
|
|
对应参数:<span class="font-black text-[#5A3DAA]"
|
|
|
|
|
>bindAddr</span
|
|
|
|
|
>
|
|
|
|
|
要将被访问者的服务绑定到本地哪个<span
|
|
|
|
|
class="font-black text-[#5A3DAA]"
|
|
|
|
|
>端口</span
|
|
|
|
|
>
|
|
|
|
|
<br />
|
|
|
|
|
请自行确保端口未被占用
|
|
|
|
|
</template>
|
|
|
|
|
<template #reference>
|
|
|
|
|
<IconifyIconOffline
|
|
|
|
|
class="text-base"
|
|
|
|
|
color="#5A3DAA"
|
|
|
|
|
icon="info"
|
|
|
|
|
/>
|
|
|
|
|
</template>
|
|
|
|
|
</el-popover>
|
|
|
|
|
</div>
|
|
|
|
|
绑定端口:
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
<el-input-number
|
|
|
|
|
v-model="editForm.bindPort"
|
|
|
|
|
placeholder="8080"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
</template>
|
2023-11-27 15:03:25 +08:00
|
|
|
|
<el-col :span="24">
|
|
|
|
|
<el-form-item>
|
|
|
|
|
<div class="w-full flex justify-end">
|
2024-08-11 18:19:45 +08:00
|
|
|
|
<el-button @click="edit.visible = false">
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<iconify-icon-offline
|
|
|
|
|
class="cursor-pointer mr-2"
|
|
|
|
|
icon="cancel-presentation"
|
|
|
|
|
/>
|
2024-08-16 16:23:20 +08:00
|
|
|
|
关 闭
|
|
|
|
|
</el-button>
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<el-button plain type="primary" @click="handleSubmit">
|
|
|
|
|
<IconifyIconOffline
|
|
|
|
|
class="cursor-pointer mr-2"
|
|
|
|
|
icon="save-rounded"
|
|
|
|
|
/>
|
2024-08-11 18:19:45 +08:00
|
|
|
|
保 存
|
2023-11-27 15:03:25 +08:00
|
|
|
|
</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
</el-form>
|
|
|
|
|
</el-dialog>
|
2024-08-11 18:19:45 +08:00
|
|
|
|
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<el-dialog v-model="listPortsVisible" title="本地端口" width="600" top="5%">
|
|
|
|
|
<el-table
|
|
|
|
|
:data="localPorts"
|
|
|
|
|
stripe
|
|
|
|
|
v-loading="loading.localPorts"
|
|
|
|
|
border
|
|
|
|
|
height="400"
|
|
|
|
|
>
|
|
|
|
|
<el-table-column label="协议" :width="60" prop="protocol" />
|
|
|
|
|
<el-table-column label="IP" prop="ip" />
|
|
|
|
|
<el-table-column label="端口" :width="80" prop="port" />
|
2024-08-11 18:19:45 +08:00
|
|
|
|
<el-table-column label="操作" :width="80">
|
|
|
|
|
<template #default="scope">
|
2024-08-16 23:59:40 +08:00
|
|
|
|
<el-button
|
|
|
|
|
type="text"
|
|
|
|
|
@click="handleSelectLocalPort(scope.row.port)"
|
|
|
|
|
>
|
|
|
|
|
<IconifyIconOffline
|
|
|
|
|
class="cursor-pointer mr-2"
|
|
|
|
|
icon="gesture-select"
|
|
|
|
|
/>
|
2024-08-11 18:19:45 +08:00
|
|
|
|
选择
|
|
|
|
|
</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
</el-dialog>
|
2023-11-27 15:03:25 +08:00
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
.http {
|
|
|
|
|
background: #d3585b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tcp {
|
|
|
|
|
background: #7bbc71;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.https {
|
|
|
|
|
background: #5f3bb0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-11 15:12:45 +08:00
|
|
|
|
.udp {
|
|
|
|
|
background: #5ec7fe;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-17 00:20:47 +08:00
|
|
|
|
.stcp {
|
2024-08-17 00:34:23 +08:00
|
|
|
|
background: #d63da6;
|
2024-08-17 00:20:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-11-27 15:03:25 +08:00
|
|
|
|
.domain-input {
|
|
|
|
|
width: calc(100% - 115px);
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-11 18:19:45 +08:00
|
|
|
|
.local-port-input {
|
2024-08-11 19:12:05 +08:00
|
|
|
|
width: calc(100% - 125px);
|
2024-08-11 18:19:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-11-27 15:03:25 +08:00
|
|
|
|
.domain-input-button {
|
|
|
|
|
background: #5f3bb0;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
color: white;
|
|
|
|
|
width: 32px;
|
|
|
|
|
height: 32px;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
</style>
|