mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 22:30:38 +08:00
feat(ui): add Cognitive View tab + mobile graph redesign + fullscreen overlay
- Desktop: graph toolbar title → dual tab switcher (实时图谱 | 认知视图) - Cognitive View: owners list with avatar, metrics grid, chip groups, manual override, space tools, AI Monitor mini - Mobile: replace unreadable 200px canvas preview with tabbed layout (图谱摘要 | 认知视图) - Mobile: add fullscreen graph overlay with zoom controls - Dashboard: simplify cognition card to KV summary + jump-to-view button - CSS: ~800 lines new styles for all components with responsive breakpoints - JS: 14 new render functions, event delegation, view switching logic
This commit is contained in:
828
style.css
828
style.css
@@ -636,6 +636,49 @@
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* --- Graph View Tab Switcher --- */
|
||||
.bme-graph-view-tabs {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.bme-graph-view-tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 5px 14px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
background: transparent;
|
||||
color: var(--bme-on-surface-dim);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.18s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bme-graph-view-tab:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: var(--bme-on-surface);
|
||||
}
|
||||
|
||||
.bme-graph-view-tab.active {
|
||||
color: var(--bme-primary);
|
||||
background: var(--bme-primary-dim);
|
||||
border-color: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.bme-graph-view-tab i {
|
||||
font-size: 11px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.bme-graph-view-tab.active i {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
.bme-graph-controls {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
@@ -3419,7 +3462,8 @@
|
||||
|
||||
/* 移动端图谱预览 - 桌面端默认隐藏 */
|
||||
.bme-mobile-graph-preview,
|
||||
.bme-mobile-graph-status {
|
||||
.bme-mobile-graph-status,
|
||||
.bme-mobile-graph-section {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -3857,40 +3901,87 @@
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
/* 移动端图谱预览 */
|
||||
.bme-mobile-graph-preview {
|
||||
/* 移动端图谱区重设计 */
|
||||
.bme-mobile-graph-section {
|
||||
display: block;
|
||||
height: 200px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
margin: 8px 0 0;
|
||||
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-preview canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.bme-mobile-graph-tab:hover {
|
||||
color: var(--bme-on-surface);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
|
||||
.bme-mobile-graph-label {
|
||||
.bme-mobile-graph-tab.active {
|
||||
color: var(--bme-primary);
|
||||
}
|
||||
|
||||
.bme-mobile-graph-tab.active::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 8px;
|
||||
font-size: 9px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
color: var(--bme-accent2);
|
||||
background: var(--bme-surface);
|
||||
padding: 1px 6px;
|
||||
border-radius: 3px;
|
||||
bottom: 0;
|
||||
left: 20%;
|
||||
right: 20%;
|
||||
height: 2px;
|
||||
background: var(--bme-primary);
|
||||
border-radius: 2px 2px 0 0;
|
||||
}
|
||||
|
||||
.bme-mobile-graph-status {
|
||||
.bme-mobile-view-pane {
|
||||
display: none;
|
||||
padding: 12px;
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.bme-mobile-view-pane.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.bme-mobile-fullscreen-btn {
|
||||
display: flex;
|
||||
margin-bottom: 12px;
|
||||
border-radius: 0 0 6px 6px;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4617,3 +4708,694 @@
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════
|
||||
Cognition Workspace (Desktop)
|
||||
═══════════════════════════════════════════════════════════ */
|
||||
|
||||
.bme-cognition-workspace {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 16px;
|
||||
background: var(--bme-surface-lowest);
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.bme-cog-status-strip {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.bme-cog-status-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding: 12px 14px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--bme-border);
|
||||
background: linear-gradient(135deg, rgba(255, 255, 255, 0.035), rgba(255, 255, 255, 0.015));
|
||||
}
|
||||
|
||||
.bme-cog-status-card__label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.03em;
|
||||
text-transform: uppercase;
|
||||
color: var(--bme-on-surface-dim);
|
||||
}
|
||||
|
||||
.bme-cog-status-card__label i {
|
||||
font-size: 10px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.bme-cog-status-card__value {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: var(--bme-on-surface);
|
||||
word-break: break-word;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.bme-cog-body {
|
||||
display: grid;
|
||||
grid-template-columns: 55% 1fr;
|
||||
gap: 16px;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.bme-cog-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.bme-cog-section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
color: var(--bme-on-surface-dim);
|
||||
}
|
||||
|
||||
.bme-cog-section-title i {
|
||||
font-size: 11px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* --- Owner List --- */
|
||||
.bme-cog-owner-scroll {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
overflow-x: auto;
|
||||
padding-bottom: 6px;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.bme-cog-owner-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-width: 160px;
|
||||
max-width: 200px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--bme-border);
|
||||
background: var(--bme-surface-lowest);
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.bme-cog-owner-card:hover {
|
||||
border-color: var(--bme-border-active);
|
||||
background: var(--bme-surface-high);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.bme-cog-owner-card.is-selected {
|
||||
border-color: var(--bme-primary);
|
||||
background: var(--bme-primary-dim);
|
||||
}
|
||||
|
||||
.bme-cog-owner-card.is-active-anchor::after {
|
||||
content: "";
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 50%;
|
||||
background: #4ade80;
|
||||
box-shadow: 0 0 6px rgba(74, 222, 128, 0.5);
|
||||
flex-shrink: 0;
|
||||
animation: bme-pulse-dot 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes bme-pulse-dot {
|
||||
0%, 100% { opacity: 1; transform: scale(1); }
|
||||
50% { opacity: 0.5; transform: scale(0.75); }
|
||||
}
|
||||
|
||||
.bme-cog-avatar {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
flex-shrink: 0;
|
||||
text-shadow: 0 1px 2px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.bme-cog-owner-card__info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.bme-cog-owner-card__name {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: var(--bme-on-surface);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.bme-cog-owner-card__stats {
|
||||
font-size: 10px;
|
||||
line-height: 1.4;
|
||||
color: var(--bme-on-surface-dim);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* --- Owner Detail --- */
|
||||
.bme-cog-owner-detail {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.bme-cog-detail-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.bme-cog-detail-name {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: var(--bme-on-surface);
|
||||
}
|
||||
|
||||
.bme-cog-detail-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 3px 10px;
|
||||
border-radius: 999px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
background: var(--bme-primary-dim);
|
||||
color: var(--bme-primary);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bme-cog-metrics {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.bme-cog-metric {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
background: var(--bme-surface-lowest);
|
||||
border: 1px solid var(--bme-border);
|
||||
}
|
||||
|
||||
.bme-cog-metric__label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 10px;
|
||||
color: var(--bme-on-surface-dim);
|
||||
}
|
||||
|
||||
.bme-cog-metric-dot {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.bme-cog-metric-dot.dot-known { background: #4ade80; }
|
||||
.bme-cog-metric-dot.dot-mistaken { background: #fbbf24; }
|
||||
.bme-cog-metric-dot.dot-visible { background: #60a5fa; }
|
||||
.bme-cog-metric-dot.dot-suppressed { background: #f87171; opacity: 0.7; }
|
||||
|
||||
.bme-cog-metric__value {
|
||||
font-size: 20px;
|
||||
line-height: 1;
|
||||
font-weight: 700;
|
||||
color: var(--bme-on-surface);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* --- Chip Groups --- */
|
||||
.bme-cog-chip-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.bme-cog-chip-label {
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
color: var(--bme-on-surface-dim);
|
||||
}
|
||||
|
||||
.bme-cog-chip-wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.bme-cog-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--bme-border);
|
||||
background: var(--bme-surface-lowest);
|
||||
color: var(--bme-on-surface);
|
||||
font-size: 10px;
|
||||
line-height: 1.4;
|
||||
transition: border-color 0.12s ease;
|
||||
}
|
||||
|
||||
.bme-cog-chip.is-visible {
|
||||
border-color: rgba(96, 165, 250, 0.35);
|
||||
color: #93c5fd;
|
||||
}
|
||||
|
||||
.bme-cog-chip.is-suppressed {
|
||||
border-color: rgba(248, 113, 113, 0.25);
|
||||
color: var(--bme-on-surface-dim);
|
||||
}
|
||||
|
||||
.bme-cog-chip.is-empty {
|
||||
color: var(--bme-on-surface-dim);
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
/* --- Manual Override Buttons --- */
|
||||
.bme-cog-override-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--bme-border);
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
}
|
||||
|
||||
.bme-cog-override-title {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: var(--bme-on-surface);
|
||||
}
|
||||
|
||||
.bme-cog-override-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 11px;
|
||||
color: var(--bme-on-surface-dim);
|
||||
}
|
||||
|
||||
.bme-cog-status-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.bme-cog-status-pill.is-known { background: rgba(74, 222, 128, 0.15); color: #4ade80; }
|
||||
.bme-cog-status-pill.is-hidden { background: rgba(251, 191, 36, 0.15); color: #fbbf24; }
|
||||
.bme-cog-status-pill.is-mistaken { background: rgba(248, 113, 113, 0.15); color: #f87171; }
|
||||
.bme-cog-status-pill.is-none { background: rgba(255, 255, 255, 0.06); color: var(--bme-on-surface-dim); }
|
||||
|
||||
.bme-cog-override-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.bme-cog-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 6px 14px;
|
||||
border-radius: 8px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
border: 1px solid;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.bme-cog-btn:disabled {
|
||||
opacity: 0.35;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.bme-cog-btn--known {
|
||||
border-color: rgba(74, 222, 128, 0.4);
|
||||
color: #4ade80;
|
||||
}
|
||||
.bme-cog-btn--known:hover:not(:disabled) {
|
||||
background: rgba(74, 222, 128, 0.1);
|
||||
border-color: #4ade80;
|
||||
}
|
||||
|
||||
.bme-cog-btn--hidden {
|
||||
border-color: rgba(251, 191, 36, 0.4);
|
||||
color: #fbbf24;
|
||||
}
|
||||
.bme-cog-btn--hidden:hover:not(:disabled) {
|
||||
background: rgba(251, 191, 36, 0.1);
|
||||
border-color: #fbbf24;
|
||||
}
|
||||
|
||||
.bme-cog-btn--mistaken {
|
||||
border-color: rgba(248, 113, 113, 0.4);
|
||||
color: #f87171;
|
||||
}
|
||||
.bme-cog-btn--mistaken:hover:not(:disabled) {
|
||||
background: rgba(248, 113, 113, 0.1);
|
||||
border-color: #f87171;
|
||||
}
|
||||
|
||||
.bme-cog-btn--clear {
|
||||
border-color: var(--bme-border);
|
||||
color: var(--bme-on-surface-dim);
|
||||
}
|
||||
.bme-cog-btn--clear:hover:not(:disabled) {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
color: var(--bme-on-surface);
|
||||
}
|
||||
|
||||
/* --- Space Tools (right column) --- */
|
||||
.bme-cog-space-tools {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.bme-cog-space-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.bme-cog-space-row label {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--bme-on-surface-dim);
|
||||
}
|
||||
|
||||
.bme-cog-space-btn-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* --- Monitor Mini List --- */
|
||||
.bme-cog-monitor-mini {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.bme-cog-monitor-entry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px 10px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--bme-border);
|
||||
background: var(--bme-surface-lowest);
|
||||
border-left: 3px solid var(--bme-border);
|
||||
transition: border-color 0.12s ease;
|
||||
}
|
||||
|
||||
.bme-cog-monitor-entry.is-success {
|
||||
border-left-color: #4ade80;
|
||||
}
|
||||
|
||||
.bme-cog-monitor-entry.is-error {
|
||||
border-left-color: #f87171;
|
||||
}
|
||||
|
||||
.bme-cog-monitor-entry.is-running {
|
||||
border-left-color: #60a5fa;
|
||||
animation: bme-pulse-border 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes bme-pulse-border {
|
||||
0%, 100% { border-left-color: #60a5fa; }
|
||||
50% { border-left-color: rgba(96, 165, 250, 0.3); }
|
||||
}
|
||||
|
||||
.bme-cog-monitor-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 2px 7px;
|
||||
border-radius: 4px;
|
||||
font-size: 9px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.03em;
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
color: var(--bme-on-surface-dim);
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.bme-cog-monitor-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 11px;
|
||||
color: var(--bme-on-surface-dim);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.bme-cog-monitor-duration {
|
||||
font-size: 11px;
|
||||
font-family: "Cascadia Code", "Fira Code", monospace;
|
||||
color: var(--bme-on-surface);
|
||||
flex-shrink: 0;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.bme-cog-monitor-empty {
|
||||
padding: 16px 12px;
|
||||
font-size: 11px;
|
||||
color: var(--bme-on-surface-dim);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* --- Dashboard Jump Button --- */
|
||||
.bme-cognition-jump-btn {
|
||||
margin-top: 4px;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════
|
||||
Fullscreen Graph Overlay
|
||||
═══════════════════════════════════════════════════════════ */
|
||||
|
||||
.bme-fullscreen-graph-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 99999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--bme-surface-lowest, #0e0e11);
|
||||
}
|
||||
|
||||
.bme-fullscreen-graph-overlay[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.bme-fullscreen-graph-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 16px;
|
||||
background: var(--bme-surface, #131316);
|
||||
border-bottom: 1px solid var(--bme-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.bme-fullscreen-graph-controls {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.bme-fullscreen-graph-controls button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--bme-border);
|
||||
background: var(--bme-surface);
|
||||
color: var(--bme-on-surface);
|
||||
cursor: pointer;
|
||||
transition: all 0.12s ease;
|
||||
}
|
||||
|
||||
.bme-fullscreen-graph-controls button:hover {
|
||||
background: var(--bme-surface-high);
|
||||
border-color: var(--bme-border-active);
|
||||
}
|
||||
|
||||
.bme-fullscreen-graph-overlay canvas {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════
|
||||
AI Monitor Trace Upgrades
|
||||
═══════════════════════════════════════════════════════════ */
|
||||
|
||||
.bme-ai-monitor-entry.is-collapsed .bme-ai-monitor-entry__detail {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.bme-ai-monitor-entry__toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--bme-border);
|
||||
background: transparent;
|
||||
color: var(--bme-on-surface-dim);
|
||||
cursor: pointer;
|
||||
font-size: 10px;
|
||||
flex-shrink: 0;
|
||||
transition: all 0.12s ease;
|
||||
}
|
||||
|
||||
.bme-ai-monitor-entry__toggle:hover {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
color: var(--bme-on-surface);
|
||||
}
|
||||
|
||||
.bme-ai-monitor-entry.is-collapsed .bme-ai-monitor-entry__toggle i {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.bme-ai-monitor-status-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.bme-ai-monitor-status-dot.dot-success { background: #4ade80; }
|
||||
.bme-ai-monitor-status-dot.dot-error { background: #f87171; }
|
||||
.bme-ai-monitor-status-dot.dot-running {
|
||||
background: #60a5fa;
|
||||
animation: bme-pulse-dot 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.bme-ai-monitor-timeline-connector {
|
||||
width: 2px;
|
||||
height: 12px;
|
||||
margin: 0 auto;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.bme-ai-monitor-governance-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.bme-ai-monitor-gov-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
font-size: 9px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bme-ai-monitor-gov-tag.tag-worldinfo { background: rgba(74, 222, 128, 0.12); color: #4ade80; }
|
||||
.bme-ai-monitor-gov-tag.tag-ejs { background: rgba(45, 212, 191, 0.12); color: #2dd4bf; }
|
||||
.bme-ai-monitor-gov-tag.tag-regex { background: rgba(251, 191, 36, 0.12); color: #fbbf24; }
|
||||
.bme-ai-monitor-gov-tag.tag-cleaning { background: rgba(96, 165, 250, 0.12); color: #60a5fa; }
|
||||
.bme-ai-monitor-gov-tag.tag-error { background: rgba(248, 113, 113, 0.12); color: #f87171; }
|
||||
|
||||
/* --- Trace Cognition Snapshot Two-Column --- */
|
||||
.bme-ai-monitor-snapshot-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.bme-ai-monitor-snapshot-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.bme-ai-monitor-snapshot-col__title {
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: var(--bme-on-surface-dim);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════
|
||||
Mobile Cognition View Responsive
|
||||
═══════════════════════════════════════════════════════════ */
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.bme-cog-status-strip {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
.bme-cog-body {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.bme-cog-owner-scroll {
|
||||
flex-direction: column;
|
||||
}
|
||||
.bme-cog-owner-card {
|
||||
min-width: unset;
|
||||
max-width: unset;
|
||||
}
|
||||
.bme-ai-monitor-snapshot-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
151
ui/panel.html
151
ui/panel.html
@@ -213,72 +213,29 @@
|
||||
<div class="bme-config-card">
|
||||
<div class="bme-section-header">认知 / 空间</div>
|
||||
<div class="bme-config-row">
|
||||
<label>当前召回角色</label>
|
||||
<label><i class="fa-solid fa-user" style="margin-right:4px;opacity:0.5"></i>当前召回角色</label>
|
||||
<div class="bme-recent-meta" id="bme-cognition-active-owner">—</div>
|
||||
</div>
|
||||
<div class="bme-config-row">
|
||||
<label>当前地区</label>
|
||||
<label><i class="fa-solid fa-location-dot" style="margin-right:4px;opacity:0.5"></i>当前地区</label>
|
||||
<div class="bme-recent-meta" id="bme-cognition-active-region">—</div>
|
||||
</div>
|
||||
<div class="bme-config-row">
|
||||
<label>邻接地区</label>
|
||||
<label><i class="fa-solid fa-diagram-project" style="margin-right:4px;opacity:0.5"></i>邻接地区</label>
|
||||
<div class="bme-recent-meta" id="bme-cognition-adjacent-regions">—</div>
|
||||
</div>
|
||||
<div class="bme-config-row">
|
||||
<label>认知角色数</label>
|
||||
<label><i class="fa-solid fa-users" style="margin-right:4px;opacity:0.5"></i>认知角色数</label>
|
||||
<div class="bme-recent-meta" id="bme-cognition-owner-count">0</div>
|
||||
</div>
|
||||
<ul class="bme-recent-list" id="bme-cognition-owner-list"></ul>
|
||||
<div id="bme-cognition-detail" class="bme-cognition-detail"></div>
|
||||
<div class="bme-cognition-tools">
|
||||
<div class="bme-config-row">
|
||||
<label for="bme-cognition-manual-region">手动当前地区</label>
|
||||
<input
|
||||
id="bme-cognition-manual-region"
|
||||
class="bme-config-input"
|
||||
type="text"
|
||||
placeholder="留空则恢复自动判断"
|
||||
/>
|
||||
</div>
|
||||
<div class="bme-cognition-tool-actions">
|
||||
<button
|
||||
class="bme-config-secondary-btn"
|
||||
id="bme-cognition-region-apply"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-location-dot"></i>
|
||||
<span>设为当前地区</span>
|
||||
</button>
|
||||
<button
|
||||
class="bme-config-secondary-btn"
|
||||
id="bme-cognition-region-clear"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-rotate-left"></i>
|
||||
<span>恢复自动</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="bme-config-row">
|
||||
<label for="bme-cognition-adjacency-input">当前地区邻接</label>
|
||||
<input
|
||||
id="bme-cognition-adjacency-input"
|
||||
class="bme-config-input"
|
||||
type="text"
|
||||
placeholder="旧城区, 内廷"
|
||||
/>
|
||||
</div>
|
||||
<div class="bme-config-help">
|
||||
这里的手动覆盖只影响当前聊天图谱。选中一个节点后,可以在上面的角色详情里对该角色标记“强制已知 / 强制隐藏 / 误解”。
|
||||
</div>
|
||||
<button
|
||||
class="bme-config-secondary-btn"
|
||||
id="bme-cognition-adjacency-save"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-diagram-project"></i>
|
||||
<span>保存当前地区邻接</span>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
class="bme-config-secondary-btn bme-cognition-jump-btn"
|
||||
id="bme-cognition-jump-to-view"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-brain"></i>
|
||||
<span>在认知视图中查看完整认知 →</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="bme-config-card">
|
||||
@@ -289,20 +246,22 @@
|
||||
<ul class="bme-recent-list" id="bme-ai-monitor-list"></ul>
|
||||
</div>
|
||||
|
||||
<div class="bme-mobile-graph-preview" id="bme-mobile-graph-area">
|
||||
<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 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>
|
||||
<span class="bme-mobile-graph-label">REALTIME</span>
|
||||
<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-graph-statusbar bme-mobile-graph-status"
|
||||
id="bme-mobile-graph-status"
|
||||
>
|
||||
<span><span class="bme-status-dot"></span>NODE_SYNC_ACTIVE</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="bme-section-header">最近提取</div>
|
||||
@@ -500,9 +459,15 @@
|
||||
<div class="bme-panel-main">
|
||||
<div class="bme-graph-workspace" id="bme-graph-workspace">
|
||||
<div class="bme-graph-toolbar">
|
||||
<div class="bme-graph-toolbar-title">
|
||||
<i class="fa-solid fa-diagram-project"></i>
|
||||
<span>实时图谱</span>
|
||||
<div class="bme-graph-view-tabs">
|
||||
<button class="bme-graph-view-tab active" data-graph-view="graph" type="button">
|
||||
<i class="fa-solid fa-diagram-project"></i>
|
||||
<span>实时图谱</span>
|
||||
</button>
|
||||
<button class="bme-graph-view-tab" data-graph-view="cognition" type="button">
|
||||
<i class="fa-solid fa-brain"></i>
|
||||
<span>认知视图</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="bme-graph-controls">
|
||||
<button id="bme-graph-zoom-in" title="放大" type="button">
|
||||
@@ -534,6 +499,30 @@
|
||||
<span id="bme-status-meta">NODES: 0 | EDGES: 0</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="bme-cognition-workspace" id="bme-cognition-workspace" hidden>
|
||||
<div class="bme-cog-status-strip" id="bme-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-cog-owner-list"></div>
|
||||
<div class="bme-cog-owner-detail" id="bme-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-cog-space-tools"></div>
|
||||
<div class="bme-cog-section-title" style="margin-top:16px">
|
||||
<i class="fa-solid fa-wave-square"></i> AI Monitor
|
||||
</div>
|
||||
<div class="bme-cog-monitor-mini" id="bme-cog-monitor-mini"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bme-node-detail" id="bme-node-detail">
|
||||
<div class="bme-node-detail-header">
|
||||
<h3 id="bme-detail-title">节点详情</h3>
|
||||
@@ -2651,4 +2640,26 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bme-fullscreen-graph-overlay" id="bme-fullscreen-graph" hidden>
|
||||
<div class="bme-fullscreen-graph-toolbar">
|
||||
<div class="bme-graph-toolbar-title">
|
||||
<i class="fa-solid fa-diagram-project"></i>
|
||||
<span>实时图谱(全屏)</span>
|
||||
</div>
|
||||
<div class="bme-fullscreen-graph-controls">
|
||||
<button id="bme-fs-zoom-in" title="放大" type="button">
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
</button>
|
||||
<button id="bme-fs-zoom-out" title="缩小" type="button">
|
||||
<i class="fa-solid fa-minus"></i>
|
||||
</button>
|
||||
<button id="bme-fs-close" title="关闭" type="button">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="bme-fullscreen-graph-canvas"></canvas>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
578
ui/panel.js
578
ui/panel.js
@@ -220,6 +220,7 @@ let currentTaskProfileTabId = "generation";
|
||||
let currentTaskProfileBlockId = "";
|
||||
let currentTaskProfileRuleId = "";
|
||||
let currentCognitionOwnerKey = "";
|
||||
let currentGraphView = "graph";
|
||||
let fetchedMemoryLLMModels = [];
|
||||
let fetchedBackendEmbeddingModels = [];
|
||||
let fetchedDirectEmbeddingModels = [];
|
||||
@@ -873,6 +874,476 @@ function _applyWorkspaceMode() {
|
||||
panelEl.classList.toggle("config-mode", isConfig);
|
||||
}
|
||||
|
||||
// ==================== 图谱视图切换 ====================
|
||||
|
||||
function _switchGraphView(view) {
|
||||
currentGraphView = view || "graph";
|
||||
panelEl?.querySelectorAll(".bme-graph-view-tab").forEach((tab) => {
|
||||
tab.classList.toggle("active", tab.dataset.graphView === currentGraphView);
|
||||
});
|
||||
|
||||
const canvas = document.getElementById("bme-graph-canvas");
|
||||
const legend = document.getElementById("bme-graph-legend");
|
||||
const statusbar = panelEl?.querySelector(".bme-graph-statusbar");
|
||||
const nodeDetail = document.getElementById("bme-node-detail");
|
||||
const cogWorkspace = document.getElementById("bme-cognition-workspace");
|
||||
const graphControls = panelEl?.querySelector(".bme-graph-controls");
|
||||
|
||||
const isGraph = currentGraphView === "graph";
|
||||
if (canvas) canvas.style.display = isGraph ? "" : "none";
|
||||
if (legend) legend.style.display = isGraph ? "" : "none";
|
||||
if (statusbar) statusbar.style.display = isGraph ? "" : "none";
|
||||
if (nodeDetail) nodeDetail.style.display = isGraph ? "" : "none";
|
||||
if (graphControls) graphControls.style.display = isGraph ? "" : "none";
|
||||
if (cogWorkspace) cogWorkspace.hidden = isGraph;
|
||||
|
||||
if (!isGraph) _refreshCognitionWorkspace();
|
||||
}
|
||||
|
||||
function _ownerAvatarHsl(name) {
|
||||
let hash = 0;
|
||||
const str = String(name || "");
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
hash = ((hash << 5) - hash + str.charCodeAt(i)) | 0;
|
||||
}
|
||||
const hue = Math.abs(hash) % 360;
|
||||
return `hsl(${hue}, 55%, 42%)`;
|
||||
}
|
||||
|
||||
// ==================== 认知视图工作区 ====================
|
||||
|
||||
function _refreshCognitionWorkspace() {
|
||||
const graph = _getGraph?.();
|
||||
const loadInfo = _getGraphPersistenceSnapshot();
|
||||
if (!graph) return;
|
||||
|
||||
const canRender =
|
||||
Boolean(graph) &&
|
||||
(_canRenderGraphData(loadInfo) || loadInfo.loadState === "empty-confirmed");
|
||||
|
||||
_renderCogStatusStrip(graph, loadInfo, canRender);
|
||||
_renderCogOwnerList(graph, canRender);
|
||||
_renderCogOwnerDetail(graph, loadInfo, canRender);
|
||||
_renderCogSpaceTools(graph, loadInfo, canRender);
|
||||
_renderCogMonitorMini();
|
||||
}
|
||||
|
||||
function _renderCogStatusStrip(graph, loadInfo, canRender) {
|
||||
const el = document.getElementById("bme-cog-status-strip");
|
||||
if (!el) return;
|
||||
|
||||
if (!canRender) {
|
||||
el.innerHTML = `<div class="bme-cog-status-card" style="grid-column:1/-1"><div class="bme-cog-status-card__value">${_escHtml(_getGraphLoadLabel(loadInfo.loadState))}</div></div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
const historyState = graph?.historyState || {};
|
||||
const regionState = graph?.regionState || {};
|
||||
const { owners, activeOwnerKey, activeOwner } = _getCurrentCognitionOwnerSummary(graph);
|
||||
const activeRegion = String(
|
||||
historyState.activeRegion || historyState.lastExtractedRegion || regionState.manualActiveRegion || "",
|
||||
).trim();
|
||||
const activeRegionLabel = activeRegion
|
||||
? `${activeRegion}${historyState.activeRegionSource ? ` · ${historyState.activeRegionSource}` : ""}`
|
||||
: "—";
|
||||
const adjacentRegions = Array.isArray(regionState?.adjacencyMap?.[activeRegion]?.adjacent)
|
||||
? regionState.adjacencyMap[activeRegion].adjacent
|
||||
: [];
|
||||
|
||||
el.innerHTML = `
|
||||
<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(activeOwner?.ownerName || activeOwnerKey || "—")}</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(activeRegionLabel)}</div>
|
||||
</div>
|
||||
<div class="bme-cog-status-card">
|
||||
<div class="bme-cog-status-card__label"><i class="fa-solid fa-diagram-project"></i> 邻接地区</div>
|
||||
<div class="bme-cog-status-card__value">${_escHtml(adjacentRegions.length > 0 ? adjacentRegions.join(" / ") : "—")}</div>
|
||||
</div>
|
||||
<div class="bme-cog-status-card">
|
||||
<div class="bme-cog-status-card__label"><i class="fa-solid fa-users"></i> 认知角色数</div>
|
||||
<div class="bme-cog-status-card__value">${owners.length}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function _renderCogOwnerList(graph, canRender) {
|
||||
const el = document.getElementById("bme-cog-owner-list");
|
||||
if (!el) return;
|
||||
|
||||
if (!canRender) {
|
||||
el.innerHTML = "";
|
||||
return;
|
||||
}
|
||||
|
||||
const { owners, activeOwnerKey } = _getCurrentCognitionOwnerSummary(graph);
|
||||
|
||||
if (!owners.length) {
|
||||
el.innerHTML = `<div class="bme-cog-monitor-empty">暂无认知角色</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
el.innerHTML = owners
|
||||
.map((owner) => {
|
||||
const firstName = String(owner.ownerName || owner.ownerKey || "?").charAt(0);
|
||||
const bgColor = _ownerAvatarHsl(owner.ownerName || owner.ownerKey);
|
||||
const selected = owner.ownerKey === currentCognitionOwnerKey ? "is-selected" : "";
|
||||
const anchor = owner.ownerKey === activeOwnerKey ? "is-active-anchor" : "";
|
||||
return `
|
||||
<div class="bme-cog-owner-card ${selected} ${anchor}"
|
||||
data-owner-key="${_escHtml(String(owner.ownerKey || ""))}"
|
||||
role="button" tabindex="0">
|
||||
<div class="bme-cog-avatar" style="background:${bgColor}">${_escHtml(firstName)}</div>
|
||||
<div class="bme-cog-owner-card__info">
|
||||
<div class="bme-cog-owner-card__name">${_escHtml(String(owner.ownerName || owner.ownerKey || "未命名"))}</div>
|
||||
<div class="bme-cog-owner-card__stats">已知 ${Number(owner.knownCount || 0)} · 误解 ${Number(owner.mistakenCount || 0)} · 隐藏 ${Number(owner.manualHiddenCount || 0)}</div>
|
||||
</div>
|
||||
</div>`;
|
||||
})
|
||||
.join("");
|
||||
}
|
||||
|
||||
function _renderCogOwnerDetail(graph, loadInfo, canRender) {
|
||||
const el = document.getElementById("bme-cog-owner-detail");
|
||||
if (!el) return;
|
||||
|
||||
if (!canRender) {
|
||||
el.innerHTML = "";
|
||||
return;
|
||||
}
|
||||
|
||||
const { selectedOwner, activeOwnerKey } = _getCurrentCognitionOwnerSummary(graph);
|
||||
|
||||
if (!selectedOwner) {
|
||||
el.innerHTML = `<div class="bme-cog-monitor-empty">选择上方角色查看详情,或等待提取产生认知数据。</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
const ownerState = graph?.knowledgeState?.owners?.[selectedOwner.ownerKey] || {
|
||||
aliases: selectedOwner.aliases || [],
|
||||
visibilityScores: {},
|
||||
manualKnownNodeIds: [],
|
||||
manualHiddenNodeIds: [],
|
||||
mistakenNodeIds: [],
|
||||
knownNodeIds: [],
|
||||
updatedAt: 0,
|
||||
};
|
||||
const visibilityEntries = Object.entries(ownerState.visibilityScores || {})
|
||||
.map(([nodeId, score]) => ({ nodeId: String(nodeId || ""), score: Number(score || 0) }))
|
||||
.filter((e) => e.nodeId)
|
||||
.sort((a, b) => b.score - a.score);
|
||||
const strongVisibleNames = _collectNodeNames(
|
||||
graph,
|
||||
visibilityEntries.filter((e) => e.score >= 0.68).map((e) => e.nodeId),
|
||||
{ limit: 6 },
|
||||
);
|
||||
const suppressedNames = _collectNodeNames(
|
||||
graph,
|
||||
[...(ownerState.manualHiddenNodeIds || []), ...(ownerState.mistakenNodeIds || [])],
|
||||
{ limit: 6 },
|
||||
);
|
||||
const selectedNode = _getSelectedGraphNode(graph);
|
||||
const selectedNodeLabel = selectedNode ? getNodeDisplayName(selectedNode) : "";
|
||||
const selectedNodeState = selectedNode
|
||||
? ownerState.manualKnownNodeIds?.includes(selectedNode.id)
|
||||
? "known"
|
||||
: ownerState.manualHiddenNodeIds?.includes(selectedNode.id)
|
||||
? "hidden"
|
||||
: ownerState.mistakenNodeIds?.includes(selectedNode.id)
|
||||
? "mistaken"
|
||||
: "none"
|
||||
: "";
|
||||
const stateLabels = { known: "强制已知", hidden: "强制隐藏", mistaken: "误解", none: "未覆盖" };
|
||||
const selectedNodeStateLabel = stateLabels[selectedNodeState] || "未选中节点";
|
||||
const writeBlocked = _isGraphWriteBlocked(loadInfo);
|
||||
const suppressedCount = new Set([...(ownerState.manualHiddenNodeIds || []), ...(ownerState.mistakenNodeIds || [])]).size;
|
||||
const disabledAttr = !selectedNode || writeBlocked ? "disabled" : "";
|
||||
|
||||
const visChips = strongVisibleNames.length
|
||||
? strongVisibleNames.map((n) => `<span class="bme-cog-chip is-visible">${_escHtml(n)}</span>`).join("")
|
||||
: '<span class="bme-cog-chip is-empty">暂无</span>';
|
||||
const supChips = suppressedNames.length
|
||||
? suppressedNames.map((n) => `<span class="bme-cog-chip is-suppressed">${_escHtml(n)}</span>`).join("")
|
||||
: '<span class="bme-cog-chip is-empty">暂无</span>';
|
||||
|
||||
el.innerHTML = `
|
||||
<div class="bme-cog-detail-header">
|
||||
<div class="bme-cog-detail-name">${_escHtml(String(selectedOwner.ownerName || selectedOwner.ownerKey || "未命名"))}</div>
|
||||
${selectedOwner.ownerKey === activeOwnerKey ? '<span class="bme-cog-detail-badge">当前召回锚点</span>' : ""}
|
||||
</div>
|
||||
|
||||
<div class="bme-cog-metrics">
|
||||
<div class="bme-cog-metric">
|
||||
<div class="bme-cog-metric__label"><span class="bme-cog-metric-dot dot-known"></span> 已知锚点</div>
|
||||
<div class="bme-cog-metric__value">${Number(selectedOwner.knownCount || 0)}</div>
|
||||
</div>
|
||||
<div class="bme-cog-metric">
|
||||
<div class="bme-cog-metric__label"><span class="bme-cog-metric-dot dot-mistaken"></span> 误解节点</div>
|
||||
<div class="bme-cog-metric__value">${Number(selectedOwner.mistakenCount || 0)}</div>
|
||||
</div>
|
||||
<div class="bme-cog-metric">
|
||||
<div class="bme-cog-metric__label"><span class="bme-cog-metric-dot dot-visible"></span> 强可见</div>
|
||||
<div class="bme-cog-metric__value">${strongVisibleNames.length}</div>
|
||||
</div>
|
||||
<div class="bme-cog-metric">
|
||||
<div class="bme-cog-metric__label"><span class="bme-cog-metric-dot dot-suppressed"></span> 被压制</div>
|
||||
<div class="bme-cog-metric__value">${suppressedCount}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bme-cog-chip-section">
|
||||
<div class="bme-cog-chip-label">强可见节点 · ACTIVE VISIBILITY</div>
|
||||
<div class="bme-cog-chip-wrap">${visChips}</div>
|
||||
</div>
|
||||
<div class="bme-cog-chip-section">
|
||||
<div class="bme-cog-chip-label">被压制节点 · SUPPRESSED</div>
|
||||
<div class="bme-cog-chip-wrap">${supChips}</div>
|
||||
</div>
|
||||
|
||||
<div class="bme-cog-override-section">
|
||||
<div class="bme-cog-override-title">对当前选中节点做手动覆盖</div>
|
||||
<div class="bme-cog-override-status">${
|
||||
selectedNode
|
||||
? `当前节点:${_escHtml(selectedNodeLabel)} · <span class="bme-cog-status-pill is-${selectedNodeState}">${_escHtml(selectedNodeStateLabel)}</span>`
|
||||
: "先在实时图谱或记忆列表中选中一个节点。"
|
||||
}</div>
|
||||
<div class="bme-cog-override-actions">
|
||||
<button class="bme-cog-btn bme-cog-btn--known" type="button" data-bme-cognition-node-action="known" ${disabledAttr}>强制已知</button>
|
||||
<button class="bme-cog-btn bme-cog-btn--hidden" type="button" data-bme-cognition-node-action="hidden" ${disabledAttr}>强制隐藏</button>
|
||||
<button class="bme-cog-btn bme-cog-btn--mistaken" type="button" data-bme-cognition-node-action="mistaken" ${disabledAttr}>标记误解</button>
|
||||
<button class="bme-cog-btn bme-cog-btn--clear" type="button" data-bme-cognition-node-action="clear" ${disabledAttr}>清除覆盖</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function _renderCogSpaceTools(graph, loadInfo, canRender) {
|
||||
const el = document.getElementById("bme-cog-space-tools");
|
||||
if (!el) return;
|
||||
|
||||
if (!canRender) { el.innerHTML = ""; return; }
|
||||
|
||||
const regionState = graph?.regionState || {};
|
||||
const historyState = graph?.historyState || {};
|
||||
const activeRegion = String(
|
||||
historyState.activeRegion || historyState.lastExtractedRegion || regionState.manualActiveRegion || "",
|
||||
).trim();
|
||||
const adjacentRegions = Array.isArray(regionState?.adjacencyMap?.[activeRegion]?.adjacent)
|
||||
? regionState.adjacencyMap[activeRegion].adjacent : [];
|
||||
const writeBlocked = _isGraphWriteBlocked(loadInfo);
|
||||
const disabledAttr = writeBlocked ? "disabled" : "";
|
||||
|
||||
el.innerHTML = `
|
||||
<div class="bme-cog-space-row">
|
||||
<label>手动当前地区</label>
|
||||
<input class="bme-config-input" type="text" id="bme-cog-manual-region"
|
||||
placeholder="输入地区名称..." value="${_escHtml(regionState.manualActiveRegion || activeRegion || "")}" ${disabledAttr} />
|
||||
<div class="bme-cog-space-btn-row">
|
||||
<button class="bme-cog-btn bme-cog-btn--known" type="button" id="bme-cog-region-apply" ${disabledAttr}>
|
||||
<i class="fa-solid fa-location-dot"></i> 设为当前地区
|
||||
</button>
|
||||
<button class="bme-cog-btn bme-cog-btn--clear" type="button" id="bme-cog-region-clear" ${disabledAttr}>
|
||||
<i class="fa-solid fa-rotate-left"></i> 恢复自动
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bme-cog-space-row">
|
||||
<label>当前地区邻接</label>
|
||||
<input class="bme-config-input" type="text" id="bme-cog-adjacency-input"
|
||||
placeholder="例如:内廷, 港口, 花园" value="${_escHtml(adjacentRegions.join(", "))}" ${disabledAttr} />
|
||||
<div class="bme-config-help" style="font-size:10px;margin-top:2px">使用 "," 分隔多个地区。保存后更新该地区的邻接关系。</div>
|
||||
<button class="bme-cog-btn bme-cog-btn--known" type="button" id="bme-cog-adjacency-save" ${disabledAttr}>
|
||||
<i class="fa-solid fa-diagram-project"></i> 保存当前地区邻接
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function _renderCogMonitorMini() {
|
||||
const el = document.getElementById("bme-cog-monitor-mini");
|
||||
if (!el) return;
|
||||
|
||||
const settings = _getSettings?.() || {};
|
||||
if (settings.enableAiMonitor !== true) {
|
||||
el.innerHTML = `<div class="bme-cog-monitor-empty">AI Monitor 已关闭</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
const runtimeDebug = _getRuntimeDebugSnapshot?.() || {};
|
||||
const timeline = Array.isArray(runtimeDebug?.runtimeDebug?.taskTimeline)
|
||||
? runtimeDebug.runtimeDebug.taskTimeline : [];
|
||||
|
||||
if (!timeline.length) {
|
||||
el.innerHTML = `<div class="bme-cog-monitor-empty">暂无任务流水</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
const taskTypeLabels = { extract: "提取", recall: "召回", compress: "压缩", sleep: "遗忘", evolve: "进化", embed: "向量" };
|
||||
|
||||
el.innerHTML = timeline
|
||||
.slice(-8)
|
||||
.reverse()
|
||||
.map((entry) => {
|
||||
const status = String(entry?.status || "").toLowerCase();
|
||||
const statusClass = status.includes("error") || status.includes("fail") ? "is-error"
|
||||
: status.includes("run") ? "is-running" : "is-success";
|
||||
const taskType = String(entry?.taskType || "unknown");
|
||||
const route = String(entry?.route || entry?.llmConfigSourceLabel || entry?.model || "").trim();
|
||||
const durationMs = Number(entry?.durationMs);
|
||||
const durationText = Number.isFinite(durationMs) && durationMs > 0
|
||||
? durationMs >= 1000 ? `${(durationMs / 1000).toFixed(1)}s` : `${Math.round(durationMs)}ms`
|
||||
: "—";
|
||||
return `
|
||||
<div class="bme-cog-monitor-entry ${statusClass}">
|
||||
<span class="bme-cog-monitor-badge">${_escHtml(taskTypeLabels[taskType] || taskType)}</span>
|
||||
<span class="bme-cog-monitor-info">${_escHtml(route || "—")}</span>
|
||||
<span class="bme-cog-monitor-duration">${_escHtml(durationText)}</span>
|
||||
</div>`;
|
||||
})
|
||||
.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 } = _getCurrentCognitionOwnerSummary(graph);
|
||||
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 firstName = String(owner.ownerName || owner.ownerKey || "?").charAt(0);
|
||||
const bgColor = _ownerAvatarHsl(owner.ownerName || owner.ownerKey);
|
||||
const anchor = owner.ownerKey === activeOwnerKey ? "is-active-anchor" : "";
|
||||
return `
|
||||
<div class="bme-cog-owner-card ${anchor}" style="min-width:unset;max-width:unset">
|
||||
<div class="bme-cog-avatar" style="background:${bgColor}">${_escHtml(firstName)}</div>
|
||||
<div class="bme-cog-owner-card__info">
|
||||
<div class="bme-cog-owner-card__name">${_escHtml(String(owner.ownerName || owner.ownerKey || "未命名"))}</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(activeOwner?.ownerName || "—")}</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 _openFullscreenGraph() {
|
||||
const overlay = document.getElementById("bme-fullscreen-graph");
|
||||
if (!overlay) return;
|
||||
overlay.hidden = false;
|
||||
document.body.style.overflow = "hidden";
|
||||
}
|
||||
|
||||
function _closeFullscreenGraph() {
|
||||
const overlay = document.getElementById("bme-fullscreen-graph");
|
||||
if (!overlay) return;
|
||||
overlay.hidden = true;
|
||||
document.body.style.overflow = "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
function _switchConfigSection(sectionId) {
|
||||
currentConfigSectionId = sectionId || "toggles";
|
||||
_syncConfigSectionState();
|
||||
@@ -998,6 +1469,7 @@ function _refreshDashboard() {
|
||||
|
||||
_refreshCognitionDashboard(graph);
|
||||
_refreshAiMonitorDashboard();
|
||||
_refreshMobileSummary();
|
||||
_renderRecentList("bme-recent-extract", _getLastExtract?.() || []);
|
||||
_renderRecentList("bme-recent-recall", _getLastRecall?.() || []);
|
||||
}
|
||||
@@ -1405,25 +1877,10 @@ function _refreshCognitionDashboard(
|
||||
adjacentRegions.length > 0 ? adjacentRegions.join(" / ") : "—",
|
||||
);
|
||||
_setText("bme-cognition-owner-count", owners.length);
|
||||
_renderCognitionOwnerList(graph, { owners, activeOwnerKey });
|
||||
_renderCognitionDetail(
|
||||
graph,
|
||||
{
|
||||
selectedOwner,
|
||||
activeOwnerKey,
|
||||
activeRegion,
|
||||
adjacentRegions,
|
||||
},
|
||||
loadInfo,
|
||||
);
|
||||
_setInputValueIfIdle(
|
||||
"bme-cognition-manual-region",
|
||||
regionState.manualActiveRegion || activeRegion || "",
|
||||
);
|
||||
_setInputValueIfIdle(
|
||||
"bme-cognition-adjacency-input",
|
||||
adjacentRegions.join(", "),
|
||||
);
|
||||
// Cognition view workspace refresh (if visible)
|
||||
if (currentGraphView === "cognition") {
|
||||
_refreshCognitionWorkspace();
|
||||
}
|
||||
}
|
||||
|
||||
function _refreshAiMonitorDashboard() {
|
||||
@@ -2856,6 +3313,89 @@ function _bindActions() {
|
||||
_refreshGraphAvailabilityState();
|
||||
}
|
||||
});
|
||||
|
||||
// ==================== 认知视图绑定 ====================
|
||||
|
||||
// 图谱/认知视图 tab 切换
|
||||
panelEl?.querySelectorAll(".bme-graph-view-tab").forEach((tab) => {
|
||||
tab.addEventListener("click", () => {
|
||||
_switchGraphView(tab.dataset.graphView);
|
||||
});
|
||||
});
|
||||
|
||||
// 移动端图谱/认知 tab 切换
|
||||
document.querySelectorAll(".bme-mobile-graph-tab").forEach((tab) => {
|
||||
tab.addEventListener("click", () => {
|
||||
_switchMobileGraphView(tab.dataset.mobileView);
|
||||
});
|
||||
});
|
||||
|
||||
// 全屏图谱
|
||||
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;
|
||||
currentCognitionOwnerKey = card.dataset.ownerKey;
|
||||
_refreshCognitionWorkspace();
|
||||
});
|
||||
|
||||
// Dashboard 跳转认知视图
|
||||
document.getElementById("bme-cognition-jump-to-view")?.addEventListener("click", () => {
|
||||
_switchTab("dashboard");
|
||||
_switchGraphView("cognition");
|
||||
});
|
||||
|
||||
// 认知视图空间工具 (delegate)
|
||||
document.getElementById("bme-cognition-workspace")?.addEventListener("click", (e) => {
|
||||
const regionApply = e.target.closest("#bme-cog-region-apply");
|
||||
const regionClear = e.target.closest("#bme-cog-region-clear");
|
||||
const adjSave = e.target.closest("#bme-cog-adjacency-save");
|
||||
|
||||
if (regionApply) {
|
||||
const manualRegion = document.getElementById("bme-cog-manual-region")?.value?.trim();
|
||||
if (manualRegion) _callAction("setActiveRegion", { region: manualRegion });
|
||||
}
|
||||
if (regionClear) {
|
||||
_callAction("setActiveRegion", { region: "" });
|
||||
}
|
||||
if (adjSave) {
|
||||
const adjInput = document.getElementById("bme-cog-adjacency-input")?.value?.trim() || "";
|
||||
const adjList = adjInput.split(/[,,\/\\]/).map((s) => s.trim()).filter(Boolean);
|
||||
const graph = _getGraph?.();
|
||||
const activeRegion = String(
|
||||
graph?.historyState?.activeRegion || graph?.historyState?.lastExtractedRegion || graph?.regionState?.manualActiveRegion || "",
|
||||
).trim();
|
||||
if (activeRegion) _callAction("updateRegionAdjacency", { region: activeRegion, adjacent: adjList });
|
||||
}
|
||||
|
||||
// 手动覆盖按钮
|
||||
const actionBtn = e.target.closest("[data-bme-cognition-node-action]");
|
||||
if (actionBtn) {
|
||||
const mode = actionBtn.dataset.bmeCognitionNodeAction;
|
||||
if (!mode) return;
|
||||
const graph = _getGraph?.();
|
||||
const selectedNode = _getSelectedGraphNode(graph);
|
||||
if (!selectedNode) return;
|
||||
const { selectedOwner } = _getCurrentCognitionOwnerSummary(graph);
|
||||
if (!selectedOwner) return;
|
||||
|
||||
if (mode === "clear") {
|
||||
_callAction("clearKnowledgeOverride", { nodeId: selectedNode.id, ownerKey: selectedOwner.ownerKey });
|
||||
} else {
|
||||
_callAction("applyKnowledgeOverride", {
|
||||
nodeId: selectedNode.id,
|
||||
ownerKey: selectedOwner.ownerKey,
|
||||
ownerType: selectedOwner.ownerType || "",
|
||||
ownerName: selectedOwner.ownerName || "",
|
||||
mode,
|
||||
});
|
||||
}
|
||||
_refreshCognitionWorkspace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function _refreshConfigTab() {
|
||||
|
||||
Reference in New Issue
Block a user