skill-memo-ilife 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/cmd_read.d.ts +3 -0
- package/dist/cli/cmd_read.d.ts.map +1 -0
- package/dist/cli/cmd_read.js +178 -0
- package/dist/cli/cmd_read.js.map +1 -0
- package/dist/fetch/db.d.ts +31 -0
- package/dist/fetch/db.d.ts.map +1 -0
- package/dist/fetch/db.js +117 -0
- package/dist/fetch/db.js.map +1 -0
- package/dist/fetch/errors.d.ts +11 -0
- package/dist/fetch/errors.d.ts.map +1 -0
- package/dist/fetch/errors.js +18 -0
- package/dist/fetch/errors.js.map +1 -0
- package/dist/fetch/feishu.d.ts +24 -0
- package/dist/fetch/feishu.d.ts.map +1 -0
- package/dist/fetch/feishu.js +117 -0
- package/dist/fetch/feishu.js.map +1 -0
- package/dist/fetch/index.d.ts +6 -0
- package/dist/fetch/index.d.ts.map +1 -0
- package/dist/fetch/index.js +4 -0
- package/dist/fetch/index.js.map +1 -0
- package/dist/help/index.d.ts +3 -0
- package/dist/help/index.d.ts.map +1 -0
- package/dist/help/index.js +2 -0
- package/dist/help/index.js.map +1 -0
- package/dist/help/lookup.d.ts +11 -0
- package/dist/help/lookup.d.ts.map +1 -0
- package/dist/help/lookup.js +38 -0
- package/dist/help/lookup.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/policy/category.d.ts +7 -0
- package/dist/policy/category.d.ts.map +1 -0
- package/dist/policy/category.js +29 -0
- package/dist/policy/category.js.map +1 -0
- package/dist/policy/crud.d.ts +19 -0
- package/dist/policy/crud.d.ts.map +1 -0
- package/dist/policy/crud.js +24 -0
- package/dist/policy/crud.js.map +1 -0
- package/dist/policy/index.d.ts +10 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +6 -0
- package/dist/policy/index.js.map +1 -0
- package/dist/policy/reminder.d.ts +10 -0
- package/dist/policy/reminder.d.ts.map +1 -0
- package/dist/policy/reminder.js +20 -0
- package/dist/policy/reminder.js.map +1 -0
- package/dist/policy/wakewords.d.ts +14 -0
- package/dist/policy/wakewords.d.ts.map +1 -0
- package/dist/policy/wakewords.js +53 -0
- package/dist/policy/wakewords.js.map +1 -0
- package/dist/policy/wish.d.ts +7 -0
- package/dist/policy/wish.d.ts.map +1 -0
- package/dist/policy/wish.js +13 -0
- package/dist/policy/wish.js.map +1 -0
- package/dist/render/envelope.d.ts +6 -0
- package/dist/render/envelope.d.ts.map +1 -0
- package/dist/render/envelope.js +50 -0
- package/dist/render/envelope.js.map +1 -0
- package/dist/render/errors.d.ts +5 -0
- package/dist/render/errors.d.ts.map +1 -0
- package/dist/render/errors.js +10 -0
- package/dist/render/errors.js.map +1 -0
- package/dist/render/html.d.ts +10 -0
- package/dist/render/html.d.ts.map +1 -0
- package/dist/render/html.js +52 -0
- package/dist/render/html.js.map +1 -0
- package/dist/render/index.d.ts +6 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +5 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/templates.d.ts +4 -0
- package/dist/render/templates.d.ts.map +1 -0
- package/dist/render/templates.js +26 -0
- package/dist/render/templates.js.map +1 -0
- package/package.json +32 -0
- package/templates/change_category.html +257 -0
- package/templates/init_report.html +225 -0
- package/templates/memo_query.html +104 -0
- package/templates/sync_report.html +512 -0
- package/templates/wish_complete.html +239 -0
- package/templates/wish_plan.html +272 -0
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "skill-memo-ilife",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "备忘录SKILL一期:取数+口径+渲染+出口(M2/M3/M4/M5),依 link-core",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/index.js",
|
|
10
|
+
"./fetch": "./dist/fetch/index.js",
|
|
11
|
+
"./policy": "./dist/policy/index.js",
|
|
12
|
+
"./render": "./dist/render/index.js",
|
|
13
|
+
"./cli": "./dist/cli/cmd_read.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"templates/*.html"
|
|
18
|
+
],
|
|
19
|
+
"bin": {
|
|
20
|
+
"memo-cmd-read": "./dist/cli/cmd_read.js"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"base-link-core": "workspace:^0.1.0"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=22.13"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc -b && node scripts/build-help.mjs",
|
|
30
|
+
"test": "node --test ../../test/scaffold.test.mjs"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<title>批量改分类向导</title>
|
|
7
|
+
<style><!--SHARED-CSS--></style>
|
|
8
|
+
<style>
|
|
9
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
10
|
+
body{font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif;background:var(--bg);color:var(--fg);line-height:1.65;-webkit-font-smoothing:antialiased}
|
|
11
|
+
.wrap{max-width:980px;margin:0 auto;padding:48px 22px 90px}
|
|
12
|
+
.hero{background:linear-gradient(180deg,#fff 0%,#f8fbff 100%);border-radius:28px;padding:34px;margin-bottom:20px;box-shadow:var(--shadow,0 1px 2px rgba(0,0,0,.04),0 12px 36px rgba(0,0,0,.06))}
|
|
13
|
+
.eyebrow{font-size:13px;color:var(--blue);font-weight:800;letter-spacing:.08em;text-transform:uppercase;margin-bottom:10px}
|
|
14
|
+
h1{font-size:36px;line-height:1.15;letter-spacing:-.035em;margin-bottom:12px}
|
|
15
|
+
.lead{color:var(--fg2);font-size:17px}
|
|
16
|
+
.meta{margin-top:14px;color:var(--fg3);font-size:13px}
|
|
17
|
+
.badge{display:inline-block;background:var(--soft,#f5f8ff);color:var(--blue);padding:4px 11px;border-radius:999px;font-size:13px;font-weight:700;margin:2px 6px 2px 0}
|
|
18
|
+
.badge.ok{background:#ecfff2;color:#178a3a}
|
|
19
|
+
.badge.warn{background:#fff7e8;color:#b25b00}
|
|
20
|
+
.panel{background:var(--card);border-radius:20px;padding:22px;box-shadow:0 1px 3px rgba(0,0,0,.04);margin:14px 0}
|
|
21
|
+
.panel .hint{font-size:12px;color:var(--fg3);margin-top:6px}
|
|
22
|
+
.toolbar{display:flex;gap:10px;flex-wrap:wrap;margin:14px 0;align-items:center}
|
|
23
|
+
button{border:0;background:var(--blue);color:#fff;border-radius:999px;padding:10px 16px;cursor:pointer;font-size:14px;font-weight:600}
|
|
24
|
+
button.ghost{background:transparent;color:var(--blue);border:1px solid var(--line);min-height:44px}
|
|
25
|
+
button.copy.ghost{background:var(--card);color:var(--blue);border:1.5px solid var(--blue)}
|
|
26
|
+
button.primary{background:var(--blue);color:#fff;font-size:15px;padding:12px 20px}
|
|
27
|
+
input[type=text]{border:1px solid var(--line);border-radius:12px;padding:9px 12px;font-size:14px;font-family:inherit;background:var(--card)}
|
|
28
|
+
select{border:1px solid var(--line);border-radius:12px;padding:9px 12px;font-size:14px;font-family:inherit;background:var(--card)}
|
|
29
|
+
.note{background:var(--card);border-radius:18px;padding:18px;margin:12px 0;box-shadow:0 1px 3px rgba(0,0,0,.04);transition:box-shadow .15s,opacity .15s}
|
|
30
|
+
#noteList{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;align-items:stretch}
|
|
31
|
+
#noteList .note{margin:0;padding:14px;display:flex;flex-direction:column;height:100%}
|
|
32
|
+
#noteList .hm-empty{grid-column:1/-1}
|
|
33
|
+
#noteList .note-head{flex-wrap:nowrap;gap:6px;margin-bottom:8px;align-items:flex-start}
|
|
34
|
+
#noteList .note-id{font-size:13px;min-width:0;white-space:nowrap}
|
|
35
|
+
#noteList .note-content{font-size:14px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;word-break:break-all;flex:1 1 auto}
|
|
36
|
+
#noteList .note-meta{margin:auto 0 0;gap:8px;padding-top:8px}
|
|
37
|
+
#noteList .note-meta .badge{font-size:11px;padding:2px 8px;margin:2px 4px 2px 0}
|
|
38
|
+
.note.off{opacity:.5}
|
|
39
|
+
.note.off .content{text-decoration:line-through;color:var(--fg3)}
|
|
40
|
+
.note-head{display:flex;align-items:center;gap:12px;margin-bottom:10px}
|
|
41
|
+
.note-id{color:var(--blue);font-weight:800;font-size:15px;min-width:48px}
|
|
42
|
+
.note-content{font-size:16px;flex:1}
|
|
43
|
+
.note-meta{display:flex;gap:16px;flex-wrap:wrap;align-items:center;color:var(--fg2);font-size:13px;margin:8px 0}
|
|
44
|
+
.flow{display:flex;align-items:center;justify-content:center;gap:12px;margin:20px 0;font-size:17px;font-weight:600}
|
|
45
|
+
.flow .from{background:var(--bg);color:var(--fg2);padding:8px 16px;border-radius:14px;border:1px solid var(--line)}
|
|
46
|
+
.flow .to{background:var(--soft,#f5f8ff);color:var(--blue);padding:8px 16px;border-radius:14px}
|
|
47
|
+
.flow .arrow{font-size:24px;color:var(--fg3)}
|
|
48
|
+
.kpi{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:14px 0}
|
|
49
|
+
.kpi .stat{background:var(--card);border-radius:18px;padding:18px;box-shadow:0 1px 3px rgba(0,0,0,.04)}
|
|
50
|
+
.kpi b{display:block;font-size:22px;letter-spacing:-.02em;margin-bottom:4px}
|
|
51
|
+
.kpi span{color:var(--fg2);font-size:13px}
|
|
52
|
+
pre{white-space:pre-wrap;background:#f5f5f7;color:var(--fg);border:1px solid var(--line);border-radius:16px;padding:16px;overflow:auto;font-size:13px;line-height:1.65;max-height:340px;margin-top:14px;font-family:inherit}
|
|
53
|
+
.notice{padding:12px 16px;border-radius:14px;margin:10px 0;font-size:14px}
|
|
54
|
+
.notice.warn{background:#fff7e8;color:#b25b00}
|
|
55
|
+
.notice.err{background:#fff5f5;color:#ff3b30}
|
|
56
|
+
@media(max-width:800px){.wrap{padding:28px 14px 70px}.hero{padding:26px 20px}h1{font-size:30px}.flow{flex-direction:column}}
|
|
57
|
+
</style>
|
|
58
|
+
</head>
|
|
59
|
+
<body>
|
|
60
|
+
<div class="wrap">
|
|
61
|
+
<header class="hero">
|
|
62
|
+
<h1 id="title">批量改分类向导</h1>
|
|
63
|
+
<p class="lead" id="subtitle">数据加载中</p>
|
|
64
|
+
<p class="meta" id="meta"></p>
|
|
65
|
+
</header>
|
|
66
|
+
<section id="injectError" style="display:none"></section>
|
|
67
|
+
|
|
68
|
+
<section class="kpi" id="kpis"></section>
|
|
69
|
+
|
|
70
|
+
<section class="panel">
|
|
71
|
+
<div style="font-weight:700;margin-bottom:10px">🎯 改到哪个分类</div>
|
|
72
|
+
<div class="toolbar">
|
|
73
|
+
<label style="color:var(--fg2);font-size:14px">目标分类:</label>
|
|
74
|
+
<select id="toCatSelect">
|
|
75
|
+
<option value="备忘">备忘</option>
|
|
76
|
+
<option value="心愿">心愿</option>
|
|
77
|
+
<option value="打卡">打卡</option>
|
|
78
|
+
<option value="情绪日记">情绪日记</option>
|
|
79
|
+
</select>
|
|
80
|
+
<div class="toolbar" style="margin-left:auto" id="batchBtns">
|
|
81
|
+
<button class="ghost" onclick="selectAll(true)">全选</button>
|
|
82
|
+
<button class="ghost" onclick="selectAll(false)">清空选择</button>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
<p class="hint">已选择 <b id="selCount">0</b> 条,共 <span id="selTotal">0</span> 条</p>
|
|
86
|
+
</section>
|
|
87
|
+
|
|
88
|
+
<section id="noteList"></section>
|
|
89
|
+
|
|
90
|
+
<section class="panel">
|
|
91
|
+
<div style="font-weight:700;margin-bottom:8px">📋 发给 AI 的指令</div>
|
|
92
|
+
<p style="color:var(--fg2);font-size:13px;margin-bottom:12px">点击后复制指令,粘贴给 AI,AI 会把勾选笔记的分类改成目标分类(子分类保持不变),改完给你回执。</p>
|
|
93
|
+
<div class="toolbar">
|
|
94
|
+
<button class="primary" onclick="adopt()">📋 复制修改指令</button>
|
|
95
|
+
</div>
|
|
96
|
+
<div id="warnArea"></div>
|
|
97
|
+
<pre id="promptOut" style="display:none"></pre>
|
|
98
|
+
</section>
|
|
99
|
+
|
|
100
|
+
<section class="panel">
|
|
101
|
+
<strong>数据与日志</strong>
|
|
102
|
+
<div class="hint">点复制数据保存当前笔记列表 · 点复制日志用于反馈问题(日志不含隐私内容)</div>
|
|
103
|
+
<div class="hm-actions">
|
|
104
|
+
<button class="copy ghost" onclick="copyData()">复制数据</button>
|
|
105
|
+
<button class="copy ghost" onclick="copyLog()">复制日志</button>
|
|
106
|
+
</div>
|
|
107
|
+
</section>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<script id="payload" type="application/json"><!--INJECT-DATA--></script>
|
|
111
|
+
<script><!--SHARED-HELPERS--></script>
|
|
112
|
+
<script>
|
|
113
|
+
(function(){
|
|
114
|
+
"use strict";
|
|
115
|
+
var raw=document.getElementById("payload");
|
|
116
|
+
var payload=null,perr=null;
|
|
117
|
+
try{payload=JSON.parse(raw.textContent||"{}");}catch(e){perr=e.message;}
|
|
118
|
+
if(perr){document.getElementById("injectError").style.display="block";document.getElementById("injectError").innerHTML=window.errorReceipt({message:"数据解析失败",log:perr,payload:null});return;}
|
|
119
|
+
if(!payload||payload.status!=="ok"||!payload.data){document.getElementById("injectError").style.display="block";document.getElementById("injectError").innerHTML=window.errorReceipt({message:(payload&&payload.message)||"数据未注入",retryPrompt:"请重新运行批量改分类(唤醒词:备忘改分类)",payload:null});return;}
|
|
120
|
+
window.__hmPayload=payload;
|
|
121
|
+
function data(){return payload.data}
|
|
122
|
+
function items(){return data().items||[]}
|
|
123
|
+
|
|
124
|
+
function init(){
|
|
125
|
+
var d=data();
|
|
126
|
+
document.getElementById('title').textContent=d.title||'批量改分类向导';
|
|
127
|
+
document.getElementById('subtitle').textContent='勾选下方笔记 → 复制指令 → 粘贴给 AI 帮你完成改分类';
|
|
128
|
+
var meta=d.meta||{};
|
|
129
|
+
document.getElementById('meta').textContent=`从「${d.from_category||'当前分类'}」改到「${d.to_category||'目标分类'}」 · 生成时间:${d.generated_at||''}`;
|
|
130
|
+
if(d.to_category){
|
|
131
|
+
var sel=document.getElementById('toCatSelect');
|
|
132
|
+
sel.value=d.to_category;
|
|
133
|
+
}
|
|
134
|
+
renderKPIs();renderList();
|
|
135
|
+
// success: 笔记列表已加载,等待用户勾选改分类
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function renderKPIs(){
|
|
139
|
+
var all=items();
|
|
140
|
+
var withSub=all.filter(w=>w.sub_category).length;
|
|
141
|
+
document.getElementById('kpis').innerHTML=[
|
|
142
|
+
['待处理笔记',all.length,'勾选要移动的'],
|
|
143
|
+
['含子分类',withSub,'随笔记一起移动'],
|
|
144
|
+
].map(x=>`<div class="stat"><b>${x[1]}</b><span>${x[0]}</span><div style="color:var(--fg3);font-size:12px;margin-top:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${esc(x[2])}</div></div>`).join('');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function renderList(){
|
|
148
|
+
var list=document.getElementById('noteList');
|
|
149
|
+
document.getElementById('batchBtns').style.display=items().length>1?'flex':'none';
|
|
150
|
+
if(!items().length){list.innerHTML='<div class="panel">'+window.emptyState({icon:'🗂',text:'原分类下没有笔记',hint:'换个原分类,或先记一条备忘'})+'</div>';return}
|
|
151
|
+
list.innerHTML=items().map(renderNote).join('');
|
|
152
|
+
items().forEach(function(w){
|
|
153
|
+
var cb=document.getElementById('cb_'+w.id);
|
|
154
|
+
if(cb) cb.addEventListener('change',function(e){document.getElementById('note_'+w.id).classList.toggle('off',!e.target.checked);updateSelCount();});
|
|
155
|
+
});
|
|
156
|
+
document.getElementById('selTotal').textContent=items().length;
|
|
157
|
+
updateSelCount();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function updateSelCount(){
|
|
161
|
+
var checked=items().filter(function(w){
|
|
162
|
+
var cb=document.getElementById('cb_'+w.id);
|
|
163
|
+
return cb&&cb.checked;
|
|
164
|
+
}).length;
|
|
165
|
+
document.getElementById('selCount').textContent=checked;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function renderNote(w){
|
|
169
|
+
var cls=w.selected?'':'off';
|
|
170
|
+
var checked=w.selected?'checked':'';
|
|
171
|
+
return `<article class="note ${cls}" id="note_${w.id}">
|
|
172
|
+
<div class="note-head">
|
|
173
|
+
<input type="checkbox" id="cb_${w.id}" ${checked} data-id="${w.id}" />
|
|
174
|
+
<span class="note-id">#${esc(w.id)}</span>
|
|
175
|
+
<span class="note-content">${esc(w.content)}</span>
|
|
176
|
+
</div>
|
|
177
|
+
<div class="note-meta">
|
|
178
|
+
${w.sub_category?`<span class="badge">${esc(w.sub_category)}</span>`:''}
|
|
179
|
+
${w.media_path?`<span class="badge ok">有附件</span>`:''}
|
|
180
|
+
${w.due?`<span class="badge warn">排期 ${esc(w.due)}</span>`:''}
|
|
181
|
+
</div>
|
|
182
|
+
</article>`;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function selectAll(on){
|
|
186
|
+
items().forEach(function(w){
|
|
187
|
+
var cb=document.getElementById('cb_'+w.id);
|
|
188
|
+
if(cb){cb.checked=on;document.getElementById('note_'+w.id).classList.toggle('off',!on)}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function selectedRows(){
|
|
193
|
+
var targetCat=document.getElementById('toCatSelect').value;
|
|
194
|
+
var rows=[];
|
|
195
|
+
items().forEach(function(w){
|
|
196
|
+
var cb=document.getElementById('cb_'+w.id);
|
|
197
|
+
if(cb&&cb.checked){
|
|
198
|
+
rows.push({id:w.id,content:w.content,from:data().from_category,to:targetCat});
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
return {rows:rows,target:targetCat};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function buildPrompt(rows,target,ctx){
|
|
205
|
+
if(!rows.length) return '未选择任何笔记';
|
|
206
|
+
return [
|
|
207
|
+
'① 场景: 我用批量改分类向导,把 '+rows.length+' 条「'+ctx.from_cat+'」笔记改到「'+target+'」',
|
|
208
|
+
'',
|
|
209
|
+
'② 数据(要改分类的笔记):',
|
|
210
|
+
...rows.map(r=>` · 笔记 #${r.id} "${r.content}"`),
|
|
211
|
+
'',
|
|
212
|
+
'③ 期望: 请把以上笔记的顶层分类从「'+ctx.from_cat+'」改为「'+target+'」,子分类保持不变;改完给我回执。',
|
|
213
|
+
'',
|
|
214
|
+
'④ 来源: 批量改分类向导 · '+ctx.generated_at,
|
|
215
|
+
].join('\n');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function warnIfAny(rows){
|
|
219
|
+
var notes=[];
|
|
220
|
+
if(rows.length>=10){
|
|
221
|
+
notes.push(`<div class="notice warn">⚠️ 批量改 ${rows.length} 条分类,请确认都是预期操作</div>`);
|
|
222
|
+
}
|
|
223
|
+
var dup=data().target_conflict_count||0;
|
|
224
|
+
if(dup>0){
|
|
225
|
+
notes.push(`<div class="notice warn">ℹ️ ${dup} 条目标分类(${document.getElementById('toCatSelect').value})下已有同名笔记</div>`);
|
|
226
|
+
}
|
|
227
|
+
document.getElementById('warnArea').innerHTML=notes.join('');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function adopt(){
|
|
231
|
+
var sel=selectedRows();
|
|
232
|
+
var rows=sel.rows,target=sel.target;
|
|
233
|
+
if(!rows.length){window.toast('未选择任何笔记','勾选要改分类的笔记',{icon:'warn'});return}
|
|
234
|
+
warnIfAny(rows);
|
|
235
|
+
var ctx={
|
|
236
|
+
from_cat:data().from_category||'',
|
|
237
|
+
to_cat:target,
|
|
238
|
+
generated_at:data().generated_at||'',
|
|
239
|
+
};
|
|
240
|
+
var text=buildPrompt(rows,target,ctx);
|
|
241
|
+
var out=document.getElementById('promptOut');
|
|
242
|
+
out.textContent=text;out.style.display='block';
|
|
243
|
+
window.copyText(text,{silent:true});
|
|
244
|
+
window.toast('指令已复制','粘贴发给 AI 即可执行',{icon:'ok'});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function copyData(){window.copyText(window.buildDataText(payload),{silent:true});window.toast('数据已复制','人类可读快照 · 可粘贴到笔记存档',{icon:'copy'});}
|
|
248
|
+
function copyLog(){window.copyText(window.buildLogText(payload),{silent:true});window.toast('日志已复制','诊断信息 · 有异常时粘贴给开发者排查',{icon:'copy'});}
|
|
249
|
+
window.selectAll=selectAll;
|
|
250
|
+
window.adopt=adopt;
|
|
251
|
+
window.copyData=copyData;
|
|
252
|
+
window.copyLog=copyLog;
|
|
253
|
+
init();
|
|
254
|
+
})();
|
|
255
|
+
</script>
|
|
256
|
+
</body>
|
|
257
|
+
</html>
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
|
|
6
|
+
<meta name="color-scheme" content="light">
|
|
7
|
+
<title>备忘录 · 初始化报告</title>
|
|
8
|
+
<style><!--SHARED-CSS--></style>
|
|
9
|
+
<style>
|
|
10
|
+
/* ================================================================
|
|
11
|
+
备忘录初始化报告 · 过程型 HTML(#8 经验:场景 HTML 承载 AI 执行证据)
|
|
12
|
+
设计原则:
|
|
13
|
+
1. 移动优先:480px 居中,PC 不空
|
|
14
|
+
2. 首屏结论:就绪度汇总 → 逐项检查清单 → 待办指引
|
|
15
|
+
3. 承诺↔兑现:prompt 说 5 步,HTML 每步有对应物
|
|
16
|
+
4. 状态色:绿=就绪 / 橙=可选缺失 / 红=必装缺失
|
|
17
|
+
5. 自包含:零外链 · 原生 details 折叠
|
|
18
|
+
================================================================ */
|
|
19
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
20
|
+
:root{
|
|
21
|
+
--fg:#1d1d1f;--fg2:#6e6e73;--fg3:#86868b;
|
|
22
|
+
--bg:#f5f5f7;--card:#fff;--line:#d2d2d7;
|
|
23
|
+
--ok:#34c759;--ok-soft:#ecfff2;--ok-fg:#178a3a;
|
|
24
|
+
--warn:#ff9500;--warn-soft:#fff7e8;--warn-fg:#b25b00;
|
|
25
|
+
--err:#ff3b30;--err-soft:#fff5f5;--err-fg:#c7254e;
|
|
26
|
+
--shadow-md:0 1px 3px rgba(0,0,0,.04),0 12px 36px rgba(0,0,0,.06);
|
|
27
|
+
--font:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif;
|
|
28
|
+
}
|
|
29
|
+
html{-webkit-text-size-adjust:100%}
|
|
30
|
+
body{font-family:var(--font);background:var(--bg);color:var(--fg);line-height:1.6;-webkit-font-smoothing:antialiased;padding:0 env(safe-area-inset-right,0) env(safe-area-inset-bottom,0) env(safe-area-inset-left,0)}
|
|
31
|
+
.wrap{max-width:480px;margin:0 auto;padding:max(20px,env(safe-area-inset-top,0)) 16px calc(40px + env(safe-area-inset-bottom,0))}
|
|
32
|
+
|
|
33
|
+
/* ===== 首屏状态卡 ===== */
|
|
34
|
+
.status-card{background:var(--card);border-radius:20px;padding:24px 22px;margin:16px 0 14px;box-shadow:var(--shadow-md);text-align:center}
|
|
35
|
+
.status-icon{font-size:32px;line-height:1;margin-bottom:10px}
|
|
36
|
+
.status-title{font-size:20px;font-weight:700;letter-spacing:-.01em}
|
|
37
|
+
.status-sub{font-size:13.5px;color:var(--fg2);margin-top:8px}
|
|
38
|
+
.status-meta{font-size:12px;color:var(--fg3);margin-top:10px}
|
|
39
|
+
|
|
40
|
+
/* ===== 段落 ===== */
|
|
41
|
+
.section-title{font-size:13px;font-weight:700;color:var(--fg3);letter-spacing:.06em;margin:22px 0 8px;text-transform:uppercase}
|
|
42
|
+
|
|
43
|
+
/* ===== 检查清单(逐项) ===== */
|
|
44
|
+
.check-item{background:var(--card);border-radius:14px;padding:12px 14px;margin-bottom:8px;border:1px solid var(--line);display:flex;gap:10px;align-items:flex-start}
|
|
45
|
+
.check-item .st{flex-shrink:0;font-size:16px;line-height:1.4;min-width:22px;text-align:center}
|
|
46
|
+
.check-item .body{flex:1;min-width:0}
|
|
47
|
+
.check-item .name{font-size:14px;font-weight:600}
|
|
48
|
+
.check-item .desc{font-size:12.5px;color:var(--fg2);margin-top:2px}
|
|
49
|
+
.check-item .action{font-size:12.5px;margin-top:4px;padding:5px 10px;border-radius:8px;display:inline-block}
|
|
50
|
+
.check-item.ok{background:var(--ok-soft);border-color:transparent}
|
|
51
|
+
.check-item.ok .name{color:var(--ok-fg)}
|
|
52
|
+
.check-item.warn{background:var(--warn-soft);border-color:transparent}
|
|
53
|
+
.check-item.warn .action{background:#fff;color:var(--warn-fg)}
|
|
54
|
+
.check-item.err{background:var(--err-soft);border-color:transparent}
|
|
55
|
+
.check-item.err .name{color:var(--err-fg)}
|
|
56
|
+
.check-item.err .action{background:#fff;color:var(--err-fg)}
|
|
57
|
+
|
|
58
|
+
/* ===== 待办指引 ===== */
|
|
59
|
+
.todo-card{background:var(--card);border-radius:14px;padding:14px 16px;margin-bottom:8px;border:1px solid var(--line)}
|
|
60
|
+
.todo-card .todo-title{font-size:13.5px;font-weight:700;margin-bottom:6px}
|
|
61
|
+
.todo-card ol{padding-left:18px;font-size:13px;color:var(--fg2)}
|
|
62
|
+
.todo-card li{margin-bottom:4px}
|
|
63
|
+
|
|
64
|
+
/* ===== 完成验证清单(承诺↔兑现 · #299 去勾选框:徽章已表达状态) ===== */
|
|
65
|
+
.verify-card{background:var(--card);border-radius:14px;padding:14px 16px;border:1px solid var(--line)}
|
|
66
|
+
.verify-card .verify-title{font-size:13.5px;font-weight:700;margin-bottom:6px}
|
|
67
|
+
.verify-item{display:flex;gap:8px;align-items:flex-start;padding:6px 0;font-size:13px;color:var(--fg2)}
|
|
68
|
+
/* 三态徽章(#197 · 飞书权限已实测:已实测 ✓ / 跳过 / 未通过 ✗) */
|
|
69
|
+
.verify-badge{font-size:11px;font-weight:800;border-radius:999px;padding:1px 10px;margin-left:auto;white-space:nowrap;flex:none}
|
|
70
|
+
.verify-badge.ok{background:var(--ok-soft);color:var(--ok-fg)}
|
|
71
|
+
.verify-badge.skip{background:#f0f0f3;color:var(--fg3)}
|
|
72
|
+
.verify-badge.fail{background:var(--err-soft);color:var(--err-fg)}
|
|
73
|
+
|
|
74
|
+
/* ===== 数据与日志 ===== */
|
|
75
|
+
.data-panel{background:var(--card);border-radius:14px;padding:14px 16px;border:1px solid var(--line);margin-top:14px}
|
|
76
|
+
.data-panel strong{font-size:13.5px}
|
|
77
|
+
.data-panel .hint{font-size:12px;color:var(--fg3);margin-top:6px}
|
|
78
|
+
|
|
79
|
+
@media(max-width:360px){.check-item .name{font-size:13px}.status-card{padding:20px 16px}}
|
|
80
|
+
</style>
|
|
81
|
+
</head>
|
|
82
|
+
<body>
|
|
83
|
+
<div class="wrap">
|
|
84
|
+
<div class="status-card" id="statusCard">
|
|
85
|
+
<div class="status-icon" id="statusIcon">🔍</div>
|
|
86
|
+
<div class="status-title" id="statusTitle">环境检查中…</div>
|
|
87
|
+
<div class="status-sub" id="statusSub">加载检查结果</div>
|
|
88
|
+
<div class="status-meta" id="statusMeta"></div>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<section id="injectError" style="display:none"></section>
|
|
92
|
+
<section id="stateArea"></section>
|
|
93
|
+
|
|
94
|
+
<main id="bodyContent"></main>
|
|
95
|
+
|
|
96
|
+
<section class="data-panel" id="dataPanel">
|
|
97
|
+
<strong>数据与日志</strong>
|
|
98
|
+
<div class="hint">点复制数据保存当前检查结果 · 点复制日志用于反馈问题</div>
|
|
99
|
+
<div class="hm-actions">
|
|
100
|
+
<button class="copy ghost" onclick="copyData()">复制数据</button>
|
|
101
|
+
<button class="copy ghost" onclick="copyLog()">复制日志</button>
|
|
102
|
+
</div>
|
|
103
|
+
</section>
|
|
104
|
+
<p style="text-align:center;color:var(--fg3);font-size:12px;margin-top:14px">补齐后回到对话,告诉 AI「重新检查」即可刷新本页</p>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<script id="payload" type="application/json"><!--INJECT-DATA--></script>
|
|
108
|
+
<script><!--SHARED-HELPERS--></script>
|
|
109
|
+
<script>
|
|
110
|
+
(function(){
|
|
111
|
+
"use strict";
|
|
112
|
+
var raw=document.getElementById("payload");
|
|
113
|
+
var payload=null,perr=null;
|
|
114
|
+
try{payload=JSON.parse(raw.textContent||"{}");}catch(e){perr=e.message;}
|
|
115
|
+
if(perr){document.getElementById("injectError").style.display="block";document.getElementById("injectError").innerHTML=window.errorReceipt({message:"数据解析失败",log:perr,payload:null});return;}
|
|
116
|
+
if(!payload||payload.status!=="ok"||!payload.data){document.getElementById("injectError").style.display="block";document.getElementById("injectError").innerHTML=window.errorReceipt({message:(payload&&payload.message)||"数据未注入",retryPrompt:"请重新运行首次使用(唤醒词:首次使用)",payload:null});return;}
|
|
117
|
+
window.__hmPayload=payload;
|
|
118
|
+
|
|
119
|
+
try{
|
|
120
|
+
var d=payload.data;
|
|
121
|
+
var items=Array.isArray(d.items)?d.items:[];
|
|
122
|
+
|
|
123
|
+
if(items.length===0){
|
|
124
|
+
// #299:空态 → Base emptyState(替代旧 4 状态横幅)
|
|
125
|
+
document.getElementById('stateArea').innerHTML=window.emptyState({
|
|
126
|
+
icon:'📭',text:'暂无检查数据',hint:'AI 诊断结果为空,请重新运行首次使用'
|
|
127
|
+
});
|
|
128
|
+
document.getElementById('statusCard').style.display='none';
|
|
129
|
+
document.getElementById('dataPanel').style.display='none';
|
|
130
|
+
}else{
|
|
131
|
+
|
|
132
|
+
// 汇总
|
|
133
|
+
var ready=items.filter(function(i){return i.status==='ok'}).length;
|
|
134
|
+
var warn=items.filter(function(i){return i.status==='warn'}).length;
|
|
135
|
+
var err=items.filter(function(i){return i.status==='err'}).length;
|
|
136
|
+
var icon=err>0?'❌':(warn>0?'⚠️':'✅');
|
|
137
|
+
var title=err>0?'环境未就绪':(warn>0?'部分就绪':'环境就绪');
|
|
138
|
+
document.getElementById('statusIcon').textContent=icon;
|
|
139
|
+
document.getElementById('statusTitle').textContent=title;
|
|
140
|
+
document.getElementById('statusSub').textContent=ready+' 项正常 · '+warn+' 项需补 · '+err+' 项可选';
|
|
141
|
+
document.getElementById('statusMeta').textContent=(d.generated_at?'生成于 '+d.generated_at+' · ':'')+'共 '+items.length+' 项检查';
|
|
142
|
+
|
|
143
|
+
var main=document.getElementById('bodyContent');
|
|
144
|
+
main.innerHTML='';
|
|
145
|
+
|
|
146
|
+
// 检查清单
|
|
147
|
+
var sec1=document.createElement('div');sec1.className='section-title';sec1.textContent='环境检查';
|
|
148
|
+
main.appendChild(sec1);
|
|
149
|
+
items.forEach(function(i){
|
|
150
|
+
var el=document.createElement('div');el.className='check-item '+esc(i.status||'err');
|
|
151
|
+
var st=document.createElement('div');st.className='st';
|
|
152
|
+
st.textContent=i.status==='ok'?'✅':(i.status==='warn'?'⚠️':'❌');
|
|
153
|
+
el.appendChild(st);
|
|
154
|
+
var body=document.createElement('div');body.className='body';
|
|
155
|
+
var name=document.createElement('div');name.className='name';name.textContent=esc(i.name);
|
|
156
|
+
body.appendChild(name);
|
|
157
|
+
if(i.desc){var d1=document.createElement('div');d1.className='desc';d1.textContent=esc(i.desc);body.appendChild(d1)}
|
|
158
|
+
if(i.action){var a=document.createElement('div');a.className='action';a.textContent=esc(i.action);body.appendChild(a)}
|
|
159
|
+
el.appendChild(body);
|
|
160
|
+
main.appendChild(el);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// 待办指引
|
|
164
|
+
var todos=Array.isArray(d.todos)?d.todos:[];
|
|
165
|
+
if(todos.length){
|
|
166
|
+
var sec2=document.createElement('div');sec2.className='section-title';sec2.textContent='待办指引';
|
|
167
|
+
main.appendChild(sec2);
|
|
168
|
+
todos.forEach(function(t){
|
|
169
|
+
var card=document.createElement('div');card.className='todo-card';
|
|
170
|
+
var tt=document.createElement('div');tt.className='todo-title';tt.textContent=esc(t.title||'');
|
|
171
|
+
card.appendChild(tt);
|
|
172
|
+
if(Array.isArray(t.steps)){
|
|
173
|
+
var ol=document.createElement('ol');
|
|
174
|
+
t.steps.forEach(function(s){var li=document.createElement('li');li.textContent=esc(s);ol.appendChild(li)});
|
|
175
|
+
card.appendChild(ol);
|
|
176
|
+
}
|
|
177
|
+
main.appendChild(card);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 完成验证清单(承诺↔兑现:prompt 5 步 → 可勾选)
|
|
182
|
+
var verify=Array.isArray(d.verify)?d.verify:[];
|
|
183
|
+
if(verify.length){
|
|
184
|
+
var sec3=document.createElement('div');sec3.className='section-title';sec3.textContent='完成验证清单';
|
|
185
|
+
main.appendChild(sec3);
|
|
186
|
+
var vc=document.createElement('div');vc.className='verify-card';
|
|
187
|
+
var vt=document.createElement('div');vt.className='verify-title';vt.textContent='请核对每项状态;跳过/未通过的建议手动补做,完成后告诉 AI 收尾';
|
|
188
|
+
vc.appendChild(vt);
|
|
189
|
+
verify.forEach(function(v){
|
|
190
|
+
var vi=document.createElement('div');vi.className='verify-item';
|
|
191
|
+
var tx=document.createElement('span');
|
|
192
|
+
// 兼容两种形态(#197):str = 旧契约; {text, status: ok|skip|fail} = 三态(飞书权限已实测)
|
|
193
|
+
var status='';
|
|
194
|
+
if(v&&typeof v==='object'){
|
|
195
|
+
status=v.status||'';
|
|
196
|
+
tx.textContent=esc(v.text||'');
|
|
197
|
+
}else{
|
|
198
|
+
tx.textContent=esc(v);
|
|
199
|
+
}
|
|
200
|
+
vi.appendChild(tx);
|
|
201
|
+
if(status){
|
|
202
|
+
var badge=document.createElement('span');badge.className='verify-badge '+status;
|
|
203
|
+
var labelMap={ok:'已实测',skip:'跳过',fail:'未通过'};
|
|
204
|
+
badge.textContent=labelMap[status]||status;
|
|
205
|
+
vi.appendChild(badge);
|
|
206
|
+
}
|
|
207
|
+
vc.appendChild(vi);
|
|
208
|
+
});
|
|
209
|
+
main.appendChild(vc);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// success: 初始化报告已渲染(检查清单 + 待办 + 验证清单)
|
|
213
|
+
}catch(e){
|
|
214
|
+
document.getElementById("injectError").style.display="block";
|
|
215
|
+
document.getElementById("injectError").innerHTML=window.errorReceipt({message:"渲染失败:"+e.message,payload:null});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function copyData(){window.copyText(window.buildDataText(payload),{silent:true});window.toast('数据已复制','人类可读快照 · 可粘贴到笔记存档',{icon:'copy'});}
|
|
219
|
+
function copyLog(){window.copyText(window.buildLogText(payload),{silent:true});window.toast('日志已复制','诊断信息 · 有异常时粘贴给开发者排查',{icon:'copy'});}
|
|
220
|
+
window.copyData=copyData;
|
|
221
|
+
window.copyLog=copyLog;
|
|
222
|
+
})();
|
|
223
|
+
</script>
|
|
224
|
+
</body>
|
|
225
|
+
</html>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<title>备忘录查询结果</title>
|
|
7
|
+
<style><!--SHARED-CSS--></style>
|
|
8
|
+
<style>
|
|
9
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
10
|
+
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
|
|
11
|
+
body{font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif;background:var(--bg);color:var(--fg);line-height:1.65;-webkit-font-smoothing:antialiased}
|
|
12
|
+
.wrap{max-width:1120px;margin:0 auto;padding:48px 22px 90px}
|
|
13
|
+
.hero{background:linear-gradient(180deg,#fff 0%,#f8fbff 100%);border-radius:28px;padding:34px;margin-bottom:20px;box-shadow:var(--shadow-md,0 1px 2px rgba(0,0,0,.04),0 12px 36px rgba(0,0,0,.06))}
|
|
14
|
+
.eyebrow{font-size:13px;color:var(--blue);font-weight:800;letter-spacing:.08em;text-transform:uppercase;margin-bottom:10px}
|
|
15
|
+
h1{font-size:38px;line-height:1.15;letter-spacing:-.035em;margin-bottom:12px}.lead{color:var(--fg2);font-size:17px}.meta{margin-top:16px;color:var(--fg3);font-size:13px}
|
|
16
|
+
.grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin:18px 0}.stat,.panel,.item{background:var(--card);border-radius:20px;padding:18px;box-shadow:0 1px 3px rgba(0,0,0,.04)}.panel{margin:14px 0}
|
|
17
|
+
.stat b{display:block;font-size:22px;letter-spacing:-.02em;font-weight:800}.stat span{color:var(--fg2);font-size:13px;font-weight:600}.toolbar{display:flex;gap:10px;flex-wrap:wrap;margin:14px 0}.pill{border:1px solid var(--line);background:#fff;border-radius:999px;padding:7px 12px;font-size:13px;color:var(--fg2);cursor:pointer}.pill.active{background:#eef5ff;color:var(--blue);border-color:#b8d8ff}
|
|
18
|
+
.item{margin:12px 0}.item-head{display:flex;justify-content:space-between;gap:14px;align-items:flex-start}.id{color:var(--blue);font-weight:800}.content{font-size:17px;margin:10px 0;white-space:pre-wrap}.muted{color:var(--fg2)}.small{font-size:13px;color:var(--fg3)}.badge{display:inline-block;background:var(--soft,#f5f8ff);color:var(--blue);padding:3px 9px;border-radius:999px;font-size:12px;font-weight:700;margin:3px 5px 3px 0}.badge.warn{background:#fff7e8;color:#b25b00}.badge.ok{background:#ecfff2;color:#178a3a}
|
|
19
|
+
#list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;align-items:stretch;margin:14px 0}
|
|
20
|
+
#list .item{margin:0;padding:14px;display:flex;flex-direction:column;height:100%}
|
|
21
|
+
#list .hm-empty{grid-column:1/-1}
|
|
22
|
+
#list .item-head{flex-wrap:nowrap;gap:6px;min-height:32px;align-items:center}
|
|
23
|
+
#list .id{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
24
|
+
#list .item-head button.copy{flex:0 0 auto;min-height:30px;padding:5px 12px;font-size:12px}
|
|
25
|
+
#list .content{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:14px;margin:8px 0;word-break:break-all;flex:1 1 auto}
|
|
26
|
+
#list .item .badge{font-size:11px;padding:2px 8px;margin:2px 4px 2px 0}
|
|
27
|
+
#list .small{font-size:12px;margin-top:auto;padding-top:8px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
28
|
+
.empty{padding:42px;text-align:center;color:var(--fg2)}button{border:0;background:var(--blue);color:#fff;border-radius:999px;padding:8px 12px;cursor:pointer}.item-head button.copy{flex:0 0 auto;min-height:40px;padding:8px 16px;font-size:13px}input{width:100%;border:1px solid var(--line);border-radius:14px;padding:12px 14px;font-size:15px;margin-top:12px}pre{white-space:pre-wrap;background:#f5f5f7;color:var(--fg);border:1px solid var(--line);border-radius:16px;padding:16px;overflow:auto;font-size:13px;line-height:1.65;font-family:inherit}
|
|
29
|
+
@media(max-width:800px){.wrap{padding:28px 14px 70px}.hero{padding:26px 20px}.grid{grid-template-columns:repeat(2,minmax(0,1fr))}h1{font-size:30px}.item-head{flex-wrap:wrap}}
|
|
30
|
+
</style>
|
|
31
|
+
</head>
|
|
32
|
+
<body>
|
|
33
|
+
<div class="wrap">
|
|
34
|
+
<header class="hero">
|
|
35
|
+
<h1 id="title">备忘录查询结果</h1>
|
|
36
|
+
<p class="lead" id="subtitle">数据加载中</p>
|
|
37
|
+
<p class="meta" id="meta"></p>
|
|
38
|
+
</header>
|
|
39
|
+
<section id="injectError" style="display:none"></section>
|
|
40
|
+
<section class="grid" id="stats"></section>
|
|
41
|
+
<section class="panel">
|
|
42
|
+
<strong>筛选与检索</strong>
|
|
43
|
+
<label for="filter" class="sr-only">在结果内搜索内容</label>
|
|
44
|
+
<input id="filter" aria-label="在结果内搜索内容" placeholder="输入关键词搜索笔记内容">
|
|
45
|
+
<div class="toolbar" id="chips"></div>
|
|
46
|
+
<div class="toolbar" id="length-mode-bar" style="display:none"><button id="lengthModeBtn" class="copy" type="button">显示全部</button><span id="lengthModeHint" class="small"></span></div>
|
|
47
|
+
</section>
|
|
48
|
+
<section id="list"></section>
|
|
49
|
+
<section class="panel">
|
|
50
|
+
<strong>筛选快照</strong>
|
|
51
|
+
<p class="small" style="margin-top:6px">跟随筛选/展开实时变化 · 粘贴给 AI 继续下一步(复制数据 = 初始全量存档)</p>
|
|
52
|
+
<div class="toolbar"><button class="copy ghost" data-copy-receipt onclick="copyFiltered()">复制筛选结果</button></div>
|
|
53
|
+
<pre id="receipt" style="display:none"></pre>
|
|
54
|
+
</section>
|
|
55
|
+
<section class="panel">
|
|
56
|
+
<strong>数据与日志</strong>
|
|
57
|
+
<p class="small" style="margin-top:6px">点复制数据保存当前结果 · 点复制日志用于反馈问题(日志不含隐私内容)</p>
|
|
58
|
+
<div class="hm-actions">
|
|
59
|
+
<button class="copy ghost" onclick="copyData()">复制数据</button>
|
|
60
|
+
<button class="copy ghost" onclick="copyLog()">复制日志</button>
|
|
61
|
+
</div>
|
|
62
|
+
</section>
|
|
63
|
+
</div>
|
|
64
|
+
<script id="payload" type="application/json"><!--INJECT-DATA--></script>
|
|
65
|
+
<script><!--SHARED-HELPERS--></script>
|
|
66
|
+
<script>
|
|
67
|
+
(function(){
|
|
68
|
+
"use strict";
|
|
69
|
+
var raw=document.getElementById("payload");
|
|
70
|
+
var payload=null,perr=null;
|
|
71
|
+
try{payload=JSON.parse(raw.textContent||"{}");}catch(e){perr=e.message;}
|
|
72
|
+
if(perr){document.getElementById("injectError").style.display="block";document.getElementById("injectError").innerHTML=window.errorReceipt({message:"数据解析失败",log:perr,payload:null});return;}
|
|
73
|
+
if(!payload||payload.status!=="ok"||!payload.data){document.getElementById("injectError").style.display="block";document.getElementById("injectError").innerHTML=window.errorReceipt({message:(payload&&payload.message)||"数据未注入",retryPrompt:"请重新运行查询命令(唤醒词:查备忘)",payload:null});return;}
|
|
74
|
+
window.__hmPayload=payload;
|
|
75
|
+
const MAX_DEFAULT = 50;
|
|
76
|
+
var appState={category:'全部',q:'',showAll:false};
|
|
77
|
+
function dataRows(){var d=payload.data;if(Array.isArray(d))return d;if(Array.isArray(d.items))return d.items;if(d.item)return [d.item];return []}
|
|
78
|
+
function init(){var d=payload.data;document.getElementById('title').textContent=d.title||'备忘录查询结果';document.getElementById('subtitle').textContent=payload.message||d.subtitle||'查询完成';var meta=d.meta||{};document.getElementById('meta').textContent=`生成时间:${d.generated_at||''} · 场景:${meta.command_cn||d.command||''}`;renderStats();renderChips();renderList();renderReceipt();// success: 数据加载完成,内容已渲染
|
|
79
|
+
}
|
|
80
|
+
function rowsFiltered(){var rows=dataRows();if(appState.category!=='全部')rows=rows.filter(x=>(x.category||x.repeat_type||'未分类')===appState.category);if(appState.q){var q=appState.q.toLowerCase();rows=rows.filter(x=>String(x.content||'').toLowerCase().includes(q))}return rows}
|
|
81
|
+
function categories(){return ['全部',...Array.from(new Set(dataRows().map(x=>x.category||x.repeat_type||'未分类').filter(Boolean)))]}
|
|
82
|
+
function renderStats(){var rows=dataRows();var due=rows.filter(x=>x.due).length;var sample=rows[0]||{};var hasMediaField='media_path' in sample;var media=hasMediaField?rows.filter(x=>x.media_path).length:'—';var reminders=rows.filter(x=>x.remind_at||x.reminder_id).length;document.getElementById('stats').innerHTML=[['总数',rows.length],['有排期',due],['有附件',media],['有提醒',reminders]].map(x=>`<div class="stat"><b>${x[1]}</b><span>${esc(x[0])}</span></div>`).join('')}
|
|
83
|
+
function renderChips(){document.getElementById('chips').innerHTML=categories().map(c=>`<span class="pill ${c===appState.category?'active':''}" data-cat="${esc(c)}">${esc(c)}</span>`).join('');var chipBar=document.getElementById('chips');if(chipBar&&!chipBar.dataset.bound){chipBar.addEventListener('click',function(e){var pill=e.target.closest('.pill');if(pill&&pill.dataset.cat){setCat(pill.dataset.cat)}});chipBar.dataset.bound='1'}}
|
|
84
|
+
function setCat(c){appState.category=c;renderChips();renderList();renderReceipt()}
|
|
85
|
+
document.getElementById('filter').addEventListener('input',e=>{appState.q=e.target.value;renderList();renderReceipt()});
|
|
86
|
+
document.getElementById('lengthModeBtn').addEventListener('click',toggleLengthMode);
|
|
87
|
+
function renderList(){var all=rowsFiltered();var totalCount=all.length;var cap=appState.showAll?totalCount:Math.min(MAX_DEFAULT,totalCount);var rows=all.slice(0,cap);var list=document.getElementById('list');if(!all.length){list.innerHTML=window.emptyState({icon:'🔍',text:'没有匹配结果',hint:'换关键词或分类再试'});document.getElementById('length-mode-bar').style.display='none';return}list.innerHTML=rows.map(renderItem).join('');var bar=document.getElementById('length-mode-bar');var btn=document.getElementById('lengthModeBtn');var hint=document.getElementById('lengthModeHint');if(totalCount>MAX_DEFAULT){bar.style.display='flex';btn.textContent=appState.showAll?`显示前 ${MAX_DEFAULT} 条`:`显示全部 (${totalCount} 条)`;hint.textContent=appState.showAll?`已展开全部 · 滚到底可看完`: `默认仅显示前 ${MAX_DEFAULT} 条`;}else{bar.style.display='none'}}
|
|
88
|
+
function toggleLengthMode(){appState.showAll=!appState.showAll;renderList();renderReceipt()}
|
|
89
|
+
function renderItem(x){var id=x.id||x.checkin_note_id||x.reminder_id||'';var content=x.content||x.checkin_content||x.reminder_content||x.note_content||'';var badges=[x.category,x.sub_category,x.repeat_type,x.due?`排期 ${x.due}`:'',x.remind_at?`提醒 ${x.remind_at}`:'',x.media_path?'附件':''].filter(Boolean);var created=String(x.created_at||x.checkin_at||'').slice(5,16);var updated=String(x.updated_at||'').slice(5,16);var timeRow=updated&&updated!==created?`<p class="small">创建:${esc(created)} 改:${esc(updated)}</p>`:`<p class="small">创建:${esc(created)}</p>`;return `<article class="item"><div class="item-head"><div class="id">#${esc(id)}</div><button class="copy ghost" data-item='${esc(JSON.stringify(x))}' onclick="copyInfo(this)">复制</button></div><div class="content">${esc(content)}</div><div>${badges.map(b=>`<span class="badge ${String(b).includes('排期')||String(b).includes('提醒')?'warn':''}">${esc(b)}</span>`).join('')}</div>${timeRow}</article>`}
|
|
90
|
+
function snapshotText(){var d=payload.data;var filtered=rowsFiltered();var meta=d.meta||{};var text=`① 场景: 我在备忘录查询页筛选出了 ${filtered.length} 条结果(共 ${dataRows().length} 条)\n\n② 数据(筛选后):`;if(!filtered.length){text+='\n (无匹配结果 · 请调整筛选)';}filtered.forEach(function(x){text+=`\n · #${x.id||x.checkin_note_id||x.reminder_id||''} [${esc(x.category||'未分类')}${x.sub_category?'/'+esc(x.sub_category):''}] ${esc(x.created_at||x.checkin_at||'')}\n ${esc((x.content||x.checkin_content||'').slice(0,80))}`;});text+=`\n\n③ 期望: 请基于以上结果继续下一步(修改/删除/改分类/关联提醒等,我会补充说明)\n\n④ 来源: ${meta.command_cn||d.command||'search'} · 筛选: ${appState.category}${appState.q?' / '+appState.q:''} · ${d.generated_at||''}`;return text}
|
|
91
|
+
function renderReceipt(){document.getElementById('receipt').textContent=snapshotText()}
|
|
92
|
+
function copyInfo(btn){try{var raw=btn.getAttribute('data-item').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"').replace(/'/g,"'").replace(/&/g,'&');var x=JSON.parse(raw);var id=x.id||x.checkin_note_id||x.reminder_id||'';var content=x.content||x.checkin_content||'';var cat=x.category||'未分类';var sub=x.sub_category?'/'+x.sub_category:'';var created=x.created_at||x.checkin_at||'';var text=`备忘录 #${id}\n分类: ${cat}${sub}\n创建: ${created}\n内容: ${content}\n`;if(x.due)text+=`排期: ${x.due}\n`;if(x.remind_at)text+=`提醒: ${x.remind_at}\n`;window.copyText(text,{silent:true});window.toast('已复制这条备忘','#'+id+' · '+content.slice(0,20),{icon:'copy'});}catch(e){window.toast('复制失败','长按选择文本手动复制',{badge:{text:'失败',type:'danger'}})}}
|
|
93
|
+
function copyFiltered(){var text=snapshotText();if(!text)return;var out=document.getElementById('receipt');out.textContent=text;out.style.display='block';window.copyText(text,{silent:true});window.toast('筛选结果已复制','粘贴给 AI 继续下一步',{icon:'copy'});}
|
|
94
|
+
function copyData(){window.copyText(window.buildDataText(payload),{silent:true});window.toast('数据已复制','人类可读快照 · 可粘贴到笔记存档',{icon:'copy'});}
|
|
95
|
+
function copyLog(){window.copyText(window.buildLogText(payload),{silent:true});window.toast('日志已复制','诊断信息 · 有异常时粘贴给开发者排查',{icon:'copy'});}
|
|
96
|
+
window.copyInfo=copyInfo;
|
|
97
|
+
window.copyFiltered=copyFiltered;
|
|
98
|
+
window.copyData=copyData;
|
|
99
|
+
window.copyLog=copyLog;
|
|
100
|
+
init();
|
|
101
|
+
})();
|
|
102
|
+
</script>
|
|
103
|
+
</body>
|
|
104
|
+
</html>
|