正在进行1.5版本更新,导入第一批代码

This commit is contained in:
2026-07-25 22:15:41 +08:00
parent 1669abf9e8
commit ce07f4f0f0
8 changed files with 717 additions and 117 deletions
+102 -14
View File
@@ -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,
};
},
});