first commit
This commit is contained in:
136
apps/miniprogram/pages/terminal/terminalSessionInfo.js
Normal file
136
apps/miniprogram/pages/terminal/terminalSessionInfo.js
Normal file
@@ -0,0 +1,136 @@
|
||||
/* global module */
|
||||
|
||||
/**
|
||||
* 会话信息浮层只展示当前终端会话已经拥有的静态配置。
|
||||
* 这里保持纯函数,避免点击工具栏时再触发额外网络请求或依赖页面实例状态。
|
||||
*/
|
||||
function normalizeDisplayText(value) {
|
||||
const normalized = String(value || "").trim();
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function buildTerminalServerAddress(serverInput) {
|
||||
const server = serverInput && typeof serverInput === "object" ? serverInput : {};
|
||||
const username = normalizeDisplayText(server.username);
|
||||
const host = normalizeDisplayText(server.host);
|
||||
const port = normalizeDisplayText(server.port);
|
||||
if (!host) {
|
||||
return "";
|
||||
}
|
||||
const authority = username ? `${username}@${host}` : host;
|
||||
return port ? `${authority}:${port}` : authority;
|
||||
}
|
||||
|
||||
function resolveSessionConnectionValue(sessionInfoCopy, connected) {
|
||||
const onValue = normalizeDisplayText(sessionInfoCopy.connectedValue) || "连接";
|
||||
const offValue = normalizeDisplayText(sessionInfoCopy.disconnectedValue) || "断开";
|
||||
return connected ? onValue : offValue;
|
||||
}
|
||||
|
||||
function resolveAiProviderLabel(activeAiProvider) {
|
||||
const normalized = normalizeDisplayText(activeAiProvider).toLowerCase();
|
||||
if (normalized === "copilot") return "Copilot";
|
||||
if (normalized === "codex") return "Codex";
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 工具栏浮层需要稳定输出静态会话信息:
|
||||
* 1. 顶部 hero 区聚焦“当前是哪台机器、通过哪条链路进入”;
|
||||
* 2. SSH / AI 连接态拆成两枚并排胶囊,便于一眼判断双通道状态;
|
||||
* 3. hero 已承载入口 / 跳转链路后,下方信息卡只保留不重复的目录信息;
|
||||
* 4. 缺省值统一在这里兜底,页面层只负责展示。
|
||||
*/
|
||||
function buildTerminalSessionInfoModel(input) {
|
||||
const source = input && typeof input === "object" ? input : {};
|
||||
const copy = source.copy && typeof source.copy === "object" ? source.copy : {};
|
||||
const sessionInfoCopy = copy.sessionInfo && typeof copy.sessionInfo === "object" ? copy.sessionInfo : {};
|
||||
const fallbackCopy = copy.fallback && typeof copy.fallback === "object" ? copy.fallback : {};
|
||||
const server = source.server && typeof source.server === "object" ? source.server : {};
|
||||
const jumpHost = server.jumpHost && typeof server.jumpHost === "object" ? server.jumpHost : null;
|
||||
const hasJumpHost = !!(jumpHost && jumpHost.enabled);
|
||||
const serverLabel = normalizeDisplayText(source.serverLabel);
|
||||
const statusText = normalizeDisplayText(source.statusText);
|
||||
const activeAiProvider = normalizeDisplayText(source.activeAiProvider);
|
||||
const emptyValue = normalizeDisplayText(sessionInfoCopy.emptyValue) || "-";
|
||||
const serverName =
|
||||
normalizeDisplayText(server.name) ||
|
||||
serverLabel ||
|
||||
normalizeDisplayText(fallbackCopy.unnamedServer) ||
|
||||
emptyValue;
|
||||
const projectPath =
|
||||
normalizeDisplayText(server.projectPath) || normalizeDisplayText(fallbackCopy.noProject) || emptyValue;
|
||||
const address =
|
||||
(hasJumpHost ? buildTerminalServerAddress(jumpHost) : buildTerminalServerAddress(server)) || emptyValue;
|
||||
const jumpTarget = hasJumpHost ? buildTerminalServerAddress(server) || emptyValue : "";
|
||||
const sshConnected = statusText === "connected";
|
||||
const aiConnected = !!activeAiProvider;
|
||||
const sshConnection = resolveSessionConnectionValue(sessionInfoCopy, statusText === "connected");
|
||||
const aiConnection = resolveSessionConnectionValue(sessionInfoCopy, aiConnected);
|
||||
const aiProviderLabel = resolveAiProviderLabel(activeAiProvider);
|
||||
const hero = {
|
||||
eyebrow: hasJumpHost ? "双跳通道" : "直连通道",
|
||||
name: serverName,
|
||||
subtitle: address,
|
||||
routeLabel: normalizeDisplayText(sessionInfoCopy.jumpTargetLabel) || "跳至服务器",
|
||||
route: hasJumpHost ? jumpTarget : ""
|
||||
};
|
||||
const statusChips = [
|
||||
{
|
||||
key: "sshConnection",
|
||||
label: normalizeDisplayText(sessionInfoCopy.sshConnectionLabel) || "SSH连接",
|
||||
value: sshConnection,
|
||||
badge: sshConnected ? "LIVE" : "IDLE",
|
||||
note: sshConnected ? "终端链路已就绪" : "等待重新建立",
|
||||
connected: sshConnected
|
||||
},
|
||||
{
|
||||
key: "aiConnection",
|
||||
label: normalizeDisplayText(sessionInfoCopy.aiConnectionLabel) || "AI连接",
|
||||
value: aiConnection,
|
||||
badge: aiConnected ? aiProviderLabel : "STANDBY",
|
||||
note: aiConnected ? `${aiProviderLabel} 正在前台` : "尚未接管终端",
|
||||
connected: aiConnected
|
||||
}
|
||||
];
|
||||
/**
|
||||
* 链路信息已经在 hero 区完整展示:
|
||||
* 1. 直连时 subtitle 就是目标服务器;
|
||||
* 2. 跳板时 subtitle + route 已同时覆盖入口与目标;
|
||||
* 3. 同一弹层里不再重复渲染“入口 / 目标”卡片,只留下工作目录。
|
||||
*/
|
||||
const detailItems = [
|
||||
{
|
||||
key: "project",
|
||||
accent: "目录",
|
||||
label: normalizeDisplayText(sessionInfoCopy.projectLabel) || "工作目录",
|
||||
value: projectPath,
|
||||
wide: true
|
||||
}
|
||||
];
|
||||
|
||||
return {
|
||||
title: normalizeDisplayText(sessionInfoCopy.title) || "会话信息",
|
||||
hero,
|
||||
statusChips,
|
||||
detailItems,
|
||||
items: detailItems
|
||||
.map((item) => ({
|
||||
key: item.key,
|
||||
label: item.label,
|
||||
value: item.value
|
||||
}))
|
||||
.concat(
|
||||
statusChips.map((item) => ({
|
||||
key: item.key,
|
||||
label: item.label,
|
||||
value: item.value
|
||||
}))
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildTerminalServerAddress,
|
||||
buildTerminalSessionInfoModel
|
||||
};
|
||||
Reference in New Issue
Block a user