mirror of https://gitee.com/godoos/godoos.git
9 changed files with 1355 additions and 236 deletions
@ -0,0 +1,204 @@ |
|||
<script setup lang="ts"> |
|||
import { notifyError } from '@/util/msg'; |
|||
import { Plus } from '@element-plus/icons-vue' |
|||
import { ref, computed } from "vue"; |
|||
|
|||
interface ProxyItem { |
|||
id: number; |
|||
port: string; |
|||
domain: string; |
|||
type: string; |
|||
name: string; |
|||
serverAddr: string; |
|||
serverPort: string; |
|||
} |
|||
const localKey = "godoos_net_proxy" |
|||
const getProxies = (): ProxyItem[] => { |
|||
const proxies = localStorage.getItem(localKey); |
|||
return proxies ? JSON.parse(proxies) : []; |
|||
}; |
|||
|
|||
const saveProxies = (proxies: ProxyItem[]) => { |
|||
localStorage.setItem(localKey, JSON.stringify(proxies)); |
|||
}; |
|||
|
|||
const proxies = ref<ProxyItem[]>(getProxies()); |
|||
const proxyData = ref<ProxyItem>({ |
|||
id: Date.now(), |
|||
type: "http", |
|||
name: "", |
|||
port: "", |
|||
domain: "", |
|||
serverAddr: "", |
|||
serverPort: "", |
|||
}); |
|||
const proxyDialogShow = ref(false); |
|||
const isEditing = ref(false); |
|||
const pwdRef = ref<any>(null); |
|||
const types = ref([ |
|||
{ label: 'HTTP', value: 'http' }, |
|||
{ label: '静态文件访问', value: 'file' }, |
|||
{ label: '点对点穿透', value: 'p2p' }, |
|||
{ label: 'SSH', value: 'ssh' }, |
|||
{ label: 'SOCKS5', value: 'socks5' }, |
|||
|
|||
]) |
|||
|
|||
const addProxy = () => { |
|||
if (pwdRef.value.validate()) { |
|||
const isNameDuplicate = proxies.value.some(p => p.name === proxyData.value.name); |
|||
if (isNameDuplicate) { |
|||
notifyError("代理名称已存在"); |
|||
return; |
|||
} |
|||
proxies.value.push({ ...proxyData.value }); |
|||
saveProxies(proxies.value); |
|||
proxyDialogShow.value = false; |
|||
proxyData.value = { id: Date.now(), port: "", domain: "", type: "http", name: "", serverAddr: "", serverPort: "" }; |
|||
} |
|||
}; |
|||
|
|||
const editProxy = (proxy: ProxyItem) => { |
|||
proxyData.value = { ...proxy }; |
|||
isEditing.value = true; |
|||
proxyDialogShow.value = true; |
|||
}; |
|||
|
|||
const updateProxy = () => { |
|||
if (pwdRef.value.validate()) { |
|||
const index = proxies.value.findIndex(p => p.id === proxyData.value.id); |
|||
if (index !== -1) { |
|||
const isNameDuplicate = proxies.value.some((p, i) => p.name === proxyData.value.name && i !== index); |
|||
if (isNameDuplicate) { |
|||
notifyError("代理名称已存在"); |
|||
return; |
|||
} |
|||
proxies.value[index] = { ...proxyData.value }; |
|||
saveProxies(proxies.value); |
|||
proxyDialogShow.value = false; |
|||
proxyData.value = { id: Date.now(), port: "", domain: "", type: "http", name: "", serverAddr: "", serverPort: "" }; |
|||
isEditing.value = false; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const deleteProxy = (id: number) => { |
|||
proxies.value = proxies.value.filter(p => p.id !== id); |
|||
saveProxies(proxies.value); |
|||
}; |
|||
|
|||
const saveProxy = () => { |
|||
pwdRef.value.validate((valid: boolean) => { |
|||
if (valid) { |
|||
if (isEditing.value) { |
|||
updateProxy(); |
|||
} else { |
|||
addProxy(); |
|||
} |
|||
} else { |
|||
console.log('表单验证失败'); |
|||
} |
|||
}); |
|||
}; |
|||
|
|||
const proxyRules = { |
|||
name: [ |
|||
{ required: true, message: '代理名称不能为空', trigger: 'blur' }, |
|||
{ min: 1, max: 20, message: '代理名称长度在 1 到 20 个字符', trigger: 'blur' }, |
|||
{ pattern: /^[a-zA-Z]+$/, message: '代理名称只能包含英文字符', trigger: 'blur' } |
|||
], |
|||
port: [ |
|||
{ required: true, message: '端口不能为空', trigger: 'blur' }, |
|||
{ pattern: /^(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{1,3}|[0-9])$/, message: '请输入有效的端口号(1-65535)', trigger: 'blur' } |
|||
], |
|||
domain: [ |
|||
{ required: true, message: '代理域名不能为空', trigger: 'blur' }, |
|||
{ pattern: /^(https?:\/\/)?(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}(:\d{1,5})?(\/[^\s]*)?$/, message: '请输入有效的域名格式', trigger: 'blur' } |
|||
], |
|||
serverAddr: [ |
|||
{ required: true, message: '服务器地址不能为空', trigger: 'blur' }, |
|||
{ pattern: /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/, message: '请输入有效的IP地址格式', trigger: 'blur' } |
|||
], |
|||
serverPort: [ |
|||
{ required: true, message: '服务器端口不能为空', trigger: 'blur' }, |
|||
{ pattern: /^(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{1,3}|[0-9])$/, message: '请输入有效的服务器端口号(1-65535)', trigger: 'blur' } |
|||
] |
|||
}; |
|||
|
|||
const pageSize = 10; |
|||
const currentPage = ref(1); |
|||
|
|||
const paginatedProxies = computed(() => { |
|||
const start = (currentPage.value - 1) * pageSize; |
|||
const end = start + pageSize; |
|||
return proxies.value.slice(start, end); |
|||
}); |
|||
|
|||
const totalPages = computed(() => Math.ceil(proxies.value.length / pageSize)); |
|||
|
|||
const nextPage = () => { |
|||
if (currentPage.value < totalPages.value) { |
|||
currentPage.value++; |
|||
} |
|||
}; |
|||
|
|||
const prevPage = () => { |
|||
if (currentPage.value > 1) { |
|||
currentPage.value--; |
|||
} |
|||
}; |
|||
</script> |
|||
<template> |
|||
<div> |
|||
<el-row justify="end"> |
|||
<el-button type="primary" :icon="Plus" circle @click="proxyDialogShow = true" /> |
|||
</el-row> |
|||
<el-table :data="paginatedProxies" style="width: 98%;border:none"> |
|||
<el-table-column prop="name" label="名称" width="100" /> |
|||
<el-table-column prop="type" label="类型" width="80" /> |
|||
<el-table-column prop="port" label="本地端口" width="80" /> |
|||
<el-table-column prop="domain" label="代理域名" width="180" /> |
|||
<el-table-column label="操作"> |
|||
<template #default="scope"> |
|||
<el-button size="small" @click="editProxy(scope.row)">编辑</el-button> |
|||
<el-button size="small" type="danger" @click="deleteProxy(scope.row.id)">删除</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<el-pagination v-if="totalPages > 1" layout="prev, pager, next" :total="getProxies().length" |
|||
:page-size="pageSize" v-model:current-page="currentPage" @next-click="nextPage" @prev-click="prevPage" /> |
|||
<el-dialog v-model="proxyDialogShow" :title="isEditing ? '编辑代理' : '添加代理'" width="400px"> |
|||
<span> |
|||
<el-form :model="proxyData" :rules="proxyRules" ref="pwdRef"> |
|||
<el-form-item label="代理类型" prop="type"> |
|||
<el-select v-model="proxyData.type" placeholder="代理类型"> |
|||
<el-option v-for="type in types" :key="type.value" :label="type.label" |
|||
:value="type.value" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="代理名称" prop="name"> |
|||
<el-input v-model="proxyData.name" /> |
|||
</el-form-item> |
|||
|
|||
<el-form-item label="本地端口" prop="port"> |
|||
<el-input v-model="proxyData.port" /> |
|||
</el-form-item> |
|||
<el-form-item label="代理域名" prop="domain"> |
|||
<el-input v-model="proxyData.domain" /> |
|||
</el-form-item> |
|||
<el-form-item label="服务器地址" prop="serverAddr"> |
|||
<el-input v-model="proxyData.serverAddr" /> |
|||
</el-form-item> |
|||
<el-form-item label="服务器端口" prop="serverPort"> |
|||
<el-input v-model="proxyData.serverPort" /> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button type="primary" @click="saveProxy" style="margin: 0 auto;"> |
|||
确认 |
|||
</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</span> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
@ -0,0 +1,182 @@ |
|||
import { defineStore } from 'pinia'; |
|||
import { ref } from 'vue'; |
|||
|
|||
export interface ProxyItem { |
|||
port: string; |
|||
domain: string; |
|||
type: string; |
|||
name: string; |
|||
serverAddr: string; |
|||
serverPort: string; |
|||
httpAuth: boolean; |
|||
authUsername: string; |
|||
authPassword: string; |
|||
https2http: boolean; |
|||
https2httpCaFile: string; |
|||
https2httpKeyFile: string; |
|||
remotePort?: string; |
|||
stcpModel?: string; |
|||
secretKey?: string; |
|||
visitedName?: string; |
|||
bindAddr?: string; |
|||
bindPort?: string; |
|||
fallbackTo?: string; |
|||
fallbackTimeoutMs?: number; |
|||
keepAlive?: boolean; |
|||
} |
|||
|
|||
export const useProxyStore = defineStore('proxyStore', () => { |
|||
const localKey = "godoos_net_proxy"; |
|||
|
|||
const proxies = ref<ProxyItem[]>(getProxies()); |
|||
const customDomains = ref<string[]>([""]); |
|||
const proxyData = ref<ProxyItem>(createNewProxyData()); |
|||
|
|||
function createNewProxyData(): ProxyItem { |
|||
return { |
|||
type: "http", |
|||
name: "", |
|||
port: "", |
|||
domain: "", |
|||
serverAddr: "", |
|||
serverPort: "", |
|||
httpAuth: false, |
|||
authUsername: "", |
|||
authPassword: "", |
|||
https2http: false, |
|||
https2httpCaFile: "", |
|||
https2httpKeyFile: "", |
|||
remotePort: "", |
|||
stcpModel: "", |
|||
secretKey: "", |
|||
visitedName: "", |
|||
bindAddr: "", |
|||
bindPort: "", |
|||
fallbackTo: "", |
|||
fallbackTimeoutMs: 0, |
|||
keepAlive: false, |
|||
}; |
|||
} |
|||
|
|||
function getProxies(): ProxyItem[] { |
|||
const proxies = localStorage.getItem(localKey); |
|||
return proxies ? JSON.parse(proxies) : []; |
|||
} |
|||
|
|||
function saveProxies(proxies: ProxyItem[]) { |
|||
localStorage.setItem(localKey, JSON.stringify(proxies)); |
|||
} |
|||
|
|||
const addProxy = (proxy: ProxyItem) => { |
|||
proxies.value.push(proxy); |
|||
saveProxies(proxies.value); |
|||
}; |
|||
|
|||
const updateProxy = (updatedProxy: ProxyItem) => { |
|||
const index = proxies.value.findIndex(p => p.id === updatedProxy.id); |
|||
if (index !== -1) { |
|||
proxies.value[index] = updatedProxy; |
|||
saveProxies(proxies.value); |
|||
} |
|||
}; |
|||
|
|||
const deleteProxy = (id: number) => { |
|||
proxies.value = proxies.value.filter(p => p.id !== id); |
|||
saveProxies(proxies.value); |
|||
}; |
|||
|
|||
const addCustomDomain = () => { |
|||
customDomains.value.push(""); |
|||
}; |
|||
|
|||
const removeCustomDomain = (index: number) => { |
|||
if (customDomains.value.length > 1) { |
|||
customDomains.value.splice(index, 1); |
|||
} |
|||
}; |
|||
|
|||
const resetProxyData = () => { |
|||
proxyData.value = createNewProxyData(); |
|||
}; |
|||
|
|||
const createFrpcConfig = async () => { |
|||
const url = "http://localhost:56780/frpc/create"; |
|||
const requestData = { |
|||
config: { |
|||
ServerAddr: proxyData.value.serverAddr, |
|||
ServerPort: Number(proxyData.value.serverPort), |
|||
AuthMethod: "token", |
|||
AuthToken: "your-auth-token", |
|||
User: "your-username", |
|||
MetaToken: "your-meta-token", |
|||
TransportHeartbeatInterval: 30, |
|||
TransportHeartbeatTimeout: 90, |
|||
LogLevel: "info", |
|||
LogMaxDays: 3, |
|||
WebPort: 7500, |
|||
TlsConfigEnable: true, |
|||
TlsConfigCertFile: "/path/to/cert/file", |
|||
TlsConfigKeyFile: "/path/to/key/file", |
|||
TlsConfigTrustedCaFile: "/path/to/ca/file", |
|||
TlsConfigServerName: "server-name", |
|||
ProxyConfigEnable: true, |
|||
ProxyConfigProxyUrl: "http://proxy.example.com" |
|||
}, |
|||
proxies: [ |
|||
{ |
|||
Name: proxyData.value.name, |
|||
Type: proxyData.value.type, |
|||
LocalIp: proxyData.value.serverAddr, |
|||
LocalPort: Number(proxyData.value.port), |
|||
RemotePort: Number(proxyData.value.remotePort), |
|||
CustomDomains: customDomains.value, |
|||
Subdomain: proxyData.value.domain, |
|||
BasicAuth: proxyData.value.httpAuth, |
|||
HttpUser: proxyData.value.authUsername, |
|||
HttpPassword: proxyData.value.authPassword, |
|||
StcpModel: proxyData.value.stcpModel, |
|||
ServerName: "server1", |
|||
BindAddr: proxyData.value.bindAddr, |
|||
BindPort: Number(proxyData.value.bindPort), |
|||
FallbackTo: proxyData.value.fallbackTo, |
|||
FallbackTimeoutMs: Number(proxyData.value.fallbackTimeoutMs), |
|||
SecretKey: proxyData.value.secretKey |
|||
} |
|||
] |
|||
}; |
|||
|
|||
try { |
|||
const response = await fetch(url, { |
|||
method: "POST", |
|||
headers: { |
|||
"Content-Type": "application/json" |
|||
}, |
|||
body: JSON.stringify(requestData) |
|||
}); |
|||
|
|||
if (!response.ok) { |
|||
throw new Error(`HTTP error! status: ${response.status}`); |
|||
} |
|||
|
|||
const data = await response.json(); |
|||
console.log("Response data:", data); |
|||
// 可以在这里添加成功通知
|
|||
} catch (error) { |
|||
console.error("Error:", error); |
|||
// 可以在这里添加错误通知
|
|||
} |
|||
}; |
|||
|
|||
return { |
|||
proxies, |
|||
customDomains, |
|||
proxyData, |
|||
addProxy, |
|||
updateProxy, |
|||
deleteProxy, |
|||
addCustomDomain, |
|||
removeCustomDomain, |
|||
resetProxyData, |
|||
createFrpcConfig, |
|||
}; |
|||
}); |
Loading…
Reference in new issue