配置导出

This commit is contained in:
刘嘉伟 2024-08-21 22:31:12 +08:00
parent 6e028d377a
commit 9fed5fc844
8 changed files with 213 additions and 86 deletions

View File

@ -1,18 +1,23 @@
import {app, ipcMain} from "electron";
import {getConfig, saveConfig} from "../storage/config";
import {listVersion} from "../storage/version";
import { app, dialog, ipcMain } from "electron";
import { getConfig, saveConfig } from "../storage/config";
import { listVersion } from "../storage/version";
import { generateConfig, genIniConfig, genTomlConfig } from "./frpc";
import { exec } from "child_process";
import { listProxy } from "../storage/proxy";
import path from "path";
import fs from "fs";
const log = require('electron-log');
const log = require("electron-log");
export const initConfigApi = () => {
ipcMain.on("config.saveConfig", async (event, args) => {
saveConfig(args, (err, numberOfUpdated, upsert) => {
if (!err) {
const start = args.systemSelfStart || false;
log.info("开启自启状态", start)
log.info("开启自启状态", start);
app.setLoginItemSettings({
openAtLogin: start, //win
openAsHidden: start, //macOs
openAsHidden: start //macOs
});
}
event.reply("Config.saveConfig.hook", {
@ -49,4 +54,49 @@ export const initConfigApi = () => {
});
});
});
ipcMain.on("config.exportConfig", async (event, args) => {
const result = await dialog.showOpenDialog({
properties: ["openDirectory"]
});
const outputDirectory = result.filePaths[0];
log.info(`导出目录 ${outputDirectory} 类型:${args}`);
getConfig((err1, config) => {
if (!err1 && config) {
listProxy((err2, proxys) => {
if (!err2) {
let configContent = "";
if (args === "ini") {
configContent = genIniConfig(config, proxys);
} else if (args === "toml") {
configContent = genTomlConfig(config, proxys);
}
const configPath = path.join(
outputDirectory,
`frpc-desktop.${args}`
);
fs.writeFile(
configPath, // 配置文件目录
configContent, // 配置文件内容
{ flag: "w" },
err => {
if (!err) {
// callback(filename);
event.reply("config.exportConfig.hook", {
data: "导出错误",
err: err
});
}
}
);
event.reply("Config.exportConfig.hook", {
data: {
configPath: configPath
}
});
}
});
}
});
});
};

View File

@ -38,7 +38,7 @@ const getFrpcVersionWorkerPath = (
* @param config
* @param proxys
*/
const genTomlConfig = (config: FrpConfig, proxys: Proxy[]) => {
export const genTomlConfig = (config: FrpConfig, proxys: Proxy[]) => {
const proxyToml = proxys.map(m => {
let toml = `
[[${m.type === "stcp" && m.stcpModel === "visitors" ? "visitors" : "proxies"}]]
@ -155,7 +155,7 @@ ${proxyToml.join("")}
* @param config
* @param proxys
*/
const genIniConfig = (config: FrpConfig, proxys: Proxy[]) => {
export const genIniConfig = (config: FrpConfig, proxys: Proxy[]) => {
const proxyIni = proxys.map(m => {
let ini = `
[${m.name}]

View File

@ -29,6 +29,9 @@ import ContentCopy from "@iconify-icons/material-symbols/content-copy";
import ContentPasteGo from "@iconify-icons/material-symbols/content-paste-go";
import Edit from "@iconify-icons/material-symbols/edit";
import CheckBox from "@iconify-icons/material-symbols/check-box";
import ExportNotesOutline from "@iconify-icons/material-symbols/export-notes-outline";
import uploadRounded from "@iconify-icons/material-symbols/upload-rounded";
import downloadRounded from "@iconify-icons/material-symbols/download-rounded";
addIcon("cloud", Cloud);
addIcon("rocket-launch-rounded", RocketLaunchRounded);
@ -53,4 +56,8 @@ addIcon("content-copy", ContentCopy);
addIcon("content-paste-go", ContentPasteGo);
addIcon("edit", Edit);
addIcon("check-box", CheckBox);
addIcon("export", ExportNotesOutline);
addIcon("uploadRounded", uploadRounded);
addIcon("downloadRounded", downloadRounded);

View File

@ -1,9 +1,7 @@
<script setup lang="ts">
import { Icon } from "@iconify/vue";
import { computed, defineComponent } from "vue";
import router from "@/router";
defineComponent({
name: "Breadcrumb"
});
@ -14,16 +12,17 @@ const currentRoute = computed(() => {
</script>
<template>
<div class="flex justify-between">
<div class="breadcrumb animate__animated animate__lightSpeedInLeft">
<IconifyIconOffline class="inline-block mr-2" :icon="currentRoute.meta['icon'] as string"/>
<!-- <Icon-->
<!-- class="inline-block mr-2"-->
<!-- :icon="currentRoute.meta['icon'] as string"-->
<!-- />-->
<div class="breadcrumb flex justify-between items-center">
<div
class="flex items-center justify-center breadcrumb-left animate__animated animate__lightSpeedInLeft"
>
<IconifyIconOffline
class="inline-block mr-2"
:icon="currentRoute.meta['icon'] as string"
/>
<span>{{ currentRoute.meta["title"] }}</span>
</div>
<div class="right">
<div class="breadcrumb-right">
<slot></slot>
</div>
</div>

View File

@ -21,9 +21,12 @@ $danger-color: #F56C6C;
}
.breadcrumb {
margin-bottom: 15px;
.breadcrumb-left {
color: $primary-color;
font-size: 36px;
height: 50px;
height: 30px;
svg {
vertical-align: top;
@ -34,11 +37,14 @@ $danger-color: #F56C6C;
color: black;
font-size: 18px;
font-weight: bold;
transform: translateY(5px);
//transform: translateY(5px);
display: inline-block;
}
}
}
}
.left-menu-container {
@ -57,6 +63,7 @@ $danger-color: #F56C6C;
font-size: 14px;
cursor: pointer;
}
.version:hover {
animation: heartBeat 1s;
}
@ -91,7 +98,6 @@ $danger-color: #F56C6C;
}
}
}
@ -111,6 +117,10 @@ $danger-color: #F56C6C;
color: $primary-color;
}
.bg-primary {
background: $primary-color;
}
.danger-text {
color: $danger-color !important;
}

View File

@ -6,6 +6,7 @@ import Breadcrumb from "@/layout/compoenets/Breadcrumb.vue";
import { useDebounceFn } from "@vueuse/core";
import { clone } from "@/utils/clone";
import { Base64 } from "js-base64";
import IconifyIconOffline from "@/components/IconifyIcon/src/iconifyIconOffline";
defineComponent({
name: "Config"
@ -116,9 +117,12 @@ const protocol = ref("frp://");
const visibles = reactive({
copyServerConfig: false,
pasteServerConfig: false
pasteServerConfig: false,
exportConfig: false
});
const exportConfigType = ref("toml");
const handleSubmit = useDebounceFn(() => {
if (!formRef.value) return;
formRef.value.validate(valid => {
@ -195,6 +199,14 @@ onMounted(() => {
checkAndResetVersion();
}
});
ipcRenderer.on("Config.exportConfig.hook", (event, args) => {
const { err, data } = args;
console.log(err, data, "export");
if (!err) {
const { configPath } = data;
ElMessageBox.alert(`配置路径:${configPath}`, `🎉 导出成功`);
}
});
});
const handleSelectFile = (type: number, ext: string[]) => {
@ -286,15 +298,34 @@ const handlePasteServerConfigBase64 = useDebounceFn(() => {
visibles.pasteServerConfig = false;
}, 300);
const handleShowExportDialog = () => {
visibles.exportConfig = true;
};
const handleExportConfig = useDebounceFn(() => {
ipcRenderer.send("config.exportConfig", exportConfigType.value);
visibles.exportConfig = false;
}, 300);
const handleImportConfig = () => {};
onUnmounted(() => {
ipcRenderer.removeAllListeners("Config.getConfig.hook");
ipcRenderer.removeAllListeners("Config.saveConfig.hook");
ipcRenderer.removeAllListeners("Config.versions.hook");
ipcRenderer.removeAllListeners("Config.exportConfig.hook");
});
</script>
<template>
<div class="main">
<breadcrumb />
<breadcrumb>
<el-button plain type="primary">
<IconifyIconOffline icon="uploadRounded" />
</el-button>
<el-button plain type="primary" @click="handleShowExportDialog">
<IconifyIconOffline icon="downloadRounded" />
</el-button>
</breadcrumb>
<div class="app-container-breadcrumb pr-2" v-loading="loading > 0">
<div class="w-full bg-white p-4 rounded drop-shadow-lg">
<el-form
@ -643,8 +674,8 @@ onUnmounted(() => {
class="ml-2"
type="primary"
@click="handleSelectFile(1, ['crt'])"
>选择</el-button
>
>选择
</el-button>
</el-form-item>
</el-col>
<el-col :span="24">
@ -682,8 +713,8 @@ onUnmounted(() => {
class="ml-2"
type="primary"
@click="handleSelectFile(2, ['key'])"
>选择</el-button
>
>选择
</el-button>
</el-form-item>
</el-col>
<el-col :span="24">
@ -721,8 +752,8 @@ onUnmounted(() => {
class="ml-2"
type="primary"
@click="handleSelectFile(3, ['crt'])"
>选择</el-button
>
>选择
</el-button>
</el-form-item>
</el-col>
<el-col :span="24">
@ -896,7 +927,7 @@ onUnmounted(() => {
</el-form>
</div>
</div>
<!-- 链接导入服务器 -->
<el-dialog
v-model="visibles.copyServerConfig"
title="复制链接"
@ -916,7 +947,7 @@ onUnmounted(() => {
:rows="8"
></el-input>
</el-dialog>
<!-- 链接导出服务器-->
<el-dialog
v-model="visibles.pasteServerConfig"
title="导入链接"
@ -946,6 +977,39 @@ onUnmounted(() => {
</div>
</template>
</el-dialog>
<!-- 配置导出-->
<el-dialog
v-model="visibles.exportConfig"
title="导出配置"
width="500"
top="5%"
>
<el-alert
class="mb-4"
:title="`导出文件名为 frpc-desktop.${exportConfigType} 重复导出则覆盖`"
type="warning"
:closable="false"
/>
<el-form>
<el-form-item label="导出类型">
<el-radio-group v-model="exportConfigType">
<el-radio-button label="toml" value="toml" />
<el-radio-button label="ini" value="ini" />
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button plain type="primary" @click="handleExportConfig">
<IconifyIconOffline
class="cursor-pointer mr-2"
icon="downloadRounded"
/>
</el-button>
</div>
</template>
</el-dialog>
</div>
</template>

View File

@ -117,7 +117,7 @@ onUnmounted(() => {
<breadcrumb>
<div class="h-full flex items-center justify-center">
<span class="text-sm font-bold">下载源 </span>
<el-select class="w-24" v-model="currMirror">
<el-select class="w-40" v-model="currMirror">
<el-option
v-for="m in mirrors"
:label="m.name"

View File

@ -300,12 +300,9 @@ onUnmounted(() => {
<!-- <coming-soon />-->
<div class="main">
<breadcrumb>
<div
class="cursor-pointer h-[36px] w-[36px] bg-[#5f3bb0] rounded text-white flex justify-center items-center"
@click="handleOpenInsert"
>
<el-button class="mr-2" plain type="primary" @click="handleOpenInsert">
<IconifyIconOffline icon="add" />
</div>
</el-button>
</breadcrumb>
<div class="app-container-breadcrumb pr-2" v-loading="loading.list > 0">
<template v-if="proxys && proxys.length > 0">