部分重型模块的原子化拆解
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
// modules/api.js
|
||||
const API_BASE = '/api';
|
||||
|
||||
export function getToken() {
|
||||
return localStorage.getItem('frpc_token') || '';
|
||||
}
|
||||
|
||||
export function getHeaders() {
|
||||
return {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + getToken(),
|
||||
};
|
||||
}
|
||||
|
||||
export async function apiFetch(endpoint, options = {}) {
|
||||
const url = API_BASE + endpoint;
|
||||
const headers = options.body instanceof FormData
|
||||
? { 'Authorization': 'Bearer ' + getToken() }
|
||||
: getHeaders();
|
||||
|
||||
const res = await fetch(url, {
|
||||
...options,
|
||||
headers: { ...headers, ...(options.headers || {}) },
|
||||
});
|
||||
return res.json();
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// modules/auth.js
|
||||
import { apiFetch } from './api.js';
|
||||
|
||||
export function parseJwtExpire(token) {
|
||||
try {
|
||||
const payload = JSON.parse(atob(token.split('.')[1]));
|
||||
return payload.exp * 1000;
|
||||
} catch {
|
||||
return Date.now() + 7 * 24 * 60 * 60 * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
export function saveAuthState(token, username) {
|
||||
const expire = parseJwtExpire(token);
|
||||
localStorage.setItem('frpc_token', token);
|
||||
localStorage.setItem('frpc_token_expire', String(expire));
|
||||
localStorage.setItem('frpc_username', username);
|
||||
return expire;
|
||||
}
|
||||
|
||||
export function loadAuthState() {
|
||||
const token = localStorage.getItem('frpc_token');
|
||||
const expire = parseInt(localStorage.getItem('frpc_token_expire') || '0', 10);
|
||||
const username = localStorage.getItem('frpc_username') || '';
|
||||
if (token && expire > Date.now()) {
|
||||
return { token, expire, username, valid: true };
|
||||
}
|
||||
clearAuthState();
|
||||
return { token: '', expire: 0, username: '', valid: false };
|
||||
}
|
||||
|
||||
export function clearAuthState() {
|
||||
localStorage.removeItem('frpc_token');
|
||||
localStorage.removeItem('frpc_token_expire');
|
||||
localStorage.removeItem('frpc_username');
|
||||
}
|
||||
|
||||
export async function login(username, password) {
|
||||
const data = await apiFetch('/login', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ username, password }),
|
||||
});
|
||||
if (data.code === 0) {
|
||||
const token = data.data.token;
|
||||
const expire = saveAuthState(token, username);
|
||||
return { success: true, token, expire };
|
||||
}
|
||||
return { success: false, error: data.msg || '登录失败' };
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// modules/config.js
|
||||
import { apiFetch } from './api.js';
|
||||
|
||||
const defaultConfig = {
|
||||
serverAddr: 'frp.whitetop.xyz',
|
||||
serverPort: 9358,
|
||||
token: '',
|
||||
logLevel: 'info',
|
||||
logMaxDays: 3,
|
||||
tcpMux: true,
|
||||
tcpMuxKeepalive: 30,
|
||||
heartbeatInterval: 15,
|
||||
heartbeatTimeout: 70,
|
||||
poolCount: 8,
|
||||
};
|
||||
|
||||
export async function loadConfig() {
|
||||
try {
|
||||
const data = await apiFetch('/config');
|
||||
if (data.code === 0) {
|
||||
return { ...defaultConfig, ...data.data };
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('加载配置失败', e);
|
||||
}
|
||||
return { ...defaultConfig };
|
||||
}
|
||||
|
||||
export async function saveConfig(config) {
|
||||
const data = await apiFetch('/config', {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(config),
|
||||
});
|
||||
return data;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// modules/frpc.js
|
||||
import { apiFetch } from './api.js';
|
||||
|
||||
export async function getFrpcStatus() {
|
||||
try {
|
||||
const data = await apiFetch('/frpc/status');
|
||||
if (data.code === 0) {
|
||||
return data.data.running || false;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('获取 frpc 状态失败', e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function reloadFrpc() {
|
||||
const data = await apiFetch('/frpc/reload', { method: 'POST' });
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function startFrpc() {
|
||||
const data = await apiFetch('/frpc/start', { method: 'POST' });
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function stopFrpc() {
|
||||
const data = await apiFetch('/frpc/stop', { method: 'POST' });
|
||||
return data;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// modules/proxies.js
|
||||
import { apiFetch } from './api.js';
|
||||
|
||||
export async function loadProxies() {
|
||||
try {
|
||||
const data = await apiFetch('/proxies');
|
||||
if (data.code === 0) {
|
||||
return data.data || [];
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('加载隧道失败', e);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export async function createProxy(proxy) {
|
||||
const data = await apiFetch('/proxy', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(proxy),
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function updateProxy(proxy) {
|
||||
const data = await apiFetch('/proxy/' + proxy.id, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(proxy),
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function deleteProxy(id) {
|
||||
const data = await apiFetch('/proxy/' + id, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
export function filterProxies(list, keyword) {
|
||||
if (!keyword) return list;
|
||||
const kw = keyword.toLowerCase();
|
||||
return list.filter(p =>
|
||||
p.name.toLowerCase().includes(kw) ||
|
||||
p.localIP.includes(kw) ||
|
||||
String(p.remotePort).includes(kw)
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// modules/ui.js
|
||||
import { ref } from 'vue';
|
||||
|
||||
// Tab 切换
|
||||
export const activeTab = ref('proxies');
|
||||
export function switchTab(tab) {
|
||||
activeTab.value = tab;
|
||||
}
|
||||
|
||||
// 弹窗控制
|
||||
export const dialogVisible = ref(false);
|
||||
export const dialogMode = ref('add');
|
||||
export const dialogForm = ref({
|
||||
id: null,
|
||||
name: '',
|
||||
type: 'tcp',
|
||||
localIP: '',
|
||||
localPort: 0,
|
||||
remotePort: 0,
|
||||
});
|
||||
|
||||
export function openAddDialog() {
|
||||
dialogMode.value = 'add';
|
||||
dialogForm.value = { id: null, name: '', type: 'tcp', localIP: '', localPort: 0, remotePort: 0 };
|
||||
dialogVisible.value = true;
|
||||
}
|
||||
|
||||
export function openEditDialog(proxy) {
|
||||
dialogMode.value = 'edit';
|
||||
dialogForm.value = { ...proxy };
|
||||
dialogVisible.value = true;
|
||||
}
|
||||
|
||||
export function closeDialog() {
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
|
||||
// 搜索
|
||||
export const searchKeyword = ref('');
|
||||
Reference in New Issue
Block a user