Files
remoteconn-gitea/apps/miniprogram/utils/terminalNavigation.js
2026-03-21 18:57:10 +08:00

102 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* global wx, getCurrentPages, module, require */
const { setPendingTerminalIntent } = require("./terminalIntent");
const { normalizeTerminalSessionSnapshot } = require("./terminalSessionState");
const ACTIVE_TERMINAL_SESSION_STATUS = new Set(["connecting", "auth_pending", "connected", "resumable"]);
/**
* 生成终端页路由:
* 1. 终端页必须携带 serverId否则 onLoad 无法定位服务器;
* 2. AI 快捷启动仍沿用历史 query `openCodex=1`,避免再维护第二套入口参数。
*/
function resolveTerminalPageUrl(serverId, options) {
const normalizedServerId = String(serverId || "").trim();
if (!normalizedServerId) return "";
const nextOptions = options && typeof options === "object" ? options : {};
const query = nextOptions.openCodex ? "&openCodex=1" : "";
return `/pages/terminal/index?serverId=${normalizedServerId}${query}`;
}
/**
* 若导航栈上一页已经是同一台服务器的终端页,则优先复用它:
* 1. 避免重复压栈多个终端实例;
* 2. 保留该终端页内部已有的连接态和缓冲区。
*/
function shouldReusePreviousTerminalPage(pages, serverId) {
const normalizedServerId = String(serverId || "").trim();
if (!normalizedServerId || !Array.isArray(pages) || pages.length < 2) {
return false;
}
const previous = pages[pages.length - 2];
return !!(
previous &&
previous.route === "pages/terminal/index" &&
previous.data &&
previous.data.serverId === normalizedServerId
);
}
/**
* 从终端会话快照中提取“当前可打开的终端服务器”:
* 1. 仅接受连接中/已连接/可恢复的会话;
* 2. 若服务器列表里已不存在该服务器,则视为不可打开。
*/
function resolveActiveTerminalServerId(snapshot, servers, now = Date.now()) {
const normalizedSnapshot = normalizeTerminalSessionSnapshot(snapshot, now);
if (!normalizedSnapshot) return "";
if (!ACTIVE_TERMINAL_SESSION_STATUS.has(normalizedSnapshot.status)) {
return "";
}
const rows = Array.isArray(servers) ? servers : [];
return rows.some((item) => String(item && item.id ? item.id : "").trim() === normalizedSnapshot.serverId)
? normalizedSnapshot.serverId
: "";
}
/**
* 判断当前是否存在“可从 shell 按钮直接打开”的活动终端:
* 1. 与 shell 按钮点击逻辑共用同一判定,避免“能点开但不高亮”或反过来的分叉;
* 2. 只要会话仍处于连接中 / 已连接 / 可恢复,且服务器仍存在,即视为活动连接。
*/
function hasActiveTerminalSession(snapshot, servers, now = Date.now()) {
return Boolean(resolveActiveTerminalServerId(snapshot, servers, now));
}
/**
* 打开终端页:
* 1. 连接页与底部 shell 按钮共用同一套终端导航语义;
* 2. 若命中上一页复用,则直接返回现有终端页;
* 3. 仅在需要时写入一次瞬时终端意图。
*/
function openTerminalPage(serverId, reuseExisting, options) {
const normalizedServerId = String(serverId || "").trim();
if (!normalizedServerId) return false;
const nextOptions = options && typeof options === "object" ? options : {};
const pages = typeof getCurrentPages === "function" ? getCurrentPages() : [];
if (reuseExisting && shouldReusePreviousTerminalPage(pages, normalizedServerId)) {
if (nextOptions.openCodex) {
setPendingTerminalIntent({
// `open_ai` 为历史命名,当前语义已是“进入终端后直接启动默认 AI”。
action: "open_ai",
serverId: normalizedServerId,
createdAt: Date.now()
});
}
wx.navigateBack({ delta: 1 });
return true;
}
const url = resolveTerminalPageUrl(normalizedServerId, nextOptions);
if (!url) return false;
wx.navigateTo({ url });
return true;
}
module.exports = {
resolveTerminalPageUrl,
shouldReusePreviousTerminalPage,
resolveActiveTerminalServerId,
hasActiveTerminalSession,
openTerminalPage
};