learn_results.html
7.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
{% extends "base.html" %}
{% block title %}学习结果 - WeChat Viewer{% endblock %}
{% block body %}
<style>
body{overflow-y:auto!important;height:auto!important;}
.results-container{max-width:960px;margin:0 auto;padding:20px;}
.results-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;}
.results-header h1{font-size:20px;color:#2c3e50;}
.result-card{background:white;border-radius:8px;padding:16px 18px;margin-bottom:10px;box-shadow:0 1px 2px rgba(0,0,0,0.05);border-left:3px solid #8e44ad;}
.result-card.failed{border-left-color:#e74c3c;}
.result-card .top{display:flex;align-items:center;gap:10px;margin-bottom:10px;}
.result-card .title{font-size:14px;font-weight:600;flex:1;}
.result-type{font-size:10px;padding:2px 8px;border-radius:10px;font-weight:600;}
.result-type.skill{background:#d5f5e3;color:#1e8449}
.result-type.memory{background:#d6eaf8;color:#1a5276}
.result-type.methodology{background:#fdebd0;color:#b9770e}
.result-type.reference{background:#e8daef;color:#6c3483}
.result-type.architecture{background:#fadbd8;color:#922b21}
.auto-badge{font-size:9px;padding:1px 6px;border-radius:8px;background:#e8daef;color:#6c3483;}
.result-card .summary{font-size:12px;color:#666;line-height:1.5;margin-bottom:8px;}
.result-card .details{font-size:11px;color:#888;}
.result-card .details span{display:inline-block;margin-right:12px;margin-bottom:4px;}
.feedback-section{border-top:1px solid #eee;padding-top:8px;margin-top:8px;}
.feedback-input{width:100%;padding:6px;border:1px solid #ddd;border-radius:4px;font-size:11px;box-sizing:border-box;}
.btn-feedback{background:#3498db;color:white;border:none;padding:4px 10px;border-radius:4px;cursor:pointer;font-size:11px;margin-top:4px;}
.btn-feedback:hover{background:#2980b9}
.existing-feedback{font-size:11px;color:#8e44ad;padding:4px 8px;background:#f4ecf7;border-radius:4px;}
.empty-state{text-align:center;padding:60px 20px;color:#999;}
.loading{text-align:center;padding:40px;color:#999;}
</style>
<div class="results-container">
<div class="results-header">
<h1>📊 学习结果</h1>
<div style="display:flex;gap:8px;">
<a href="/learn" style="font-size:12px;color:#3498db;text-decoration:none;padding:6px 10px;border:1px solid #3498db;border-radius:6px;">← 审核队列</a>
<button onclick="refresh()" style="background:#8e44ad;color:white;border:none;padding:6px 14px;border-radius:6px;cursor:pointer;font-size:13px;">🔄 刷新</button>
</div>
</div>
<div class="rbar" style="display:flex;gap:8px;margin-bottom:12px;flex-wrap:wrap;align-items:center;">
<input type="text" id="searchInput" placeholder="搜索文章标题/摘要..." oninput="render()" style="flex:1;min-width:120px;padding:10px;border:1px solid #ddd;border-radius:8px;font-size:14px;">
<select id="typeFilter" onchange="render()" style="padding:10px;border:1px solid #ddd;border-radius:8px;font-size:13px;background:white;cursor:pointer;">
<option value="">全部类型</option>
<option value="skill">Skill</option>
<option value="memory">记忆</option>
<option value="todo">待办</option>
<option value="reference">参考</option>
<option value="methodology">方法论</option>
<option value="architecture">架构</option>
</select>
<select id="sortBy" onchange="render()" style="padding:10px;border:1px solid #ddd;border-radius:8px;font-size:13px;background:white;cursor:pointer;">
<option value="time">按时间↓</option>
<option value="title">按标题</option>
</select>
</div>
<div id="stats" style="margin-bottom:16px;font-size:13px;color:#888;"></div>
<div id="list"></div>
</div>
<script>
var allResults = [];
var TYPE_NAMES = {
skill:'🛠 Skill', memory:'🧠 记忆', todo:'📋 待办',
reference:'📖 参考', methodology:'💡 方法论', architecture:'🔧 架构'
};
function esc(s){return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');}
function refresh(){
var el=document.getElementById('list');
el.innerHTML='<div class="loading">加载中...</div>';
fetch('/api/learn-results').then(function(r){return r.json()}).then(function(j){
if(!j.ok||!j.data.length){el.innerHTML='<div class="empty-state"><p>暂无学习结果<br><small>吸收文章后会自动出现在这里</small></p></div>';return;}
allResults = j.data;
document.getElementById('stats').textContent='共 '+allResults.length+' 条学习记录';
render();
}).catch(function(e){el.innerHTML='<div class="empty-state"><p>加载失败: '+e.message+'</p></div>';});
}
function render(){
var el=document.getElementById('list');
var q=(document.getElementById('searchInput').value||'').trim().toLowerCase();
var tf=document.getElementById('typeFilter').value;
var sb=document.getElementById('sortBy').value;
var filtered=[];
for(var i=0;i<allResults.length;i++){
var t=allResults[i];
if(q){
var hay=((t.article_title||'')+' '+(t.result_summary||'')+' '+(t.created_skill||'')+' '+(t.updated_skill||'')).toLowerCase();
if(hay.indexOf(q)<0)continue;
}
if(tf&&t.result_type!==tf)continue;
filtered.push(t);
}
if(sb==='title')filtered.sort(function(a,b){return (a.article_title||'').localeCompare(b.article_title||'')});
else filtered.sort(function(a,b){return (b.created_at||'').localeCompare(a.created_at||'')});
if(!filtered.length){el.innerHTML='<div class="empty-state"><p>无匹配</p></div>';return;}
var h='';
for(var i=0;i<filtered.length;i++){
var t=filtered[i];
var tn=TYPE_NAMES[t.result_type]||t.result_type;
var failed=t.status==='failed';
h+='<div class="result-card'+(failed?' failed':'')+'">';
h+='<div class="top"><span class="result-type '+t.result_type+'">'+tn+'</span>';
if(t.auto_applied)h+='<span class="auto-badge">🤖 自动</span>';
h+='<span class="title">'+esc(t.article_title||'未命名')+'</span>';
h+='<span style="font-size:10px;color:#999;">'+(t.created_at||'').substring(0,16)+'</span></div>';
if(t.result_summary)h+='<div class="summary">'+esc(t.result_summary)+'</div>';
h+='<div class="details">';
if(t.created_skill)h+='<span>🛠 创建: <b>'+esc(t.created_skill)+'</b></span>';
if(t.updated_skill)h+='<span>📝 更新: <b>'+esc(t.updated_skill)+'</b></span>';
if(t.learned_methodology)h+='<span>💡 方法论: '+esc(t.learned_methodology).substring(0,80)+'</span>';
if(t.verification_result)h+='<span>✅ 验证: '+esc(t.verification_result).substring(0,80)+'</span>';
if(t.architecture_change)h+='<span>🔧 架构: '+esc(t.architecture_change).substring(0,80)+'</span>';
h+='</div>';
h+='<div class="feedback-section">';
if(t.human_feedback){
h+='<div class="existing-feedback">💬 反馈: '+esc(t.human_feedback)+'</div>';
}else{
h+='<input class="feedback-input" id="fb_'+t.id+'" placeholder="输入反馈...">';
h+='<button class="btn-feedback" onclick="sendFeedback('+t.id+')">发送反馈</button>';
}
h+='</div>';
h+='</div>';
}
el.innerHTML=h;
}
function sendFeedback(id){
var inp=document.getElementById('fb_'+id);
if(!inp||!inp.value.trim())return;
fetch('/api/learn-result/'+id+'/feedback',{
method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({feedback:inp.value.trim()})
}).then(function(r){return r.json()}).then(function(j){
if(j.ok){refresh();}else{alert('失败: '+(j.error||''));}
});
}
refresh();
</script>
{% endblock %}