Files
frpc-console/static/app.js
T

198 lines
6.6 KiB
JavaScript

// app.js
import { createApp, ref, reactive, computed, onMounted } from 'vue';
// 导入各模块
import { apiFetch } from './modules/api.js';
import { login, loadAuthState, clearAuthState, saveAuthState } from './modules/auth.js';
import { loadConfig, saveConfig as saveConfigApi } from './modules/config.js';
import { loadProxies, createProxy, updateProxy, deleteProxy, filterProxies } from './modules/proxies.js';
import { getFrpcStatus, reloadFrpc, startFrpc, stopFrpc } from './modules/frpc.js';
import {
activeTab, switchTab,
dialogVisible, dialogMode, dialogForm,
openAddDialog, openEditDialog, closeDialog,
searchKeyword,
} from './modules/ui.js';
import { importToml, exportToml } from './modules/import.js'; // 如果有的话
const app = createApp({
setup() {
// ===== 登录态 =====
const loggedIn = ref(false);
const loading = ref(false);
const loginError = ref('');
const loginForm = reactive({ username: '', password: '' });
const token = ref('');
const tokenExpireTime = ref(0);
const transitioning = ref(false);
const contentVisible = ref(false);
let expireTimer = null;
// ===== 数据 =====
const globalConfig = reactive({});
const proxies = ref([]);
const frpcRunning = ref(false);
// ===== 初始化 =====
onMounted(() => {
const saved = loadAuthState();
if (saved.valid) {
token.value = saved.token;
tokenExpireTime.value = saved.expire;
loginForm.username = saved.username;
loggedIn.value = true;
loadAllData().then(() => {
contentVisible.value = true;
startExpireTimer();
});
}
});
const startExpireTimer = () => {
if (expireTimer) clearInterval(expireTimer);
expireTimer = setInterval(() => {
if (Date.now() >= tokenExpireTime.value) {
doLogout();
alert('登录已超时,请重新登录');
}
}, 5000);
};
const loadAllData = async () => {
const [cfg, list, running] = await Promise.all([
loadConfig(),
loadProxies(),
getFrpcStatus(),
]);
Object.assign(globalConfig, cfg);
proxies.value = list;
frpcRunning.value = running;
};
// ===== 登录/退出 =====
const doLogin = async () => {
if (!loginForm.username || !loginForm.password) {
loginError.value = '请输入用户名和密码';
return;
}
loading.value = true;
loginError.value = '';
const result = await login(loginForm.username, loginForm.password);
if (result.success) {
token.value = result.token;
tokenExpireTime.value = result.expire;
transitioning.value = true;
loggedIn.value = true;
setTimeout(async () => {
transitioning.value = false;
await loadAllData();
loading.value = false;
setTimeout(() => {
contentVisible.value = true;
startExpireTimer();
}, 300);
}, 500);
} else {
loginError.value = result.error;
loading.value = false;
}
};
const doLogout = () => {
if (expireTimer) clearInterval(expireTimer);
contentVisible.value = false;
loggedIn.value = false;
token.value = '';
tokenExpireTime.value = 0;
loginForm.username = '';
loginForm.password = '';
loading.value = false;
transitioning.value = false;
clearAuthState();
};
// ===== 保存配置 =====
const saveConfig = async () => {
const result = await saveConfigApi(globalConfig);
if (result.code === 0) {
frpcRunning.value = await getFrpcStatus();
alert('配置已更新并热加载');
} else {
alert('保存失败: ' + result.msg);
}
};
// ===== 隧道操作 =====
const toggleProxy = async (p) => {
const result = await updateProxy(p);
if (result.code !== 0) {
alert('更新失败: ' + result.msg);
proxies.value = await loadProxies();
} else {
frpcRunning.value = await getFrpcStatus();
}
};
const removeProxy = async (id) => {
if (!confirm('确定要删除这条隧道吗?')) return;
const result = await deleteProxy(id);
if (result.code === 0) {
proxies.value = await loadProxies();
frpcRunning.value = await getFrpcStatus();
} else {
alert('删除失败: ' + result.msg);
}
};
const confirmDialog = async () => {
const form = dialogForm.value;
if (!form.name || !form.localIP || !form.localPort || !form.remotePort) {
alert('请填写完整信息');
return;
}
const result = dialogMode.value === 'add'
? await createProxy(form)
: await updateProxy(form);
if (result.code === 0) {
closeDialog();
proxies.value = await loadProxies();
frpcRunning.value = await getFrpcStatus();
} else {
alert('操作失败: ' + result.msg);
}
};
// ===== 计算属性 =====
const filteredProxies = computed(() => filterProxies(proxies.value, searchKeyword.value));
return {
loggedIn,
loading,
loginError,
loginForm,
doLogin,
doLogout,
activeTab,
switchTab,
globalConfig,
saveConfig,
proxies,
filteredProxies,
toggleProxy,
removeProxy,
frpcRunning,
dialogVisible,
dialogMode,
dialogForm,
openAddDialog,
openEditDialog,
closeDialog,
confirmDialog,
searchKeyword,
transitioning,
contentVisible,
};
},
});
app.mount('#app');