正在进行1.5版本更新,导入第一批代码
This commit is contained in:
+102
-14
@@ -1,13 +1,12 @@
|
||||
// app.js - 普通脚本(非模块)
|
||||
|
||||
const { createApp, ref, reactive, computed, onMounted } = Vue;
|
||||
const { createApp, ref, reactive, computed, onMounted, nextTick, watch } = Vue;
|
||||
|
||||
// ============================================================
|
||||
// 1. 基础 API
|
||||
// ============================================================
|
||||
const API_BASE = "/api";
|
||||
|
||||
|
||||
function getToken() {
|
||||
return localStorage.getItem("frpc_token") || "";
|
||||
}
|
||||
@@ -86,9 +85,9 @@ async function login(username, password) {
|
||||
// 3. Config
|
||||
// ============================================================
|
||||
const defaultConfig = {
|
||||
serverAddr: "frp.whitetop.xyz",
|
||||
serverPort: 9358,
|
||||
token: "",
|
||||
serverAddr: "frp.example.com",
|
||||
serverPort: 7000,
|
||||
token: "CHANGE_ME",
|
||||
logLevel: "info",
|
||||
logMaxDays: 3,
|
||||
tcpMux: true,
|
||||
@@ -183,7 +182,22 @@ async function getFrpcStatus() {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 6. UI State
|
||||
// 6. Logs
|
||||
// ============================================================
|
||||
async function fetchLogsApi() {
|
||||
try {
|
||||
const data = await apiFetch("/frpc/log");
|
||||
if (data.code === 0) {
|
||||
return { lines: data.data.lines || [], total: data.data.total || 0, error: data.data.error || "" };
|
||||
}
|
||||
return { lines: [], total: 0, error: "加载失败" };
|
||||
} catch (e) {
|
||||
return { lines: [], total: 0, error: "网络错误" };
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 7. UI State
|
||||
// ============================================================
|
||||
const activeTab = ref("proxies");
|
||||
const dialogVisible = ref(false);
|
||||
@@ -197,6 +211,7 @@ const dialogForm = ref({
|
||||
remotePort: 0,
|
||||
});
|
||||
const searchKeyword = ref("");
|
||||
const showToken = ref(false);
|
||||
|
||||
function openAddDialog() {
|
||||
dialogMode.value = "add";
|
||||
@@ -222,7 +237,7 @@ function closeDialog() {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 7. Vue App
|
||||
// 8. Vue App
|
||||
// ============================================================
|
||||
const app = createApp({
|
||||
setup() {
|
||||
@@ -251,7 +266,6 @@ const app = createApp({
|
||||
const globalConfig = reactive({});
|
||||
const proxies = ref([]);
|
||||
const frpcRunning = ref(false);
|
||||
const showDetail = ref(false);
|
||||
|
||||
// ---- 修改密码 ----
|
||||
const passwordChange = reactive({
|
||||
@@ -262,6 +276,15 @@ const app = createApp({
|
||||
const passwordChangeError = ref("");
|
||||
const passwordChangeSuccess = ref("");
|
||||
|
||||
// ---- 日志 ----
|
||||
const logLines = ref([]);
|
||||
const logTotal = ref(0);
|
||||
const logError = ref("");
|
||||
const logLastUpdate = ref("");
|
||||
const logAutoScroll = ref(true);
|
||||
let logTimer = null;
|
||||
let logFetching = false;
|
||||
|
||||
// ---- 初始化 ----
|
||||
onMounted(() => {
|
||||
const saved = loadAuthState();
|
||||
@@ -279,6 +302,15 @@ const app = createApp({
|
||||
}
|
||||
});
|
||||
|
||||
// ---- Tab 切换监听日志轮询 ----
|
||||
watch(activeTab, (newTab) => {
|
||||
if (newTab === "logs") {
|
||||
startLogPolling();
|
||||
} else {
|
||||
stopLogPolling();
|
||||
}
|
||||
});
|
||||
|
||||
async function checkUsers() {
|
||||
try {
|
||||
const res = await fetch("/api/check/users");
|
||||
@@ -312,6 +344,54 @@ const app = createApp({
|
||||
frpcRunning.value = running;
|
||||
}
|
||||
|
||||
// ---- 日志轮询 ----
|
||||
async function fetchLogs() {
|
||||
if (logFetching) return;
|
||||
logFetching = true;
|
||||
try {
|
||||
const result = await fetchLogsApi();
|
||||
logLines.value = result.lines;
|
||||
logTotal.value = result.total;
|
||||
logError.value = result.error;
|
||||
logLastUpdate.value = new Date().toLocaleTimeString();
|
||||
if (logAutoScroll.value) {
|
||||
await nextTick();
|
||||
const container = document.getElementById("logContainer");
|
||||
if (container) {
|
||||
container.scrollTop = container.scrollHeight;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logError.value = "网络错误";
|
||||
} finally {
|
||||
logFetching = false;
|
||||
}
|
||||
}
|
||||
|
||||
function startLogPolling() {
|
||||
if (logTimer) return;
|
||||
fetchLogs();
|
||||
logTimer = setInterval(fetchLogs, 8000);
|
||||
}
|
||||
|
||||
function stopLogPolling() {
|
||||
if (logTimer) {
|
||||
clearInterval(logTimer);
|
||||
logTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function refreshLogs() {
|
||||
fetchLogs();
|
||||
}
|
||||
|
||||
function scrollLogToBottom() {
|
||||
const container = document.getElementById("logContainer");
|
||||
if (container) {
|
||||
container.scrollTop = container.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 登录 ----
|
||||
const doLogin = async () => {
|
||||
if (!loginForm.username || !loginForm.password) {
|
||||
@@ -368,9 +448,7 @@ const app = createApp({
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.code === 0) {
|
||||
// ✅ 注册成功,不再是首次启动
|
||||
isFirstRun.value = false;
|
||||
|
||||
const token = data.data.token;
|
||||
const expire = saveAuthState(token, registerForm.username);
|
||||
token.value = token;
|
||||
@@ -398,6 +476,7 @@ const app = createApp({
|
||||
// ---- 退出 ----
|
||||
const doLogout = () => {
|
||||
if (expireTimer) clearInterval(expireTimer);
|
||||
stopLogPolling();
|
||||
contentVisible.value = false;
|
||||
loggedIn.value = false;
|
||||
token.value = "";
|
||||
@@ -407,8 +486,6 @@ const app = createApp({
|
||||
loading.value = false;
|
||||
transitioning.value = false;
|
||||
clearAuthState();
|
||||
|
||||
// ✅ 重置注册相关状态
|
||||
isFirstRun.value = false;
|
||||
registerForm.username = "";
|
||||
registerForm.password = "";
|
||||
@@ -504,7 +581,7 @@ const app = createApp({
|
||||
}
|
||||
};
|
||||
|
||||
// ---- 导入导出(已移入 setup,可访问 loadAllData) ----
|
||||
// ---- 导入导出 ----
|
||||
const triggerImport = () => {
|
||||
document.getElementById("tomlFileInput").click();
|
||||
};
|
||||
@@ -579,7 +656,6 @@ const app = createApp({
|
||||
|
||||
activeTab,
|
||||
globalConfig,
|
||||
showDetail,
|
||||
saveConfig,
|
||||
|
||||
proxies,
|
||||
@@ -608,6 +684,18 @@ const app = createApp({
|
||||
passwordChangeError,
|
||||
passwordChangeSuccess,
|
||||
changePassword,
|
||||
|
||||
// 日志相关
|
||||
logLines,
|
||||
logTotal,
|
||||
logError,
|
||||
logLastUpdate,
|
||||
logAutoScroll,
|
||||
refreshLogs,
|
||||
scrollLogToBottom,
|
||||
|
||||
// Token 显示切换
|
||||
showToken,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user