first commit
This commit is contained in:
101
apps/miniprogram/utils/terminalNavigation.js
Normal file
101
apps/miniprogram/utils/terminalNavigation.js
Normal file
@@ -0,0 +1,101 @@
|
||||
/* 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
|
||||
};
|
||||
Reference in New Issue
Block a user