增加快捷选择本地端口

This commit is contained in:
刘嘉伟 2024-08-11 18:19:45 +08:00
parent 80d0b53759
commit ef1b8c186e
4 changed files with 159 additions and 12 deletions

70
electron/api/local.ts Normal file
View File

@ -0,0 +1,70 @@
import {ipcMain} from "electron";
import log from "electron-log";
const {exec, spawn} = require("child_process");
type LocalPort = {
protocol: string;
ip: string;
port: number;
}
export const initLocalApi = () => {
const command = process.platform === 'win32'
? 'netstat -a -n'
: 'netstat -tuln';
ipcMain.on("local.getLocalPorts", async (event, args) => {
log.info("开始获取本地端口")
// 执行命令
exec(command, (error, stdout, stderr) => {
if (error) {
log.error(`getLocalPorts - error ${error.message}`)
return;
}
if (stderr) {
log.error(`getLocalPorts - stderr ${stderr}`)
return;
}
log.debug(`sc ${stdout}`)
let ports = [];
if (stdout) {
ports = stdout.split('\r\n')
.filter(f => f.indexOf('TCP') > 0 || f.indexOf('UDP') > 0)
.map(m => {
const cols = m.split(' ')
.filter(f => f != '')
const local = cols[1]
const s = local.lastIndexOf(":")
let localIP = local.slice(0, s);
let localPort = local.slice(s - local.length + 1);
console.log(1)
// if (local.indexOf('[') == -1) {
// // ipv4
// const tmp = cols[1].split(":")
// localIP = tmp[0]
// localPort = tmp[1]
// } else {
// // ipv6
// console.log(1)
// }
const singe: LocalPort = {
protocol: cols[0],
ip: localIP,
port: localPort
}
return singe;
})
}
ports.sort((a, b) => a.port - b.port);
event.reply("local.getLocalPorts.hook", {
data: ports
});
});
});
}

View File

@ -7,10 +7,10 @@ import {initProxyApi} from "../api/proxy";
import {initFrpcApi, startFrpWorkerProcess, stopFrpcProcess} from "../api/frpc";
import {initLoggerApi} from "../api/logger";
import {initFileApi} from "../api/file";
import {initUpdaterApi} from "../api/update";
import {getConfig} from "../storage/config";
import log from "electron-log";
import {initCommonApi} from "../api/common";
import {initLocalApi} from "../api/local";
// The built directory structure
//
// ├─┬ dist-electron
@ -172,6 +172,7 @@ app.whenReady().then(() => {
initLoggerApi();
initFileApi();
initCommonApi();
initLocalApi();
// initUpdaterApi(win);
})
});

View File

@ -814,20 +814,22 @@ onUnmounted(() => {
</div>
</div>
<el-dialog v-model="visibles.copyServerConfig" title="复制链接" width="500">
<el-dialog v-model="visibles.copyServerConfig" title="复制链接" width="500" top="5%">
<el-alert class="mb-4" title="生成内容包含服务器密钥等内容 请妥善保管 且链接仅在Frpc-Desktop中可用" type="warning"
:closable="false"/>
<el-input class="h-30" v-model="copyServerConfigBase64" type="textarea" :rows="8"></el-input>
</el-dialog>
<el-dialog v-model="visibles.pasteServerConfig" title="导入链接" width="500">
<el-dialog v-model="visibles.pasteServerConfig" title="导入链接" width="500" top="5%">
<el-input class="h-30"
v-model="pasteServerConfigBase64"
type="textarea" placeholder="frp://......"
:rows="8"></el-input>
<template #footer>
<div class="dialog-footer">
<el-button plain type="primary" @click="handlePasteServerConfigBase64">导入</el-button>
<el-button plain type="primary" @click="handlePasteServerConfigBase64">
<Icon class="cursor-pointer mr-2" icon="material-symbols:label-important-rounded"/> </el-button>
</div>
</template>

View File

@ -5,6 +5,7 @@ import Breadcrumb from "@/layout/compoenets/Breadcrumb.vue";
import {ElMessage, FormInstance, FormRules} from "element-plus";
import {ipcRenderer} from "electron";
import {clone} from "@/utils/clone";
import {useDebounceFn} from "@vueuse/core";
defineComponent({
name: "Proxy"
@ -20,6 +21,12 @@ type Proxy = {
customDomains: string[];
};
type LocalPort = {
protocol: string;
ip: string;
port: number;
}
/**
* 代理列表
*/
@ -29,9 +36,13 @@ const proxys = ref<Array<Proxy>>([]);
*/
const loading = ref({
list: 1,
form: 0
form: 0,
localPorts: 1
});
const localPorts = ref<Array<LocalPort>>([]);
const listPortsVisible = ref(false);
/**
* 弹出层属性
*/
@ -170,6 +181,12 @@ const handleInitHook = () => {
ipcRenderer.on("Proxy.updateProxy.hook", (event, args) => {
InsertOrUpdateHook("修改成功", args);
});
ipcRenderer.on("local.getLocalPorts.hook", (event, args) => {
loading.value.localPorts--;
localPorts.value = args.data;
console.log('本地端口', localPorts.value)
})
// ipcRenderer.on("Proxy.updateProxy.hook", (event, args) => {
// loading.value.form--;
// const { err } = args;
@ -216,6 +233,26 @@ const handleOpenUpdate = (proxy: Proxy) => {
};
};
const handleLoadLocalPorts = () => {
loading.value.localPorts = 1;
ipcRenderer.send("local.getLocalPorts")
}
const handleSelectLocalPort = useDebounceFn((port: number) => {
editForm.value.localPort = port;
handleCloseLocalPortDialog();
})
const handleCloseLocalPortDialog = () => {
listPortsVisible.value = false;
}
const handleOpenLocalPortDialog = () => {
listPortsVisible.value = true;
handleLoadLocalPorts();
};
onMounted(() => {
handleInitHook();
handleLoadProxys();
@ -226,6 +263,7 @@ onUnmounted(() => {
ipcRenderer.removeAllListeners("Proxy.updateProxy.hook");
ipcRenderer.removeAllListeners("Proxy.deleteProxyById.hook");
ipcRenderer.removeAllListeners("Proxy.getProxys.hook");
ipcRenderer.removeAllListeners("local.getLocalPorts.hook");
});
</script>
<template>
@ -330,8 +368,8 @@ onUnmounted(() => {
<el-dialog
v-model="edit.visible"
:title="edit.title"
class="w-[400px]"
top="30px"
width="400"
top="5%"
>
<el-form
v-loading="loading.form"
@ -357,21 +395,25 @@ onUnmounted(() => {
<el-input v-model="editForm.name" placeholder="代理名称"/>
</el-form-item>
</el-col>
<el-col :span="16">
<el-col :span="24">
<el-form-item label="内网地址:" prop="localIp">
<el-input v-model="editForm.localIp" placeholder="127.0.0.1"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-col :span="24">
<el-form-item label="内网端口:" prop="localPort">
<el-input-number
placeholder="8080"
class="!w-full"
class="local-port-input"
:min="0"
:max="65535"
v-model="editForm.localPort"
controls-position="right"
/>
<el-button class="ml-[10px]" plain type="primary" @click="handleOpenLocalPortDialog">
<Icon class="cursor-pointer mr-2" icon="material-symbols:bring-your-own-ip-rounded"/>
本地端口
</el-button>
</el-form-item>
</el-col>
<template v-if="editForm.type === 'tcp' || editForm.type === 'udp'">
@ -443,9 +485,12 @@ onUnmounted(() => {
<el-col :span="24">
<el-form-item>
<div class="w-full flex justify-end">
<el-button @click="edit.visible = false"> </el-button>
<el-button @click="edit.visible = false">
<Icon class="cursor-pointer mr-2" icon="material-symbols:cancel-presentation"/>
</el-button>
<el-button plain type="primary" @click="handleSubmit"
>
><Icon class="cursor-pointer mr-2" icon="material-symbols:save-rounded"/>
</el-button>
</div>
</el-form-item>
@ -453,6 +498,31 @@ onUnmounted(() => {
</el-row>
</el-form>
</el-dialog>
<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"/>
<el-table-column label="操作" :width="80">
<template #default="scope">
<el-button type="text" @click="handleSelectLocalPort(scope.row.port)">
<Icon class="cursor-pointer mr-2" icon="material-symbols:gesture-select"/>
选择
</el-button>
</template>
</el-table-column>
</el-table>
<!-- <div class="h-[400px] overflow-y-scroll">-->
<!-- -->
<!-- </div>-->
</el-dialog>
</div>
</template>
@ -477,6 +547,10 @@ onUnmounted(() => {
width: calc(100% - 115px);
}
.local-port-input {
width: calc(100% - 120px);
}
.domain-input-button {
background: #5f3bb0;
display: flex;