Phase 5: Add Timeline View feature
- Add backend API endpoints for timeline data:
- GET /api/v1/projects/{id}/timeline
- GET /api/v1/projects/{id}/timeline/summary
- GET /api/v1/entities/{id}/timeline
- Add database methods for timeline queries in db_manager.py
- Add frontend timeline view:
- New sidebar button for timeline view
- Timeline panel with date-grouped events
- Visual distinction between mentions and relations
- Entity filter dropdown
- Statistics cards
- Interactive event cards
- Update STATUS.md with Phase 5 progress
- Add view switching functions (switchView, switchKBTab)
- Add knowledge base loading functions
This commit is contained in:
@@ -842,11 +842,183 @@
|
||||
color: #888;
|
||||
}
|
||||
|
||||
/* Phase 4: Low confidence entity */
|
||||
.entity.low-confidence {
|
||||
background: rgba(255, 193, 7, 0.3);
|
||||
border-bottom-color: #ffc107;
|
||||
/* Phase 5: Timeline View */
|
||||
.timeline-panel {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
background: #0a0a0a;
|
||||
}
|
||||
.timeline-panel.show {
|
||||
display: flex;
|
||||
}
|
||||
.timeline-header {
|
||||
padding: 16px 20px;
|
||||
background: #141414;
|
||||
border-bottom: 1px solid #222;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.timeline-filters {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
.timeline-filter-select {
|
||||
background: #1a1a1a;
|
||||
border: 1px solid #333;
|
||||
border-radius: 6px;
|
||||
padding: 8px 12px;
|
||||
color: #e0e0e0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.timeline-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.timeline-container {
|
||||
position: relative;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.timeline-line {
|
||||
position: absolute;
|
||||
left: 120px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 2px;
|
||||
background: linear-gradient(180deg, #00d4ff, #7b2cbf);
|
||||
}
|
||||
.timeline-date-group {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.timeline-date-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
position: relative;
|
||||
}
|
||||
.timeline-date-label {
|
||||
width: 100px;
|
||||
text-align: right;
|
||||
padding-right: 20px;
|
||||
color: #888;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.timeline-date-dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: #00d4ff;
|
||||
position: absolute;
|
||||
left: 115px;
|
||||
box-shadow: 0 0 10px rgba(0, 212, 255, 0.5);
|
||||
}
|
||||
.timeline-events {
|
||||
margin-left: 140px;
|
||||
}
|
||||
.timeline-event {
|
||||
background: #141414;
|
||||
border: 1px solid #222;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
margin-bottom: 12px;
|
||||
transition: all 0.2s;
|
||||
cursor: pointer;
|
||||
}
|
||||
.timeline-event:hover {
|
||||
border-color: #00d4ff;
|
||||
background: #1a1a1a;
|
||||
}
|
||||
.timeline-event-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.timeline-event-type {
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.timeline-event-type.mention {
|
||||
background: #7b2cbf;
|
||||
}
|
||||
.timeline-event-type.relation {
|
||||
background: #00d4ff;
|
||||
color: #000;
|
||||
}
|
||||
.timeline-event-entity {
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
.timeline-event-snippet {
|
||||
color: #aaa;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 8px;
|
||||
padding-left: 12px;
|
||||
border-left: 2px solid #333;
|
||||
}
|
||||
.timeline-event-source {
|
||||
font-size: 0.8rem;
|
||||
color: #666;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.timeline-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.timeline-stat-card {
|
||||
background: #141414;
|
||||
border: 1px solid #222;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
}
|
||||
.timeline-stat-title {
|
||||
font-size: 0.8rem;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.timeline-stat-value {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
color: #00d4ff;
|
||||
}
|
||||
.timeline-empty {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
color: #666;
|
||||
}
|
||||
.timeline-legend {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.timeline-legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 0.8rem;
|
||||
color: #888;
|
||||
}
|
||||
.timeline-legend-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.timeline-legend-dot.mention { background: #7b2cbf; }
|
||||
.timeline-legend-dot.relation { background: #00d4ff; }
|
||||
|
||||
/* Typing indicator */
|
||||
.typing-indicator {
|
||||
@@ -885,6 +1057,7 @@
|
||||
<div class="sidebar">
|
||||
<button class="sidebar-btn active" onclick="switchView('workbench')" title="工作台">📝</button>
|
||||
<button class="sidebar-btn" onclick="switchView('knowledge-base')" title="知识库">📚</button>
|
||||
<button class="sidebar-btn" onclick="switchView('timeline')" title="时间线">📅</button>
|
||||
</div>
|
||||
|
||||
<!-- Content Area -->
|
||||
@@ -957,8 +1130,51 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Knowledge Base View -->
|
||||
<div id="knowledgeBaseView" class="kb-panel">
|
||||
<!-- Timeline View -->
|
||||
<div id="timelineView" class="timeline-panel">
|
||||
<div class="timeline-header">
|
||||
<div>
|
||||
<h2>📅 项目时间线</h2>
|
||||
<div class="timeline-legend">
|
||||
<div class="timeline-legend-item">
|
||||
<div class="timeline-legend-dot mention"></div>
|
||||
<span>实体提及</span>
|
||||
</div>
|
||||
<div class="timeline-legend-item">
|
||||
<div class="timeline-legend-dot relation"></div>
|
||||
<span>关系建立</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timeline-filters">
|
||||
<select class="timeline-filter-select" id="timelineEntityFilter" onchange="loadTimeline()">
|
||||
<option value="">全部实体</option>
|
||||
</select>
|
||||
<button class="btn btn-small" onclick="loadTimeline()">🔄 刷新</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timeline-content" id="timelineContent">
|
||||
<div class="timeline-stats" id="timelineStats">
|
||||
<div class="timeline-stat-card">
|
||||
<div class="timeline-stat-title">总事件数</div>
|
||||
<div class="timeline-stat-value" id="timelineTotalEvents">-</div>
|
||||
</div>
|
||||
<div class="timeline-stat-card">
|
||||
<div class="timeline-stat-title">实体提及</div>
|
||||
<div class="timeline-stat-value" id="timelineMentions">-</div>
|
||||
</div>
|
||||
<div class="timeline-stat-card">
|
||||
<div class="timeline-stat-title">关系建立</div>
|
||||
<div class="timeline-stat-value" id="timelineRelations">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timeline-container" id="timelineContainer">
|
||||
<div class="timeline-empty">
|
||||
<p>加载时间线数据...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="kb-header">
|
||||
<h2>📚 项目知识库</h2>
|
||||
<div class="kb-stats">
|
||||
|
||||
Reference in New Issue
Block a user