🔍 防止重复提交

This commit is contained in:
刘嘉伟 2024-08-05 22:30:53 +08:00
parent c0519e7a5a
commit d6fc767077
3 changed files with 234 additions and 32 deletions

View File

@ -1,7 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import {defineComponent, onMounted, onUnmounted, reactive, ref} from "vue"; import {defineComponent, onMounted, onUnmounted, reactive, ref} from "vue";
import {ipcRenderer} from "electron"; import {ipcRenderer} from "electron";
import {ElMessage, FormInstance, FormRules} from "element-plus"; import {ElMessage, ElMessageBox, FormInstance, FormRules} from "element-plus";
import Breadcrumb from "@/layout/compoenets/Breadcrumb.vue"; import Breadcrumb from "@/layout/compoenets/Breadcrumb.vue";
import {useDebounceFn} from "@vueuse/core"; import {useDebounceFn} from "@vueuse/core";
import {clone} from "@/utils/clone"; import {clone} from "@/utils/clone";
@ -79,15 +79,15 @@ const rules = reactive<FormRules>({
metaToken: [ metaToken: [
{required: true, message: "请输入多用户令牌", trigger: "blur"} {required: true, message: "请输入多用户令牌", trigger: "blur"}
], ],
authMethod: [{ required: true, message: "请选择验证方式", trigger: "blur" }], authMethod: [{required: true, message: "请选择验证方式", trigger: "blur"}],
authToken: [{required: true, message: "请输入token值 ", trigger: "blur"}], authToken: [{required: true, message: "请输入 Token 值 ", trigger: "blur"}],
logLevel: [{required: true, message: "请选择日志级别 ", trigger: "blur"}], logLevel: [{required: true, message: "请选择日志级别 ", trigger: "blur"}],
logMaxDays: [{required: true, message: "请输入日志保留天数 ", trigger: "blur"}], logMaxDays: [{required: true, message: "请输入日志保留天数 ", trigger: "blur"}],
tlsConfigEnable: [{required: true, message: "请选择TLS状态", trigger: "change"}], tlsConfigEnable: [{required: true, message: "请选择 TLS 状态", trigger: "change"}],
tlsConfigCertFile: [{required: true, message: "请选择TLS证书文件", trigger: "change"}], tlsConfigCertFile: [{required: true, message: "请选择 TLS 证书文件", trigger: "change"}],
tlsConfigKeyFile: [{required: true, message: "请选择TLS密钥文件", trigger: "change"}], tlsConfigKeyFile: [{required: true, message: "请选择 TLS 密钥文件", trigger: "change"}],
tlsConfigTrustedCaFile: [{required: true, message: "请选择CA证书文件", trigger: "change"}], tlsConfigTrustedCaFile: [{required: true, message: "请选择 CA 证书文件", trigger: "change"}],
tlsConfigServerName: [{required: true, message: "请输入TLS Server名称", trigger: "blur"}], tlsConfigServerName: [{required: true, message: "请输入 TLS Server 名称", trigger: "blur"}],
proxyConfigEnable: [{required: true, message: "请选择代理状态", trigger: "change"}], proxyConfigEnable: [{required: true, message: "请选择代理状态", trigger: "change"}],
proxyConfigProxyUrl: [ proxyConfigProxyUrl: [
{required: true, message: "请输入代理地址", trigger: "change"}, {required: true, message: "请输入代理地址", trigger: "change"},
@ -120,6 +120,17 @@ const handleLoadVersions = () => {
ipcRenderer.send("config.versions"); ipcRenderer.send("config.versions");
}; };
const handleAuthMethodChange = e => {
if (e === 'multiuser') {
ElMessageBox.alert("多用户插件需要 Frp版本 >= <span class=\"font-black text-[#5A3DAA]\">v0.31.0</span> 请自行选择正确版本", "提示", {
// if you want to disable its autofocus
autofocus: false,
confirmButtonText: "知道了",
dangerouslyUseHTMLString: true,
})
}
}
onMounted(() => { onMounted(() => {
ipcRenderer.send("config.getConfig"); ipcRenderer.send("config.getConfig");
handleLoadVersions(); handleLoadVersions();
@ -184,7 +195,7 @@ onUnmounted(() => {
:rules="rules" :rules="rules"
label-position="right" label-position="right"
ref="formRef" ref="formRef"
label-width="140" label-width="130"
> >
<el-row :gutter="10"> <el-row :gutter="10">
<el-col :span="24"> <el-col :span="24">
@ -229,6 +240,23 @@ onUnmounted(() => {
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="服务器地址:" prop="serverAddr"> <el-form-item label="服务器地址:" prop="serverAddr">
<template #label>
<div class="h-full flex items-center mr-1">
<el-popover
placement="top"
trigger="hover"
>
<template #default>
Frps服务端地址 <br/> 支持 <span class="font-black text-[#5A3DAA]">域名</span><span
class="font-black text-[#5A3DAA]">IP</span>
</template>
<template #reference>
<Icon class="text-base" color="#5A3DAA" icon="material-symbols:info"/>
</template>
</el-popover>
</div>
服务器地址
</template>
<el-input <el-input
v-model="formData.serverAddr" v-model="formData.serverAddr"
placeholder="127.0.0.1" placeholder="127.0.0.1"
@ -249,17 +277,53 @@ onUnmounted(() => {
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="验证方式:" prop="authMethod"> <el-form-item label="验证方式:" prop="authMethod">
<template #label>
<div class="h-full flex items-center mr-1">
<el-popover
width="200"
placement="top"
trigger="hover"
>
<template #default>
对应参数<span class="font-black text-[#5A3DAA]">auth.method</span>
</template>
<template #reference>
<Icon class="text-base" color="#5A3DAA" icon="material-symbols:info"/>
</template>
</el-popover>
</div>
验证方式
</template>
<el-select <el-select
v-model="formData.authMethod" v-model="formData.authMethod"
placeholder="请选择验证方式" placeholder="请选择验证方式"
@change="handleAuthMethodChange"
clearable clearable
> >
<el-option label="token" value="token"></el-option> <el-option label="令牌token" value="token"></el-option>
<el-option label="多用户" value="multiuser"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24" v-if="formData.authMethod === 'token'"> <el-col :span="24" v-if="formData.authMethod === 'token'">
<el-form-item label="token" prop="authToken"> <el-form-item label="令牌:" prop="authToken">
<template #label>
<div class="h-full flex items-center mr-1">
<el-popover
placement="top"
trigger="hover"
width="200"
>
<template #default>
对应参数<span class="font-black text-[#5A3DAA]">auth.token</span>
</template>
<template #reference>
<Icon class="text-base" color="#5A3DAA" icon="material-symbols:info"/>
</template>
</el-popover>
</div>
令牌
</template>
<el-input <el-input
placeholder="token" placeholder="token"
type="password" type="password"
@ -267,6 +331,56 @@ onUnmounted(() => {
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12" v-if="formData.authMethod === 'multiuser'">
<el-form-item label="用户:" prop="user">
<template #label>
<div class="h-full flex items-center mr-1">
<el-popover
placement="top"
trigger="hover"
>
<template #default>
对应参数<span class="font-black text-[#5A3DAA]">user</span>
</template>
<template #reference>
<Icon class="text-base" color="#5A3DAA" icon="material-symbols:info"/>
</template>
</el-popover>
</div>
用户
</template>
<el-input
placeholder="请输入用户"
v-model="formData.user"
/>
</el-form-item>
</el-col>
<el-col :span="12" v-if="formData.authMethod === 'multiuser'">
<el-form-item label="用户令牌:" prop="metaToken">
<template #label>
<div class="h-full flex items-center mr-1">
<el-popover
width="200"
placement="top"
trigger="hover"
>
<template #default>
对应参数<span class="font-black text-[#5A3DAA]">meta_token</span>
</template>
<template #reference>
<Icon class="text-base" color="#5A3DAA" icon="material-symbols:info"/>
</template>
</el-popover>
</div>
用户令牌
</template>
<el-input
placeholder="请输入用户令牌"
type="password"
v-model="formData.metaToken"
/>
</el-form-item>
</el-col>
<el-col :span="24"> <el-col :span="24">
<div class="h2">TSL Config</div> <div class="h2">TSL Config</div>
</el-col> </el-col>
@ -280,7 +394,24 @@ onUnmounted(() => {
</el-col> </el-col>
<template v-if="formData.tlsConfigEnable"> <template v-if="formData.tlsConfigEnable">
<el-col :span="24"> <el-col :span="24">
<el-form-item label="TLS证书文件" prop="tlsConfigCertFile"> <el-form-item label="TLS证书文件" prop="tlsConfigCertFile" label-width="180">
<template #label>
<div class="h-full flex items-center mr-1">
<el-popover
width="260"
placement="top"
trigger="hover"
>
<template #default>
对应参数<span class="font-black text-[#5A3DAA]">transport.tls.certFile</span>
</template>
<template #reference>
<Icon class="text-base" color="#5A3DAA" icon="material-symbols:info"/>
</template>
</el-popover>
</div>
TLS 证书文件
</template>
<el-input <el-input
class="button-input" class="button-input"
v-model="formData.tlsConfigCertFile" v-model="formData.tlsConfigCertFile"
@ -291,18 +422,52 @@ onUnmounted(() => {
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="TLS密钥文件" prop="tlsConfigKeyFile"> <el-form-item label="TLS密钥文件" prop="tlsConfigKeyFile" label-width="180">
<template #label>
<div class="h-full flex items-center mr-1">
<el-popover
width="260"
placement="top"
trigger="hover"
>
<template #default>
对应参数<span class="font-black text-[#5A3DAA]">transport.tls.keyFile</span>
</template>
<template #reference>
<Icon class="text-base" color="#5A3DAA" icon="material-symbols:info"/>
</template>
</el-popover>
</div>
TLS 密钥文件
</template>
<el-input <el-input
class="button-input" class="button-input"
v-model="formData.tlsConfigKeyFile" v-model="formData.tlsConfigKeyFile"
placeholder="请选择TLS密钥文件" placeholder="请选择 TLS 密钥文件"
readonly readonly
/> />
<el-button class="ml-2" type="primary" @click="handleSelectFile(2, ['key'])">选择</el-button> <el-button class="ml-2" type="primary" @click="handleSelectFile(2, ['key'])">选择</el-button>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="CA证书文件" prop="tlsConfigTrustedCaFile"> <el-form-item label="CA证书文件" prop="tlsConfigTrustedCaFile" label-width="180">
<template #label>
<div class="h-full flex items-center mr-1">
<el-popover
width="310"
placement="top"
trigger="hover"
>
<template #default>
对应参数<span class="font-black text-[#5A3DAA]">transport.tls.trustedCaFile</span>
</template>
<template #reference>
<Icon class="text-base" color="#5A3DAA" icon="material-symbols:info"/>
</template>
</el-popover>
</div>
CA 证书文件
</template>
<el-input <el-input
class="button-input" class="button-input"
v-model="formData.tlsConfigTrustedCaFile" v-model="formData.tlsConfigTrustedCaFile"
@ -313,10 +478,27 @@ onUnmounted(() => {
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="TLS Server名称" prop="tlsConfigServerName"> <el-form-item label="TLS Server 名称:" prop="tlsConfigServerName" label-width="180">
<template #label>
<div class="h-full flex items-center mr-1">
<el-popover
width="300"
placement="top"
trigger="hover"
>
<template #default>
对应参数<span class="font-black text-[#5A3DAA]">transport.tls.serverName</span>
</template>
<template #reference>
<Icon class="text-base" color="#5A3DAA" icon="material-symbols:info"/>
</template>
</el-popover>
</div>
TLS Server 名称
</template>
<el-input <el-input
v-model="formData.tlsConfigServerName" v-model="formData.tlsConfigServerName"
placeholder="请输入TLS Server名称" placeholder="请输入TLS Server 名称"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -335,6 +517,23 @@ onUnmounted(() => {
<template v-if="formData.proxyConfigEnable"> <template v-if="formData.proxyConfigEnable">
<el-col :span="24"> <el-col :span="24">
<el-form-item label="代理地址:" prop="proxyConfigProxyUrl"> <el-form-item label="代理地址:" prop="proxyConfigProxyUrl">
<template #label>
<div class="h-full flex items-center mr-1">
<el-popover
width="300"
placement="top"
trigger="hover"
>
<template #default>
对应参数<span class="font-black text-[#5A3DAA]">transport.proxyURL</span>
</template>
<template #reference>
<Icon class="text-base" color="#5A3DAA" icon="material-symbols:info"/>
</template>
</el-popover>
</div>
代理地址
</template>
<el-input v-model="formData.proxyConfigProxyUrl" <el-input v-model="formData.proxyConfigProxyUrl"
placeholder="http://user:pwd@192.168.1.128:8080"/> placeholder="http://user:pwd@192.168.1.128:8080"/>
</el-form-item> </el-form-item>

View File

@ -5,6 +5,7 @@ import moment from "moment";
import Breadcrumb from "@/layout/compoenets/Breadcrumb.vue"; import Breadcrumb from "@/layout/compoenets/Breadcrumb.vue";
import {Icon} from "@iconify/vue"; import {Icon} from "@iconify/vue";
import {ElMessage} from "element-plus"; import {ElMessage} from "element-plus";
import {useDebounceFn} from "@vueuse/core";
defineComponent({ defineComponent({
name: "Download" name: "Download"
@ -39,21 +40,21 @@ const handleLoadVersions = () => {
* 下载 * 下载
* @param version * @param version
*/ */
const handleDownload = (version: Version) => { const handleDownload = useDebounceFn((version: Version) => {
ipcRenderer.send("github.download", version.id); ipcRenderer.send("github.download", version.id);
downloading.value.set(version.id, 0); downloading.value.set(version.id, 0);
}; }, 300);
/** /**
* 删除下载 * 删除下载
* @param version * @param version
*/ */
const handleDeleteVersion = (version: Version) => { const handleDeleteVersion = useDebounceFn((version: Version) => {
ipcRenderer.send("github.deleteVersion", { ipcRenderer.send("github.deleteVersion", {
id: version.id, id: version.id,
absPath: version.absPath absPath: version.absPath
}); });
} }, 300);
const handleInitDownloadHook = () => { const handleInitDownloadHook = () => {
ipcRenderer.on("Download.frpVersionHook", (event, args) => { ipcRenderer.on("Download.frpVersionHook", (event, args) => {

View File

@ -5,6 +5,7 @@ import {ipcRenderer} from "electron";
import {Icon} from "@iconify/vue"; import {Icon} from "@iconify/vue";
import {ElMessageBox} from "element-plus"; import {ElMessageBox} from "element-plus";
import router from "@/router"; import router from "@/router";
import {useDebounceFn} from "@vueuse/core";
defineComponent({ defineComponent({
name: "Home" name: "Home"
@ -20,13 +21,13 @@ const handleStopFrpc = () => {
ipcRenderer.send("frpc.stop"); ipcRenderer.send("frpc.stop");
}; };
const handleButtonClick = () => { const handleButtonClick = useDebounceFn(() => {
if (running.value) { if (running.value) {
handleStopFrpc(); handleStopFrpc();
} else { } else {
handleStartFrpc(); handleStartFrpc();
} }
}; }, 300);
onMounted(() => { onMounted(() => {
setInterval(() => { setInterval(() => {
@ -95,18 +96,19 @@ onUnmounted(() => {
<div class="pl-8 h-28 w-52 flex flex-col justify-between"> <div class="pl-8 h-28 w-52 flex flex-col justify-between">
<transition name="fade"> <transition name="fade">
<div class="font-bold text-2xl text-center"> <div class="font-bold text-2xl text-center">
<Icon v-if="running" class="text-[#7EC050] inline-block relative top-1" icon="material-symbols:check-circle-rounded" /> <Icon v-if="running" class="text-[#7EC050] inline-block relative top-1"
<Icon v-else class="text-[#E47470] inline-block relative top-1" icon="material-symbols:error" /> icon="material-symbols:check-circle-rounded"/>
<Icon v-else class="text-[#E47470] inline-block relative top-1" icon="material-symbols:error"/>
Frpc {{ running ? "已启动" : "已断开" }} Frpc {{ running ? "已启动" : "已断开" }}
</div> </div>
</transition> </transition>
<!-- <el-button--> <!-- <el-button-->
<!-- class="block"--> <!-- class="block"-->
<!-- type="text"--> <!-- type="text"-->
<!-- v-if="running"--> <!-- v-if="running"-->
<!-- @click="$router.replace({ name: 'Logger' })"--> <!-- @click="$router.replace({ name: 'Logger' })"-->
<!-- >查看日志--> <!-- >查看日志-->
<!-- </el-button>--> <!-- </el-button>-->
<div class="w-full justify-center text-center"> <div class="w-full justify-center text-center">
<el-link v-if="running" type="primary" @click="$router.replace({ name: 'Logger' })">查看日志</el-link> <el-link v-if="running" type="primary" @click="$router.replace({ name: 'Logger' })">查看日志</el-link>
</div> </div>