mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 22:30:38 +08:00
Restore mobile panel UI refinements
This commit is contained in:
327
style.css
327
style.css
@@ -704,6 +704,12 @@
|
||||
color: var(--bme-primary);
|
||||
}
|
||||
|
||||
#bme-graph-canvas,
|
||||
#bme-mobile-graph-canvas,
|
||||
#bme-fullscreen-graph-canvas {
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
#bme-graph-canvas {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
@@ -3691,26 +3697,84 @@
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
/* --- Node Detail Panel (sidebar overlay) --- */
|
||||
.bme-node-detail {
|
||||
/* --- Node detail:桌面右侧抽屉 / 移动端图谱内居中悬浮 + 遮罩 --- */
|
||||
.bme-node-detail-scrim {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 9;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
backdrop-filter: blur(3px);
|
||||
-webkit-backdrop-filter: blur(3px);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bme-node-detail-scrim[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* 桌面图谱工作区(主画布):节点详情仍为右侧滑出面板 */
|
||||
#bme-node-detail {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: auto;
|
||||
width: 280px;
|
||||
height: 100%;
|
||||
max-height: none;
|
||||
background: var(--bme-surface-container);
|
||||
border-left: 1px solid var(--bme-border);
|
||||
border-radius: 0;
|
||||
padding: 12px;
|
||||
overflow-y: auto;
|
||||
box-shadow: none;
|
||||
transform: translateX(100%);
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
pointer-events: auto;
|
||||
transition: transform 0.2s ease;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.bme-node-detail.open {
|
||||
#bme-node-detail.open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
/* 移动端「图谱」Tab:节点详情居中悬浮窗 */
|
||||
#bme-mobile-node-detail {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
right: auto;
|
||||
width: min(400px, calc(100% - 24px));
|
||||
max-height: min(78vh, 640px);
|
||||
height: auto;
|
||||
background: var(--bme-surface-container);
|
||||
border: 1px solid var(--bme-border);
|
||||
border-radius: 14px;
|
||||
padding: 12px;
|
||||
overflow-y: auto;
|
||||
box-shadow: 0 20px 48px rgba(0, 0, 0, 0.5);
|
||||
transform: translate(-50%, -48%) scale(0.96);
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
transition:
|
||||
opacity 0.22s ease,
|
||||
transform 0.22s ease,
|
||||
visibility 0.22s;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
#bme-mobile-node-detail.open {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.bme-node-detail-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -3848,13 +3912,149 @@
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* 移动端图谱预览 - 桌面端默认隐藏 */
|
||||
/* 移动端图谱预览 - 桌面端默认隐藏(旧组件已移除) */
|
||||
.bme-mobile-graph-preview,
|
||||
.bme-mobile-graph-status,
|
||||
.bme-mobile-graph-section {
|
||||
.bme-mobile-graph-status {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* --- Graph Sub-Tabs (Mobile Graph Pane) --- */
|
||||
|
||||
.bme-graph-subtabs {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
padding: 10px 12px 6px;
|
||||
background: var(--bme-surface-container);
|
||||
border-bottom: 1px solid var(--bme-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.bme-graph-subtab {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
padding: 7px 10px;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
color: var(--bme-on-surface-dim);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bme-graph-subtab i {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.bme-graph-subtab:hover {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
color: var(--bme-on-surface);
|
||||
}
|
||||
|
||||
.bme-graph-subtab.active {
|
||||
background: var(--bme-primary);
|
||||
color: #fff;
|
||||
box-shadow: 0 2px 8px rgba(233, 69, 96, 0.35);
|
||||
}
|
||||
|
||||
.bme-graph-view-content {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bme-mobile-graph-pane {
|
||||
display: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.bme-mobile-graph-pane.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.bme-mobile-canvas-wrap {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.bme-mobile-canvas-wrap canvas {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.bme-mobile-graph-float-controls {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.bme-mobile-graph-float-controls button {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
background: rgba(10, 10, 15, 0.65);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
color: var(--bme-on-surface);
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
.bme-mobile-graph-float-controls button:hover {
|
||||
background: rgba(233, 69, 96, 0.25);
|
||||
border-color: var(--bme-primary);
|
||||
color: var(--bme-primary);
|
||||
}
|
||||
|
||||
/* Graph pane layout */
|
||||
#bme-pane-graph {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#bme-pane-graph.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#bme-pane-graph .bme-graph-legend {
|
||||
flex-shrink: 0;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
#bme-pane-graph .bme-graph-statusbar {
|
||||
flex-shrink: 0;
|
||||
padding: 4px 12px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
#bme-pane-graph .bme-cognition-workspace {
|
||||
padding: 12px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* ═══════ ⑤ 高级设置折叠 (desktop+mobile) ═══════ */
|
||||
|
||||
.bme-advanced-settings {
|
||||
@@ -3954,29 +4154,21 @@
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
/* ⑥ 图谱 tab 移动端全屏覆盖 */
|
||||
.bme-panel-main.mobile-visible {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 20;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.bme-panel-main.mobile-visible ~ .bme-panel-tabbar {
|
||||
z-index: 21;
|
||||
}
|
||||
|
||||
/* ② 底部 Tabbar safe-area + 触控增大 */
|
||||
/* ② 底部 Tabbar safe-area + 6 列 icon-only */
|
||||
.bme-panel-tabbar {
|
||||
display: flex;
|
||||
padding-bottom: env(safe-area-inset-bottom, 0px);
|
||||
}
|
||||
|
||||
.bme-panel-tabbar .bme-tab-btn {
|
||||
min-height: 52px;
|
||||
gap: 3px;
|
||||
font-size: 10px;
|
||||
min-height: 44px;
|
||||
gap: 2px;
|
||||
font-size: 0;
|
||||
padding: 6px 2px;
|
||||
}
|
||||
|
||||
.bme-panel-tabbar .bme-tab-btn span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.bme-panel-tabbar .bme-tab-btn i {
|
||||
@@ -4289,9 +4481,10 @@
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
/* 节点详情移动端全宽 */
|
||||
.bme-node-detail {
|
||||
width: 100%;
|
||||
/* 移动端图谱内悬浮窗略收窄(桌面 #bme-node-detail 在窄屏下不可见) */
|
||||
#bme-mobile-node-detail {
|
||||
width: min(400px, calc(100% - 16px));
|
||||
max-height: min(82vh, 680px);
|
||||
}
|
||||
|
||||
/* 图例 */
|
||||
@@ -4299,88 +4492,6 @@
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
/* 移动端图谱区重设计 */
|
||||
.bme-mobile-graph-section {
|
||||
display: block;
|
||||
margin: 12px 0 0;
|
||||
border: 1px solid var(--bme-border);
|
||||
border-radius: 12px;
|
||||
background: var(--bme-surface-lowest);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bme-mobile-graph-tabs {
|
||||
display: flex;
|
||||
border-bottom: 1px solid var(--bme-border);
|
||||
}
|
||||
|
||||
.bme-mobile-graph-tab {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
padding: 10px 8px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--bme-on-surface-dim);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bme-mobile-graph-tab:hover {
|
||||
color: var(--bme-on-surface);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
|
||||
.bme-mobile-graph-tab.active {
|
||||
color: var(--bme-primary);
|
||||
}
|
||||
|
||||
.bme-mobile-graph-tab.active::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 20%;
|
||||
right: 20%;
|
||||
height: 2px;
|
||||
background: var(--bme-primary);
|
||||
border-radius: 2px 2px 0 0;
|
||||
}
|
||||
|
||||
.bme-mobile-view-pane {
|
||||
display: none;
|
||||
padding: 12px;
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.bme-mobile-view-pane.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.bme-mobile-fullscreen-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: none;
|
||||
border-top: 1px solid var(--bme-border);
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
color: var(--bme-primary);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
|
||||
.bme-mobile-fullscreen-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══════ Help Tip (? 图标 + 气泡) ═══════ */
|
||||
|
||||
@@ -205,6 +205,8 @@ export class GraphRenderer {
|
||||
this.isDragging = false;
|
||||
this.isPanning = false;
|
||||
this.lastMouse = { x: 0, y: 0 };
|
||||
/** @type {{ startX: number, startY: number, lastX: number, lastY: number, nodeCandidate: object|null, moved: boolean } | null} */
|
||||
this._touchSession = null;
|
||||
|
||||
this.animId = null;
|
||||
|
||||
@@ -771,19 +773,55 @@ export class GraphRenderer {
|
||||
c.addEventListener('wheel', (e) => this._onWheel(e), { passive: false });
|
||||
c.addEventListener('dblclick', (e) => this._onDoubleClick(e));
|
||||
|
||||
// 触摸:单指始终平移画布,松手时在未移动过的情况下视为「点击」选中节点(避免拖动画布时误拖节点)
|
||||
c.addEventListener('touchstart', (e) => {
|
||||
if (e.touches.length === 1) {
|
||||
const t = e.touches[0];
|
||||
this._onMouseDown({ clientX: t.clientX, clientY: t.clientY, button: 0 });
|
||||
if (e.touches.length !== 1) {
|
||||
this._touchSession = null;
|
||||
return;
|
||||
}
|
||||
}, { passive: true });
|
||||
e.preventDefault();
|
||||
const t = e.touches[0];
|
||||
const { x, y } = this._canvasToWorld(t.clientX, t.clientY);
|
||||
this._touchSession = {
|
||||
startX: t.clientX,
|
||||
startY: t.clientY,
|
||||
lastX: t.clientX,
|
||||
lastY: t.clientY,
|
||||
nodeCandidate: this._findNodeAt(x, y),
|
||||
moved: false,
|
||||
};
|
||||
}, { passive: false });
|
||||
c.addEventListener('touchmove', (e) => {
|
||||
if (e.touches.length === 1) {
|
||||
const t = e.touches[0];
|
||||
this._onMouseMove({ clientX: t.clientX, clientY: t.clientY });
|
||||
if (!this._touchSession || e.touches.length !== 1) return;
|
||||
e.preventDefault();
|
||||
const t = e.touches[0];
|
||||
const dx = t.clientX - this._touchSession.lastX;
|
||||
const dy = t.clientY - this._touchSession.lastY;
|
||||
const fromStartX = t.clientX - this._touchSession.startX;
|
||||
const fromStartY = t.clientY - this._touchSession.startY;
|
||||
if (Math.abs(fromStartX) > 5 || Math.abs(fromStartY) > 5) {
|
||||
this._touchSession.moved = true;
|
||||
}
|
||||
}, { passive: true });
|
||||
c.addEventListener('touchend', () => this._onMouseUp({}));
|
||||
this.offsetX += dx;
|
||||
this.offsetY += dy;
|
||||
this._touchSession.lastX = t.clientX;
|
||||
this._touchSession.lastY = t.clientY;
|
||||
this._render();
|
||||
}, { passive: false });
|
||||
c.addEventListener('touchend', (e) => {
|
||||
if (!this._touchSession) return;
|
||||
const sess = this._touchSession;
|
||||
this._touchSession = null;
|
||||
if (!sess.moved && sess.nodeCandidate) {
|
||||
this.selectedNode = sess.nodeCandidate;
|
||||
if (this.onNodeSelect) this.onNodeSelect(sess.nodeCandidate);
|
||||
if (this.onNodeClick) this.onNodeClick(sess.nodeCandidate);
|
||||
this._render();
|
||||
}
|
||||
});
|
||||
c.addEventListener('touchcancel', () => {
|
||||
this._touchSession = null;
|
||||
});
|
||||
}
|
||||
|
||||
_canvasToWorld(clientX, clientY) {
|
||||
|
||||
118
ui/panel.html
118
ui/panel.html
@@ -250,22 +250,6 @@
|
||||
<ul class="bme-recent-list" id="bme-ai-monitor-list"></ul>
|
||||
</div>
|
||||
|
||||
<div class="bme-mobile-graph-section" id="bme-mobile-graph-section">
|
||||
<div class="bme-mobile-graph-tabs">
|
||||
<button class="bme-mobile-graph-tab active" data-mobile-view="summary" type="button">
|
||||
<i class="fa-solid fa-chart-pie"></i> 图谱摘要
|
||||
</button>
|
||||
<button class="bme-mobile-graph-tab" data-mobile-view="cognition" type="button">
|
||||
<i class="fa-solid fa-brain"></i> 认知视图
|
||||
</button>
|
||||
</div>
|
||||
<div class="bme-mobile-view-pane active" id="bme-mobile-summary-pane" data-mobile-view="summary"></div>
|
||||
<div class="bme-mobile-view-pane" id="bme-mobile-cognition-pane" data-mobile-view="cognition"></div>
|
||||
<button class="bme-mobile-fullscreen-btn" id="bme-mobile-open-fullscreen" type="button">
|
||||
<i class="fa-solid fa-expand"></i> 打开全屏图谱
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="bme-section-header">最近提取</div>
|
||||
<ul class="bme-recent-list" id="bme-recent-extract"></ul>
|
||||
|
||||
@@ -483,6 +467,104 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bme-tab-pane" id="bme-pane-graph">
|
||||
<div class="bme-graph-subtabs">
|
||||
<button class="bme-graph-subtab active" data-mobile-graph-view="graph" type="button">
|
||||
<i class="fa-solid fa-diagram-project"></i>
|
||||
<span>实时图谱</span>
|
||||
</button>
|
||||
<button class="bme-graph-subtab" data-mobile-graph-view="cognition" type="button">
|
||||
<i class="fa-solid fa-brain"></i>
|
||||
<span>认知视图</span>
|
||||
</button>
|
||||
<button class="bme-graph-subtab" data-mobile-graph-view="summary" type="button">
|
||||
<i class="fa-solid fa-layer-group"></i>
|
||||
<span>总结视图</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="bme-graph-view-content">
|
||||
<div class="bme-mobile-graph-pane active" id="bme-mobile-graph-pane" data-mobile-graph-view="graph">
|
||||
<div class="bme-mobile-canvas-wrap">
|
||||
<canvas id="bme-mobile-graph-canvas"></canvas>
|
||||
<div class="bme-graph-overlay" id="bme-mobile-graph-overlay" hidden>
|
||||
<div class="bme-graph-overlay__text" id="bme-mobile-graph-overlay-text">
|
||||
正在加载当前聊天图谱
|
||||
</div>
|
||||
</div>
|
||||
<div class="bme-mobile-graph-float-controls">
|
||||
<button id="bme-mobile-zoom-in" title="放大" type="button">
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
</button>
|
||||
<button id="bme-mobile-zoom-out" title="缩小" type="button">
|
||||
<i class="fa-solid fa-minus"></i>
|
||||
</button>
|
||||
<button id="bme-mobile-zoom-reset" title="重置" type="button">
|
||||
<i class="fa-solid fa-arrows-rotate"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bme-graph-legend" id="bme-mobile-graph-legend"></div>
|
||||
<div class="bme-graph-statusbar">
|
||||
<span><span class="bme-status-dot"></span><span id="bme-mobile-status-text">READY</span></span>
|
||||
<span id="bme-mobile-status-meta">NODES: 0 | EDGES: 0</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bme-mobile-graph-pane" id="bme-mobile-cognition-pane" data-mobile-graph-view="cognition">
|
||||
<div class="bme-cognition-workspace" id="bme-mobile-cognition-full">
|
||||
<div class="bme-cog-status-strip" id="bme-mobile-cog-status-strip"></div>
|
||||
<div class="bme-cog-body">
|
||||
<div class="bme-cog-column bme-cog-column--owners">
|
||||
<div class="bme-cog-section-title">
|
||||
<i class="fa-solid fa-users"></i> 角色认知清单
|
||||
</div>
|
||||
<div class="bme-cog-owner-scroll" id="bme-mobile-cog-owner-list"></div>
|
||||
<div class="bme-cog-owner-detail" id="bme-mobile-cog-owner-detail"></div>
|
||||
</div>
|
||||
<div class="bme-cog-column bme-cog-column--space">
|
||||
<div class="bme-cog-section-title">
|
||||
<i class="fa-solid fa-map-location-dot"></i> 空间控制台
|
||||
</div>
|
||||
<div class="bme-cog-space-tools" id="bme-mobile-cog-space-tools"></div>
|
||||
<div class="bme-cog-section-title" style="margin-top:16px">
|
||||
<i class="fa-solid fa-wave-square"></i> 任务监视器
|
||||
</div>
|
||||
<div class="bme-cog-monitor-mini" id="bme-mobile-cog-monitor-mini"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bme-mobile-graph-pane" id="bme-mobile-summary-pane-full" data-mobile-graph-view="summary">
|
||||
<div class="bme-cognition-workspace" id="bme-mobile-summary-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bme-node-detail-scrim"
|
||||
id="bme-mobile-node-detail-scrim"
|
||||
hidden
|
||||
></div>
|
||||
<div class="bme-node-detail" id="bme-mobile-node-detail">
|
||||
<div class="bme-node-detail-header">
|
||||
<h3 id="bme-mobile-detail-title">节点详情</h3>
|
||||
<div class="bme-node-detail-actions">
|
||||
<button class="bme-detail-action-btn bme-detail-action-danger" id="bme-mobile-detail-delete" type="button" title="删除节点">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
<button class="bme-detail-action-btn" id="bme-mobile-detail-save" type="button" title="保存修改">
|
||||
<i class="fa-solid fa-floppy-disk"></i>
|
||||
</button>
|
||||
<button class="bme-panel-close" id="bme-mobile-detail-close" type="button" title="关闭">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="bme-mobile-detail-body"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2775,6 +2857,10 @@
|
||||
</div>
|
||||
|
||||
<div class="bme-panel-tabbar">
|
||||
<button class="bme-tab-btn" data-tab="graph" type="button">
|
||||
<i class="fa-solid fa-diagram-project"></i>
|
||||
<span>图谱</span>
|
||||
</button>
|
||||
<button class="bme-tab-btn active" data-tab="dashboard" type="button">
|
||||
<i class="fa-solid fa-chart-simple"></i>
|
||||
<span>总览</span>
|
||||
|
||||
363
ui/panel.js
363
ui/panel.js
@@ -286,6 +286,7 @@ let showGlobalRegexPanel = false;
|
||||
let currentGlobalRegexRuleId = "";
|
||||
let currentCognitionOwnerKey = "";
|
||||
let currentGraphView = "graph";
|
||||
let currentMobileGraphView = "graph";
|
||||
let fetchedMemoryLLMModels = [];
|
||||
let fetchedBackendEmbeddingModels = [];
|
||||
let fetchedDirectEmbeddingModels = [];
|
||||
@@ -630,6 +631,9 @@ function bindViewportSync() {
|
||||
const update = () => {
|
||||
syncViewportCssVars();
|
||||
syncFabPosition();
|
||||
if (!_isMobile() && currentTabId === "graph") {
|
||||
_switchTab("dashboard");
|
||||
}
|
||||
};
|
||||
window.addEventListener("resize", update);
|
||||
window.addEventListener("orientationchange", update);
|
||||
@@ -1000,7 +1004,13 @@ function _bindTabs() {
|
||||
}
|
||||
|
||||
function _switchTab(tabId) {
|
||||
currentTabId = tabId || "dashboard";
|
||||
let next = tabId || "dashboard";
|
||||
// 「图谱」仅移动端底部 Tab 可用;桌面端图谱在右侧主工作区,侧栏不设该 Tab
|
||||
if (!_isMobile() && next === "graph") {
|
||||
next = "dashboard";
|
||||
}
|
||||
currentTabId = next;
|
||||
_closeNodeDetailUi();
|
||||
panelEl?.querySelectorAll(".bme-tab-btn").forEach((btn) => {
|
||||
btn.classList.toggle("active", btn.dataset.tab === currentTabId);
|
||||
});
|
||||
@@ -1009,12 +1019,6 @@ function _switchTab(tabId) {
|
||||
pane.classList.toggle("active", pane.id === `bme-pane-${currentTabId}`);
|
||||
});
|
||||
|
||||
// ⑥ 移动端图谱 tab 全屏覆盖
|
||||
const mainEl = panelEl?.querySelector(".bme-panel-main");
|
||||
if (mainEl) {
|
||||
mainEl.classList.toggle("mobile-visible", currentTabId === "graph");
|
||||
}
|
||||
|
||||
_applyWorkspaceMode();
|
||||
|
||||
switch (currentTabId) {
|
||||
@@ -1030,6 +1034,9 @@ function _switchTab(tabId) {
|
||||
case "config":
|
||||
_refreshConfigTab();
|
||||
break;
|
||||
case "graph":
|
||||
_refreshMobileGraphTab();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1102,6 +1109,9 @@ function _switchGraphView(view) {
|
||||
if (legend) legend.style.display = isGraph ? "" : "none";
|
||||
if (statusbar) statusbar.style.display = isGraph ? "" : "none";
|
||||
if (nodeDetail) nodeDetail.style.display = isGraph ? "" : "none";
|
||||
if (!isGraph) {
|
||||
nodeDetail?.classList.remove("open");
|
||||
}
|
||||
if (graphControls) graphControls.style.display = isGraph ? "" : "none";
|
||||
if (cogWorkspace) cogWorkspace.hidden = !isCognition;
|
||||
if (summaryWorkspace) summaryWorkspace.hidden = !isSummary;
|
||||
@@ -1112,6 +1122,67 @@ function _switchGraphView(view) {
|
||||
if (isSummary) _refreshSummaryWorkspace();
|
||||
}
|
||||
|
||||
// ==================== 移动端图谱 Tab ====================
|
||||
|
||||
function _switchMobileGraphSubView(view) {
|
||||
currentMobileGraphView = view || "graph";
|
||||
const pane = document.getElementById("bme-pane-graph");
|
||||
if (!pane) return;
|
||||
|
||||
pane.querySelectorAll(".bme-graph-subtab").forEach((tab) => {
|
||||
tab.classList.toggle("active", tab.dataset.mobileGraphView === currentMobileGraphView);
|
||||
});
|
||||
pane.querySelectorAll(".bme-mobile-graph-pane").forEach((p) => {
|
||||
p.classList.toggle("active", p.dataset.mobileGraphView === currentMobileGraphView);
|
||||
});
|
||||
|
||||
if (currentMobileGraphView !== "graph") {
|
||||
_closeNodeDetailUi();
|
||||
}
|
||||
|
||||
_refreshMobileGraphTab();
|
||||
}
|
||||
|
||||
function _refreshMobileGraphTab() {
|
||||
if (currentMobileGraphView === "graph") {
|
||||
_refreshGraph();
|
||||
_buildMobileLegend();
|
||||
} else if (currentMobileGraphView === "cognition") {
|
||||
_refreshMobileCognitionFull();
|
||||
} else if (currentMobileGraphView === "summary") {
|
||||
_refreshMobileSummaryFull();
|
||||
}
|
||||
}
|
||||
|
||||
function _buildMobileLegend() {
|
||||
const legend = document.getElementById("bme-mobile-graph-legend");
|
||||
if (!legend) return;
|
||||
const desktopLegend = document.getElementById("bme-graph-legend");
|
||||
if (desktopLegend) {
|
||||
legend.innerHTML = desktopLegend.innerHTML;
|
||||
}
|
||||
}
|
||||
|
||||
function _refreshMobileCognitionFull() {
|
||||
const graph = _getGraph?.();
|
||||
const loadInfo = _getGraphPersistenceSnapshot();
|
||||
if (!graph) return;
|
||||
|
||||
const canRender =
|
||||
Boolean(graph) &&
|
||||
(_canRenderGraphData(loadInfo) || loadInfo.loadState === "empty-confirmed");
|
||||
|
||||
_renderCogStatusStrip(graph, loadInfo, canRender, document.getElementById("bme-mobile-cog-status-strip"));
|
||||
_renderCogOwnerList(graph, canRender, document.getElementById("bme-mobile-cog-owner-list"));
|
||||
_renderCogOwnerDetail(graph, loadInfo, canRender, document.getElementById("bme-mobile-cog-owner-detail"));
|
||||
_renderCogSpaceTools(graph, loadInfo, canRender, document.getElementById("bme-mobile-cog-space-tools"));
|
||||
_renderCogMonitorMini(document.getElementById("bme-mobile-cog-monitor-mini"));
|
||||
}
|
||||
|
||||
function _refreshMobileSummaryFull() {
|
||||
_refreshSummaryWorkspace(document.getElementById("bme-mobile-summary-full"));
|
||||
}
|
||||
|
||||
function _ownerAvatarHsl(name) {
|
||||
let hash = 0;
|
||||
const str = String(name || "");
|
||||
@@ -1232,8 +1303,8 @@ function _refreshCognitionWorkspace() {
|
||||
_renderCogMonitorMini();
|
||||
}
|
||||
|
||||
function _renderCogStatusStrip(graph, loadInfo, canRender) {
|
||||
const el = document.getElementById("bme-cog-status-strip");
|
||||
function _renderCogStatusStrip(graph, loadInfo, canRender, targetEl) {
|
||||
const el = targetEl || document.getElementById("bme-cog-status-strip");
|
||||
if (!el) return;
|
||||
|
||||
if (!canRender) {
|
||||
@@ -1305,8 +1376,8 @@ function _renderCogStatusStrip(graph, loadInfo, canRender) {
|
||||
`;
|
||||
}
|
||||
|
||||
function _renderCogOwnerList(graph, canRender) {
|
||||
const el = document.getElementById("bme-cog-owner-list");
|
||||
function _renderCogOwnerList(graph, canRender, targetEl) {
|
||||
const el = targetEl || document.getElementById("bme-cog-owner-list");
|
||||
if (!el) return;
|
||||
|
||||
if (!canRender) {
|
||||
@@ -1351,8 +1422,8 @@ function _renderCogOwnerList(graph, canRender) {
|
||||
.join("");
|
||||
}
|
||||
|
||||
function _renderCogOwnerDetail(graph, loadInfo, canRender) {
|
||||
const el = document.getElementById("bme-cog-owner-detail");
|
||||
function _renderCogOwnerDetail(graph, loadInfo, canRender, targetEl) {
|
||||
const el = targetEl || document.getElementById("bme-cog-owner-detail");
|
||||
if (!el) return;
|
||||
|
||||
if (!canRender) {
|
||||
@@ -1480,8 +1551,8 @@ function _renderCogOwnerDetail(graph, loadInfo, canRender) {
|
||||
`;
|
||||
}
|
||||
|
||||
function _renderCogSpaceTools(graph, loadInfo, canRender) {
|
||||
const el = document.getElementById("bme-cog-space-tools");
|
||||
function _renderCogSpaceTools(graph, loadInfo, canRender, targetEl) {
|
||||
const el = targetEl || document.getElementById("bme-cog-space-tools");
|
||||
if (!el) return;
|
||||
|
||||
if (!canRender) { el.innerHTML = ""; return; }
|
||||
@@ -1541,8 +1612,8 @@ function _renderCogSpaceTools(graph, loadInfo, canRender) {
|
||||
`;
|
||||
}
|
||||
|
||||
function _renderCogMonitorMini() {
|
||||
const el = document.getElementById("bme-cog-monitor-mini");
|
||||
function _renderCogMonitorMini(targetEl) {
|
||||
const el = targetEl || document.getElementById("bme-cog-monitor-mini");
|
||||
if (!el) return;
|
||||
|
||||
const settings = _getSettings?.() || {};
|
||||
@@ -1586,141 +1657,6 @@ function _renderCogMonitorMini() {
|
||||
.join("");
|
||||
}
|
||||
|
||||
// ==================== 移动端图谱视图 ====================
|
||||
|
||||
function _switchMobileGraphView(view) {
|
||||
const section = document.getElementById("bme-mobile-graph-section");
|
||||
if (!section) return;
|
||||
|
||||
section.querySelectorAll(".bme-mobile-graph-tab").forEach((tab) => {
|
||||
tab.classList.toggle("active", tab.dataset.mobileView === view);
|
||||
});
|
||||
section.querySelectorAll(".bme-mobile-view-pane").forEach((pane) => {
|
||||
pane.classList.toggle("active", pane.dataset.mobileView === view);
|
||||
});
|
||||
|
||||
if (view === "summary") _refreshMobileSummary();
|
||||
if (view === "cognition") _refreshMobileCognition();
|
||||
}
|
||||
|
||||
function _refreshMobileSummary() {
|
||||
const el = document.getElementById("bme-mobile-summary-pane");
|
||||
if (!el) return;
|
||||
|
||||
const graph = _getGraph?.();
|
||||
const loadInfo = _getGraphPersistenceSnapshot();
|
||||
if (!graph || !_canRenderGraphData(loadInfo)) {
|
||||
el.innerHTML = `<div class="bme-cog-monitor-empty">${_escHtml(_getGraphLoadLabel(loadInfo?.loadState))}</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
const activeNodes = graph.nodes.filter((n) => !n.archived);
|
||||
const archivedCount = graph.nodes.filter((n) => n.archived).length;
|
||||
const typeMap = {};
|
||||
for (const node of activeNodes) {
|
||||
const t = String(node.type || "unknown");
|
||||
typeMap[t] = (typeMap[t] || 0) + 1;
|
||||
}
|
||||
const typePills = Object.entries(typeMap)
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.slice(0, 5)
|
||||
.map(([type, count]) => `<span class="bme-cog-chip">${_escHtml(type)} ${count}</span>`)
|
||||
.join("");
|
||||
|
||||
const recentNodes = [...activeNodes]
|
||||
.sort((a, b) => (Number(b.seqRange?.[1] || b.seqRange?.[0] || 0)) - (Number(a.seqRange?.[1] || a.seqRange?.[0] || 0)))
|
||||
.slice(0, 5);
|
||||
const recentHtml = recentNodes.map((n) => {
|
||||
const name = getNodeDisplayName(n);
|
||||
const type = String(n.type || "");
|
||||
return `<div class="bme-cog-monitor-entry is-success" style="border-left-color:var(--bme-primary)">
|
||||
<span class="bme-cog-monitor-badge">${_escHtml(type)}</span>
|
||||
<span class="bme-cog-monitor-info">${_escHtml(name)}</span>
|
||||
</div>`;
|
||||
}).join("");
|
||||
|
||||
el.innerHTML = `
|
||||
<div class="bme-cog-status-strip" style="grid-template-columns:repeat(3,1fr);margin-bottom:10px">
|
||||
<div class="bme-cog-status-card"><div class="bme-cog-status-card__label">活跃</div><div class="bme-cog-status-card__value">${activeNodes.length}</div></div>
|
||||
<div class="bme-cog-status-card"><div class="bme-cog-status-card__label">边</div><div class="bme-cog-status-card__value">${graph.edges.length}</div></div>
|
||||
<div class="bme-cog-status-card"><div class="bme-cog-status-card__label">归档</div><div class="bme-cog-status-card__value">${archivedCount}</div></div>
|
||||
</div>
|
||||
<div class="bme-cog-chip-section" style="margin-bottom:10px">
|
||||
<div class="bme-cog-chip-label">类型分布</div>
|
||||
<div class="bme-cog-chip-wrap">${typePills || '<span class="bme-cog-chip is-empty">暂无</span>'}</div>
|
||||
</div>
|
||||
<div class="bme-cog-chip-label" style="margin-bottom:6px">最近节点</div>
|
||||
<div class="bme-cog-monitor-mini">${recentHtml || '<div class="bme-cog-monitor-empty">暂无</div>'}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function _refreshMobileCognition() {
|
||||
const el = document.getElementById("bme-mobile-cognition-pane");
|
||||
if (!el) return;
|
||||
|
||||
const graph = _getGraph?.();
|
||||
const loadInfo = _getGraphPersistenceSnapshot();
|
||||
if (!graph) { el.innerHTML = ""; return; }
|
||||
|
||||
const canRender =
|
||||
Boolean(graph) &&
|
||||
(_canRenderGraphData(loadInfo) || loadInfo.loadState === "empty-confirmed");
|
||||
|
||||
if (!canRender) {
|
||||
el.innerHTML = `<div class="bme-cog-monitor-empty">${_escHtml(_getGraphLoadLabel(loadInfo.loadState))}</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
const { owners, activeOwnerKey, activeOwner, activeOwnerKeys, activeOwnerLabels } =
|
||||
_getCurrentCognitionOwnerSummary(graph);
|
||||
const collisionIndex = _buildOwnerCollisionIndex(owners);
|
||||
const historyState = graph?.historyState || {};
|
||||
const regionState = graph?.regionState || {};
|
||||
const activeRegion = String(historyState.activeRegion || historyState.lastExtractedRegion || regionState.manualActiveRegion || "").trim();
|
||||
const adjacentRegions = Array.isArray(regionState?.adjacencyMap?.[activeRegion]?.adjacent)
|
||||
? regionState.adjacencyMap[activeRegion].adjacent : [];
|
||||
|
||||
const ownerCards = owners.map((owner) => {
|
||||
const displayInfo = _getOwnerDisplayInfo(owner, collisionIndex);
|
||||
const bgColor = _ownerAvatarHsl(displayInfo.avatarSeed);
|
||||
const anchor =
|
||||
owner.ownerKey === activeOwnerKey || activeOwnerKeys.includes(owner.ownerKey)
|
||||
? "is-active-anchor"
|
||||
: "";
|
||||
return `
|
||||
<div class="bme-cog-owner-card ${anchor}" style="min-width:unset;max-width:unset" title="${_escHtml(displayInfo.tooltip)}">
|
||||
<div class="bme-cog-avatar" style="background:${bgColor}">${_escHtml(displayInfo.avatarText)}</div>
|
||||
<div class="bme-cog-owner-card__info">
|
||||
<div class="bme-cog-owner-card__name-row">
|
||||
<div class="bme-cog-owner-card__name">${_escHtml(displayInfo.title)}</div>
|
||||
<span class="bme-cog-owner-card__badge">${_escHtml(displayInfo.typeLabel)}</span>
|
||||
</div>
|
||||
<div class="bme-cog-owner-card__stats">已知 ${Number(owner.knownCount || 0)} · 误解 ${Number(owner.mistakenCount || 0)}</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}).join("");
|
||||
|
||||
el.innerHTML = `
|
||||
<div class="bme-cog-status-strip" style="grid-template-columns:repeat(2,1fr);margin-bottom:10px">
|
||||
<div class="bme-cog-status-card">
|
||||
<div class="bme-cog-status-card__label"><i class="fa-solid fa-user"></i> 场景锚点</div>
|
||||
<div class="bme-cog-status-card__value">${_escHtml(
|
||||
activeOwnerLabels.length > 0
|
||||
? activeOwnerLabels.join(" / ")
|
||||
: activeOwner
|
||||
? _getOwnerDisplayInfo(activeOwner, collisionIndex).title
|
||||
: "—",
|
||||
)}</div>
|
||||
</div>
|
||||
<div class="bme-cog-status-card">
|
||||
<div class="bme-cog-status-card__label"><i class="fa-solid fa-location-dot"></i> 当前地区</div>
|
||||
<div class="bme-cog-status-card__value">${_escHtml(activeRegion || "—")}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bme-cog-chip-label" style="margin-bottom:6px">认知角色 (${owners.length})</div>
|
||||
<div style="display:flex;flex-direction:column;gap:6px">${ownerCards || '<div class="bme-cog-monitor-empty">暂无</div>'}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function _formatSummaryEntryCard(entry = {}) {
|
||||
const messageRange = Array.isArray(entry?.dialogueRange)
|
||||
@@ -1766,10 +1702,10 @@ function _formatSummaryEntryCard(entry = {}) {
|
||||
`;
|
||||
}
|
||||
|
||||
function _refreshSummaryWorkspace() {
|
||||
function _refreshSummaryWorkspace(targetEl) {
|
||||
const graph = _getGraph?.();
|
||||
const loadInfo = _getGraphPersistenceSnapshot();
|
||||
const workspace = document.getElementById("bme-summary-workspace");
|
||||
const workspace = targetEl || document.getElementById("bme-summary-workspace");
|
||||
if (!workspace) return;
|
||||
|
||||
if (!graph || !_canRenderGraphData(loadInfo)) {
|
||||
@@ -1977,7 +1913,6 @@ function _refreshDashboard() {
|
||||
|
||||
_refreshCognitionDashboard(graph);
|
||||
_refreshAiMonitorDashboard();
|
||||
_refreshMobileSummary();
|
||||
_renderRecentList("bme-recent-extract", _getLastExtract?.() || []);
|
||||
_renderRecentList("bme-recent-recall", _getLastRecall?.() || []);
|
||||
}
|
||||
@@ -2012,7 +1947,9 @@ function _setInputValueIfIdle(elementId, value = "") {
|
||||
|
||||
function _getSelectedGraphNode(graph = _getGraph?.()) {
|
||||
const detailNodeId = String(
|
||||
document.getElementById("bme-node-detail")?.dataset?.editNodeId || "",
|
||||
document.getElementById("bme-node-detail")?.dataset?.editNodeId ||
|
||||
document.getElementById("bme-mobile-node-detail")?.dataset?.editNodeId ||
|
||||
"",
|
||||
).trim();
|
||||
const rendererNodeId = String(
|
||||
_getActiveGraphRenderer()?.selectedNode?.id || "",
|
||||
@@ -3019,6 +2956,9 @@ function _refreshGraph() {
|
||||
} else if (currentGraphView === "summary") {
|
||||
_refreshSummaryWorkspace();
|
||||
}
|
||||
if (currentTabId === "graph") {
|
||||
_refreshMobileGraphTab();
|
||||
}
|
||||
}
|
||||
|
||||
function _buildLegend() {
|
||||
@@ -3175,11 +3115,45 @@ function _appendNodeDetailTextareaField(
|
||||
container.appendChild(row);
|
||||
}
|
||||
|
||||
function _useMobileGraphNodeDetail() {
|
||||
return _isMobile() && currentTabId === "graph";
|
||||
}
|
||||
|
||||
function _getNodeDetailEls() {
|
||||
const mobile = _useMobileGraphNodeDetail();
|
||||
const detailEl = document.getElementById(
|
||||
mobile ? "bme-mobile-node-detail" : "bme-node-detail",
|
||||
);
|
||||
const titleEl = document.getElementById(
|
||||
mobile ? "bme-mobile-detail-title" : "bme-detail-title",
|
||||
);
|
||||
const bodyEl = document.getElementById(
|
||||
mobile ? "bme-mobile-detail-body" : "bme-detail-body",
|
||||
);
|
||||
const scrimEl = mobile
|
||||
? document.getElementById("bme-mobile-node-detail-scrim")
|
||||
: null;
|
||||
if (!detailEl || !titleEl || !bodyEl) return null;
|
||||
return { detailEl, titleEl, bodyEl, scrimEl, mobile };
|
||||
}
|
||||
|
||||
function _closeNodeDetailUi() {
|
||||
document.getElementById("bme-node-detail")?.classList.remove("open");
|
||||
document.getElementById("bme-mobile-node-detail")?.classList.remove("open");
|
||||
document.getElementById("bme-mobile-node-detail-scrim")?.setAttribute("hidden", "");
|
||||
}
|
||||
|
||||
function _showNodeDetail(node) {
|
||||
const detailEl = document.getElementById("bme-node-detail");
|
||||
const titleEl = document.getElementById("bme-detail-title");
|
||||
const bodyEl = document.getElementById("bme-detail-body");
|
||||
if (!detailEl || !titleEl || !bodyEl) return;
|
||||
const els = _getNodeDetailEls();
|
||||
if (!els) return;
|
||||
const { detailEl, titleEl, bodyEl, scrimEl, mobile } = els;
|
||||
|
||||
if (mobile) {
|
||||
document.getElementById("bme-node-detail")?.classList.remove("open");
|
||||
} else {
|
||||
document.getElementById("bme-mobile-node-detail")?.classList.remove("open");
|
||||
document.getElementById("bme-mobile-node-detail-scrim")?.setAttribute("hidden", "");
|
||||
}
|
||||
|
||||
const raw = node.raw || node;
|
||||
const fields = raw.fields || {};
|
||||
@@ -3300,12 +3274,16 @@ function _showNodeDetail(node) {
|
||||
}
|
||||
bodyEl.replaceChildren(fragment);
|
||||
|
||||
if (mobile) {
|
||||
scrimEl?.removeAttribute("hidden");
|
||||
}
|
||||
detailEl.classList.add("open");
|
||||
}
|
||||
|
||||
function _saveNodeDetail() {
|
||||
const detailEl = document.getElementById("bme-node-detail");
|
||||
const bodyEl = document.getElementById("bme-detail-body");
|
||||
const els = _getNodeDetailEls();
|
||||
const detailEl = els?.detailEl;
|
||||
const bodyEl = els?.bodyEl;
|
||||
const nodeId = detailEl?.dataset?.editNodeId;
|
||||
if (!nodeId || !bodyEl) return;
|
||||
if (_isGraphWriteBlocked()) {
|
||||
@@ -3425,10 +3403,21 @@ function _bindNodeDetailPanel() {
|
||||
deleteBtn.addEventListener("click", () => _deleteNodeDetail());
|
||||
deleteBtn.dataset.bmeBound = "true";
|
||||
}
|
||||
const saveMob = document.getElementById("bme-mobile-detail-save");
|
||||
if (saveMob && saveMob.dataset.bmeBound !== "true") {
|
||||
saveMob.addEventListener("click", () => _saveNodeDetail());
|
||||
saveMob.dataset.bmeBound = "true";
|
||||
}
|
||||
const delMob = document.getElementById("bme-mobile-detail-delete");
|
||||
if (delMob && delMob.dataset.bmeBound !== "true") {
|
||||
delMob.addEventListener("click", () => _deleteNodeDetail());
|
||||
delMob.dataset.bmeBound = "true";
|
||||
}
|
||||
}
|
||||
|
||||
function _deleteNodeDetail() {
|
||||
const detailEl = document.getElementById("bme-node-detail");
|
||||
const els = _getNodeDetailEls();
|
||||
const detailEl = els?.detailEl;
|
||||
const nodeId = detailEl?.dataset?.editNodeId;
|
||||
if (!nodeId) return;
|
||||
if (_isGraphWriteBlocked()) {
|
||||
@@ -3461,8 +3450,11 @@ function _deleteNodeDetail() {
|
||||
} else {
|
||||
toastr.success("节点已删除", "ST-BME");
|
||||
}
|
||||
detailEl?.classList.remove("open");
|
||||
if (detailEl) delete detailEl.dataset.editNodeId;
|
||||
_closeNodeDetailUi();
|
||||
const dDesk = document.getElementById("bme-node-detail");
|
||||
const dMob = document.getElementById("bme-mobile-node-detail");
|
||||
if (dDesk) delete dDesk.dataset.editNodeId;
|
||||
if (dMob) delete dMob.dataset.editNodeId;
|
||||
graphRenderer?.highlightNode?.("__cleared__");
|
||||
mobileGraphRenderer?.highlightNode?.("__cleared__");
|
||||
refreshLiveState();
|
||||
@@ -3473,7 +3465,13 @@ function _bindClose() {
|
||||
.getElementById("bme-panel-close")
|
||||
?.addEventListener("click", closePanel);
|
||||
document.getElementById("bme-detail-close")?.addEventListener("click", () => {
|
||||
document.getElementById("bme-node-detail")?.classList.remove("open");
|
||||
_closeNodeDetailUi();
|
||||
});
|
||||
document.getElementById("bme-mobile-detail-close")?.addEventListener("click", () => {
|
||||
_closeNodeDetailUi();
|
||||
});
|
||||
document.getElementById("bme-mobile-node-detail-scrim")?.addEventListener("click", () => {
|
||||
_closeNodeDetailUi();
|
||||
});
|
||||
overlayEl?.addEventListener("click", (event) => {
|
||||
if (event.target === overlayEl) closePanel();
|
||||
@@ -4058,18 +4056,31 @@ function _bindActions() {
|
||||
});
|
||||
});
|
||||
|
||||
// 移动端图谱/认知 tab 切换
|
||||
document.querySelectorAll(".bme-mobile-graph-tab").forEach((tab) => {
|
||||
// 移动端图谱子 Tab 切换
|
||||
document.querySelectorAll(".bme-graph-subtab").forEach((tab) => {
|
||||
tab.addEventListener("click", () => {
|
||||
_switchMobileGraphView(tab.dataset.mobileView);
|
||||
_switchMobileGraphSubView(tab.dataset.mobileGraphView);
|
||||
});
|
||||
});
|
||||
|
||||
// 移动端图谱浮动控件
|
||||
document.getElementById("bme-mobile-zoom-in")?.addEventListener("click", () => {
|
||||
const r = _getActiveGraphRenderer?.();
|
||||
r?.zoomIn?.();
|
||||
});
|
||||
document.getElementById("bme-mobile-zoom-out")?.addEventListener("click", () => {
|
||||
const r = _getActiveGraphRenderer?.();
|
||||
r?.zoomOut?.();
|
||||
});
|
||||
document.getElementById("bme-mobile-zoom-reset")?.addEventListener("click", () => {
|
||||
const r = _getActiveGraphRenderer?.();
|
||||
r?.resetView?.();
|
||||
});
|
||||
|
||||
// 全屏图谱
|
||||
document.getElementById("bme-mobile-open-fullscreen")?.addEventListener("click", _openFullscreenGraph);
|
||||
document.getElementById("bme-fs-close")?.addEventListener("click", _closeFullscreenGraph);
|
||||
|
||||
// 认知视图角色列表点击
|
||||
// 认知视图角色列表点击(桌面端)
|
||||
document.getElementById("bme-cog-owner-list")?.addEventListener("click", (e) => {
|
||||
const card = e.target.closest("[data-owner-key]");
|
||||
if (!card) return;
|
||||
@@ -4077,6 +4088,14 @@ function _bindActions() {
|
||||
_refreshCognitionWorkspace();
|
||||
});
|
||||
|
||||
// 认知视图角色列表点击(移动端)
|
||||
document.getElementById("bme-mobile-cog-owner-list")?.addEventListener("click", (e) => {
|
||||
const card = e.target.closest("[data-owner-key]");
|
||||
if (!card) return;
|
||||
currentCognitionOwnerKey = card.dataset.ownerKey;
|
||||
_refreshMobileCognitionFull();
|
||||
});
|
||||
|
||||
// Dashboard 跳转认知视图
|
||||
document.getElementById("bme-cognition-jump-to-view")?.addEventListener("click", () => {
|
||||
_switchTab("dashboard");
|
||||
@@ -9809,6 +9828,8 @@ function _refreshRuntimeStatus() {
|
||||
const meta = runtimeStatus.meta || "准备就绪";
|
||||
_setText("bme-status-text", text);
|
||||
_setText("bme-status-meta", meta);
|
||||
_setText("bme-mobile-status-text", text);
|
||||
_setText("bme-mobile-status-meta", meta);
|
||||
_setText("bme-panel-status", text);
|
||||
_renderCloudStorageModeStatus(_getSettings?.() || {}, _getGraphPersistenceSnapshot());
|
||||
_refreshGraphAvailabilityState();
|
||||
|
||||
Reference in New Issue
Block a user