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
|
@@ -0,0 +1,512 @@
|
|
|
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
|
+
备忘录同步报告 · mobile-first Apple 风
|
|
12
|
+
设计原则:
|
|
13
|
+
1. 移动优先:480px 居中,PC 也不空(类 Apple Mail 窄列)
|
|
14
|
+
2. 信息分层:首屏结论 → KPI → 按需展开明细
|
|
15
|
+
3. 零假动作:没数据就不展示,无"查看""跳过"链接
|
|
16
|
+
4. 原生 <details>:无 JS 折叠,移动端触控友好
|
|
17
|
+
5. 自包含:零外链(飞书 webview 兼容)
|
|
18
|
+
6. 状态色:绿=完成 / 橙=需注意 / 红=错误 / 灰=无变化
|
|
19
|
+
================================================================ */
|
|
20
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
21
|
+
:root{
|
|
22
|
+
--fg:#1d1d1f;--fg2:#6e6e73;--fg3:#86868b;--fg4:#aeaeb2;
|
|
23
|
+
--bg:#f5f5f7;--card:#fff;--card2:#fbfbfd;--line:#d2d2d7;--line-soft:#e5e5ea;
|
|
24
|
+
--ok:#34c759;--ok-soft:#ecfff2;--ok-fg:#178a3a;
|
|
25
|
+
--warn:#ff9500;--warn-soft:#fff7e8;--warn-fg:#b25b00;
|
|
26
|
+
--err:#ff3b30;--err-soft:#fff5f5;--err-fg:#c7254e;
|
|
27
|
+
--shadow-sm:0 1px 2px rgba(0,0,0,.04);
|
|
28
|
+
--shadow-md:0 1px 3px rgba(0,0,0,.04),0 12px 36px rgba(0,0,0,.06);
|
|
29
|
+
--shadow-lg:0 1px 3px rgba(0,0,0,.04),0 24px 48px rgba(0,0,0,.08);
|
|
30
|
+
--font:-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
|
|
31
|
+
--font-mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
|
|
32
|
+
}
|
|
33
|
+
html{-webkit-text-size-adjust:100%}
|
|
34
|
+
body{
|
|
35
|
+
font-family:var(--font);
|
|
36
|
+
background:var(--bg);
|
|
37
|
+
color:var(--fg);
|
|
38
|
+
line-height:1.6;
|
|
39
|
+
-webkit-font-smoothing:antialiased;
|
|
40
|
+
-moz-osx-font-smoothing:grayscale;
|
|
41
|
+
padding:0 env(safe-area-inset-right,0) env(safe-area-inset-bottom,0) env(safe-area-inset-left,0);
|
|
42
|
+
}
|
|
43
|
+
.wrap{
|
|
44
|
+
max-width:480px;
|
|
45
|
+
margin:0 auto;
|
|
46
|
+
padding:max(20px,env(safe-area-inset-top,0)) 16px calc(40px + env(safe-area-inset-bottom,0));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* ===== 状态卡(首屏 · 结论优先) ===== */
|
|
50
|
+
.status-card{
|
|
51
|
+
background:var(--card);
|
|
52
|
+
border-radius:20px;
|
|
53
|
+
padding:24px 22px;
|
|
54
|
+
margin:16px 0 14px;
|
|
55
|
+
box-shadow:var(--shadow-md);
|
|
56
|
+
text-align:center;
|
|
57
|
+
position:relative;
|
|
58
|
+
overflow:hidden;
|
|
59
|
+
}
|
|
60
|
+
.status-card.ok{background:linear-gradient(180deg,#fff 0%,#ebfaef 100%)}
|
|
61
|
+
.status-card.warn{background:linear-gradient(180deg,#fff 0%,#fff7e0 100%)}
|
|
62
|
+
.status-card.err{background:linear-gradient(180deg,#fff 0%,#ffe8e6 100%)}
|
|
63
|
+
.status-card.idle{background:linear-gradient(180deg,#fff 0%,#fafafa 100%)}
|
|
64
|
+
|
|
65
|
+
.status-icon{
|
|
66
|
+
width:56px;height:56px;
|
|
67
|
+
border-radius:50%;
|
|
68
|
+
display:inline-flex;align-items:center;justify-content:center;
|
|
69
|
+
font-size:30px;font-weight:600;
|
|
70
|
+
margin-bottom:12px;
|
|
71
|
+
line-height:1;
|
|
72
|
+
}
|
|
73
|
+
.status-card.ok .status-icon{background:var(--ok-soft);color:var(--ok)}
|
|
74
|
+
.status-card.warn .status-icon{background:var(--warn-soft);color:var(--warn)}
|
|
75
|
+
.status-card.err .status-icon{background:var(--err-soft);color:var(--err)}
|
|
76
|
+
.status-card.idle .status-icon{background:#f0f0f2;color:var(--fg3)}
|
|
77
|
+
|
|
78
|
+
.status-title{
|
|
79
|
+
font-size:22px;font-weight:700;
|
|
80
|
+
letter-spacing:-.02em;
|
|
81
|
+
margin-bottom:6px;
|
|
82
|
+
color:var(--fg);
|
|
83
|
+
}
|
|
84
|
+
.status-desc{
|
|
85
|
+
font-size:14.5px;
|
|
86
|
+
color:var(--fg2);
|
|
87
|
+
line-height:1.55;
|
|
88
|
+
max-width:320px;
|
|
89
|
+
margin:0 auto;
|
|
90
|
+
}
|
|
91
|
+
.status-meta{
|
|
92
|
+
margin-top:14px;
|
|
93
|
+
padding-top:14px;
|
|
94
|
+
border-top:1px solid var(--line-soft);
|
|
95
|
+
font-size:12px;
|
|
96
|
+
color:var(--fg3);
|
|
97
|
+
font-variant-numeric:tabular-nums;
|
|
98
|
+
}
|
|
99
|
+
.status-meta span+span::before{content:"·";margin:0 8px;color:var(--fg4)}
|
|
100
|
+
|
|
101
|
+
/* ===== KPI 网格(第二屏 · 数字概览) ===== */
|
|
102
|
+
.kpis{
|
|
103
|
+
display:grid;
|
|
104
|
+
grid-template-columns:repeat(2,1fr);
|
|
105
|
+
gap:10px;
|
|
106
|
+
margin-bottom:14px;
|
|
107
|
+
}
|
|
108
|
+
.kpi{
|
|
109
|
+
background:var(--card);
|
|
110
|
+
border-radius:16px;
|
|
111
|
+
padding:16px 14px;
|
|
112
|
+
box-shadow:var(--shadow-sm);
|
|
113
|
+
position:relative;
|
|
114
|
+
overflow:hidden;
|
|
115
|
+
}
|
|
116
|
+
.kpi-bar{
|
|
117
|
+
position:absolute;top:0;left:0;right:0;height:4px;
|
|
118
|
+
background:var(--fg4);
|
|
119
|
+
}
|
|
120
|
+
.kpi-bar.ok{background:var(--ok)}
|
|
121
|
+
.kpi-bar.warn{background:var(--warn)}
|
|
122
|
+
.kpi-bar.blue{background:var(--blue)}
|
|
123
|
+
.kpi-num{
|
|
124
|
+
font-size:22px;font-weight:700;
|
|
125
|
+
letter-spacing:-.025em;
|
|
126
|
+
line-height:1;
|
|
127
|
+
margin:8px 0 6px;
|
|
128
|
+
color:var(--fg);
|
|
129
|
+
font-variant-numeric:tabular-nums;
|
|
130
|
+
}
|
|
131
|
+
.kpi-num.zero{color:var(--fg4);font-weight:600}
|
|
132
|
+
.kpi-label{font-size:13px;color:var(--fg2);font-weight:500}
|
|
133
|
+
.kpi-hint{font-size:11px;color:var(--fg3);margin-top:3px;line-height:1.4}
|
|
134
|
+
|
|
135
|
+
/* ===== 明细卡(<details> 原生折叠) ===== */
|
|
136
|
+
.detail{
|
|
137
|
+
background:var(--card);
|
|
138
|
+
border-radius:16px;
|
|
139
|
+
box-shadow:var(--shadow-sm);
|
|
140
|
+
margin-bottom:10px;
|
|
141
|
+
overflow:hidden;
|
|
142
|
+
}
|
|
143
|
+
.detail summary{
|
|
144
|
+
list-style:none;
|
|
145
|
+
cursor:pointer;
|
|
146
|
+
padding:15px 18px;
|
|
147
|
+
display:flex;
|
|
148
|
+
align-items:center;
|
|
149
|
+
gap:10px;
|
|
150
|
+
font-size:14.5px;
|
|
151
|
+
font-weight:600;
|
|
152
|
+
color:var(--fg);
|
|
153
|
+
user-select:none;
|
|
154
|
+
-webkit-tap-highlight-color:transparent;
|
|
155
|
+
}
|
|
156
|
+
.detail summary::-webkit-details-marker{display:none}
|
|
157
|
+
.detail summary::after{
|
|
158
|
+
content:"";
|
|
159
|
+
margin-left:auto;
|
|
160
|
+
width:8px;height:8px;
|
|
161
|
+
border-right:2px solid var(--fg3);
|
|
162
|
+
border-bottom:2px solid var(--fg3);
|
|
163
|
+
transform:rotate(-45deg);
|
|
164
|
+
transition:transform .2s;
|
|
165
|
+
flex-shrink:0;
|
|
166
|
+
}
|
|
167
|
+
.detail[open] summary::after{transform:rotate(45deg)}
|
|
168
|
+
.detail summary:active{background:var(--card2)}
|
|
169
|
+
.detail-badge{
|
|
170
|
+
display:inline-flex;align-items:center;justify-content:center;
|
|
171
|
+
min-width:22px;height:22px;padding:0 7px;
|
|
172
|
+
border-radius:999px;
|
|
173
|
+
font-size:12px;font-weight:700;
|
|
174
|
+
background:#ececef;color:var(--fg2);
|
|
175
|
+
font-variant-numeric:tabular-nums;
|
|
176
|
+
}
|
|
177
|
+
.detail-badge.ok{background:var(--ok-soft);color:var(--ok-fg)}
|
|
178
|
+
.detail-badge.warn{background:var(--warn-soft);color:var(--warn-fg)}
|
|
179
|
+
.detail-badge.err{background:var(--err-soft);color:var(--err-fg)}
|
|
180
|
+
.detail-body{
|
|
181
|
+
padding:0 18px 16px;
|
|
182
|
+
border-top:1px solid var(--line-soft);
|
|
183
|
+
margin-top:0;
|
|
184
|
+
}
|
|
185
|
+
.detail-body p{
|
|
186
|
+
font-size:13.5px;
|
|
187
|
+
color:var(--fg2);
|
|
188
|
+
line-height:1.65;
|
|
189
|
+
padding-top:14px;
|
|
190
|
+
}
|
|
191
|
+
.detail-body p+p{padding-top:10px}
|
|
192
|
+
.detail-body code{
|
|
193
|
+
background:var(--bg);
|
|
194
|
+
padding:2px 7px;
|
|
195
|
+
border-radius:5px;
|
|
196
|
+
font-size:12px;
|
|
197
|
+
font-family:var(--font-mono);
|
|
198
|
+
color:var(--fg2);
|
|
199
|
+
word-break:break-all;
|
|
200
|
+
}
|
|
201
|
+
.detail-body .note{
|
|
202
|
+
color:var(--fg3);
|
|
203
|
+
font-size:12px;
|
|
204
|
+
font-style:italic;
|
|
205
|
+
padding-top:8px;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* 明细列表(变化项) */
|
|
209
|
+
.item-list{list-style:none;padding-top:14px}
|
|
210
|
+
.item-list li{
|
|
211
|
+
padding:11px 0;
|
|
212
|
+
border-bottom:1px solid var(--line-soft);
|
|
213
|
+
font-size:14px;
|
|
214
|
+
display:flex;
|
|
215
|
+
align-items:center;
|
|
216
|
+
gap:10px;
|
|
217
|
+
}
|
|
218
|
+
.item-list li:last-child{border-bottom:0;padding-bottom:0}
|
|
219
|
+
.item-list .item-id{
|
|
220
|
+
font-family:var(--font-mono);
|
|
221
|
+
color:var(--fg3);
|
|
222
|
+
font-size:12px;
|
|
223
|
+
font-weight:600;
|
|
224
|
+
flex-shrink:0;
|
|
225
|
+
min-width:36px;
|
|
226
|
+
}
|
|
227
|
+
.item-list .item-content{
|
|
228
|
+
flex:1;
|
|
229
|
+
color:var(--fg);
|
|
230
|
+
min-width:0;
|
|
231
|
+
overflow:hidden;
|
|
232
|
+
text-overflow:ellipsis;
|
|
233
|
+
white-space:nowrap;
|
|
234
|
+
}
|
|
235
|
+
.item-list .item-mark{
|
|
236
|
+
color:var(--ok);
|
|
237
|
+
font-size:14px;
|
|
238
|
+
font-weight:700;
|
|
239
|
+
flex-shrink:0;
|
|
240
|
+
}
|
|
241
|
+
.item-list .item-mark.warn{color:var(--warn-fg)}
|
|
242
|
+
.item-list .item-mark.err{color:var(--err-fg)}
|
|
243
|
+
|
|
244
|
+
/* 错误列表 */
|
|
245
|
+
.err-list{list-style:none;padding-top:14px}
|
|
246
|
+
.err-list li{
|
|
247
|
+
padding:10px 12px;
|
|
248
|
+
background:var(--err-soft);
|
|
249
|
+
border-radius:10px;
|
|
250
|
+
margin-bottom:8px;
|
|
251
|
+
font-size:13px;
|
|
252
|
+
color:var(--err-fg);
|
|
253
|
+
line-height:1.55;
|
|
254
|
+
word-break:break-word;
|
|
255
|
+
}
|
|
256
|
+
.err-list li:last-child{margin-bottom:0}
|
|
257
|
+
|
|
258
|
+
/* ===== 数据与日志 ===== */
|
|
259
|
+
.data-panel{
|
|
260
|
+
background:var(--card);
|
|
261
|
+
border-radius:16px;
|
|
262
|
+
box-shadow:var(--shadow-sm);
|
|
263
|
+
padding:16px 18px;
|
|
264
|
+
margin-top:14px;
|
|
265
|
+
}
|
|
266
|
+
.data-panel strong{font-size:14.5px}
|
|
267
|
+
.data-panel .hint{font-size:12px;color:var(--fg3);margin-top:6px}
|
|
268
|
+
|
|
269
|
+
/* ===== 移动端微调(已经在 480 内,只处理超小屏) ===== */
|
|
270
|
+
@media(max-width:360px){
|
|
271
|
+
.wrap{padding:14px 12px 32px}
|
|
272
|
+
.status-card{padding:20px 16px}
|
|
273
|
+
.status-title{font-size:20px}
|
|
274
|
+
.kpi{padding:14px 12px}
|
|
275
|
+
.kpi-num{font-size:22px}
|
|
276
|
+
.detail summary{padding:13px 14px;font-size:14px}
|
|
277
|
+
.detail-body{padding:0 14px 14px}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/* ===== PC 端:480 居中,背景留白(类 Apple Mail) ===== */
|
|
281
|
+
@media(min-width:600px){
|
|
282
|
+
.wrap{padding-top:40px}
|
|
283
|
+
body{background:#ededf0}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* ===== reduce motion ===== */
|
|
287
|
+
@media(prefers-reduced-motion:reduce){
|
|
288
|
+
*{transition:none!important;animation:none!important}
|
|
289
|
+
}
|
|
290
|
+
</style>
|
|
291
|
+
</head>
|
|
292
|
+
<body>
|
|
293
|
+
<div class="wrap">
|
|
294
|
+
<section id="injectError" style="display:none"></section>
|
|
295
|
+
|
|
296
|
+
<!-- ===== 状态卡(首屏 · 结论) ===== -->
|
|
297
|
+
<section class="status-card" id="statusCard">
|
|
298
|
+
<div class="status-icon" id="statusIcon">✓</div>
|
|
299
|
+
<div class="status-title" id="statusTitle">备忘录同步报告</div>
|
|
300
|
+
<div class="status-desc" id="statusDesc">数据加载中</div>
|
|
301
|
+
<div class="status-meta" id="statusMeta"></div>
|
|
302
|
+
</section>
|
|
303
|
+
|
|
304
|
+
<!-- ===== 错误回执(#299 Base errorReceipt · 仅 err>0) ===== -->
|
|
305
|
+
<section id="errorReceipt" style="display:none"></section>
|
|
306
|
+
|
|
307
|
+
<!-- ===== KPI 网格(第二屏 · 数字概览) ===== -->
|
|
308
|
+
<section class="kpis" id="kpis"></section>
|
|
309
|
+
|
|
310
|
+
<!-- ===== 明细区(按需展开 · 原生 details) ===== -->
|
|
311
|
+
<div id="details"></div>
|
|
312
|
+
|
|
313
|
+
<!-- ===== 数据与日志(#299 08 硬标准) ===== -->
|
|
314
|
+
<section class="data-panel" id="dataPanel">
|
|
315
|
+
<strong>数据与日志</strong>
|
|
316
|
+
<div class="hint">点复制数据保存本次同步结果 · 点复制日志用于反馈问题</div>
|
|
317
|
+
<div class="hm-actions">
|
|
318
|
+
<button class="copy ghost" onclick="copyData()">复制数据</button>
|
|
319
|
+
<button class="copy ghost" onclick="copyLog()">复制日志</button>
|
|
320
|
+
</div>
|
|
321
|
+
</section>
|
|
322
|
+
</div>
|
|
323
|
+
|
|
324
|
+
<script id="payload" type="application/json"><!--INJECT-DATA--></script>
|
|
325
|
+
<script><!--SHARED-HELPERS--></script>
|
|
326
|
+
<script>
|
|
327
|
+
(function(){
|
|
328
|
+
"use strict";
|
|
329
|
+
var raw=document.getElementById("payload");
|
|
330
|
+
var payload=null,perr=null;
|
|
331
|
+
try{payload=JSON.parse(raw.textContent||"{}");}catch(e){perr=e.message;}
|
|
332
|
+
if(perr){document.getElementById("injectError").style.display="block";document.getElementById("injectError").innerHTML=window.errorReceipt({message:"数据解析失败",log:perr,payload:null});return;}
|
|
333
|
+
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;}
|
|
334
|
+
window.__hmPayload=payload;
|
|
335
|
+
|
|
336
|
+
function num(v){return (typeof v==='number'&&isFinite(v))?v:0}
|
|
337
|
+
function fmtTime(s){
|
|
338
|
+
if(!s||typeof s!=='string')return '';
|
|
339
|
+
var m = s.match(/(\d{2}):(\d{2})/);
|
|
340
|
+
return m ? m[1]+':'+m[2] : s;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function init(){
|
|
344
|
+
var card = document.getElementById('statusCard');
|
|
345
|
+
var icon = document.getElementById('statusIcon');
|
|
346
|
+
var title = document.getElementById('statusTitle');
|
|
347
|
+
var desc = document.getElementById('statusDesc');
|
|
348
|
+
var meta = document.getElementById('statusMeta');
|
|
349
|
+
|
|
350
|
+
var d = payload.data || {};
|
|
351
|
+
// success: 同步报告已渲染(4 状态 fallback · success 路径)
|
|
352
|
+
var synced = num(d.synced);
|
|
353
|
+
var backfilled = num(d.backfilled);
|
|
354
|
+
var dueAdded = num(d.due_added);
|
|
355
|
+
var dueOverridden = num(d.due_overridden);
|
|
356
|
+
var dueRemoved = num(d.due_removed);
|
|
357
|
+
var dueChanged = dueAdded + dueOverridden + dueRemoved;
|
|
358
|
+
var skippedNoLocal = num(d.skipped_no_local_note);
|
|
359
|
+
var skippedNoMemo = num(d.skipped_no_memo_id);
|
|
360
|
+
var skippedAlready = num(d.skipped_already_done);
|
|
361
|
+
var totalSkipped = skippedNoLocal + skippedNoMemo + skippedAlready;
|
|
362
|
+
var errs = (d.errors || []).length;
|
|
363
|
+
var totalChanged = synced + backfilled + dueChanged;
|
|
364
|
+
|
|
365
|
+
/* ----- 状态卡:四档(success / empty / missing_data / error) ----- */
|
|
366
|
+
if(errs > 0){
|
|
367
|
+
card.className = 'status-card err';
|
|
368
|
+
icon.textContent = '!';
|
|
369
|
+
title.textContent = '同步完成 · ' + errs + ' 个错误';
|
|
370
|
+
desc.innerHTML = '同步已执行,但有 <b>' + errs + '</b> 个错误需要关注。展开下方错误明细查看详情。';
|
|
371
|
+
// #299:err 态 → Base errorReceipt(修正重试 = 重新同步)
|
|
372
|
+
var er = document.getElementById('errorReceipt');
|
|
373
|
+
er.style.display = 'block';
|
|
374
|
+
er.innerHTML = window.errorReceipt({
|
|
375
|
+
message: '同步完成 · ' + errs + ' 个错误',
|
|
376
|
+
retryPrompt: '请重新运行备忘录同步(唤醒词:备忘录同步)',
|
|
377
|
+
payload: null
|
|
378
|
+
});
|
|
379
|
+
}else if(totalChanged === 0 && totalSkipped === 0){
|
|
380
|
+
card.className = 'status-card idle';
|
|
381
|
+
icon.textContent = '—';
|
|
382
|
+
title.textContent = '完全一致 · 无变化';
|
|
383
|
+
desc.textContent = '本机与飞书已同步,本次没有需要处理的变更。';
|
|
384
|
+
}else if(synced > 0 || backfilled > 0){
|
|
385
|
+
card.className = 'status-card ok';
|
|
386
|
+
icon.textContent = '✓';
|
|
387
|
+
title.textContent = '同步完成';
|
|
388
|
+
var parts = [];
|
|
389
|
+
if(synced > 0) parts.push('<b>' + synced + '</b> 条心愿在飞书勾选,本机已转打卡');
|
|
390
|
+
if(backfilled > 0) parts.push('<b>' + backfilled + '</b> 条本机心愿补建到飞书');
|
|
391
|
+
if(dueChanged > 0) parts.push('<b>' + dueChanged + '</b> 条排期已按飞书更新');
|
|
392
|
+
desc.innerHTML = parts.join('<br>') + '。';
|
|
393
|
+
}else{
|
|
394
|
+
card.className = 'status-card warn';
|
|
395
|
+
icon.textContent = '·';
|
|
396
|
+
title.textContent = '同步完成 · 无变更';
|
|
397
|
+
desc.innerHTML = '扫到飞书数据但本次没有实际变更。' + (totalSkipped > 0 ? '有 ' + totalSkipped + ' 条跳过,可展开查看。' : '');
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* ----- meta 行 ----- */
|
|
401
|
+
function commandToChinese(c){return c==='sync-from-feishu'?'同步飞书':c}
|
|
402
|
+
var metaParts = [];
|
|
403
|
+
if(d.generated_at) metaParts.push('<span>' + fmtTime(d.generated_at) + '</span>');
|
|
404
|
+
if(d.command) metaParts.push('<span>' + esc(commandToChinese(d.command)) + '</span>');
|
|
405
|
+
meta.innerHTML = metaParts.join('');
|
|
406
|
+
|
|
407
|
+
/* ----- KPI 网格 ----- */
|
|
408
|
+
var kpis = [
|
|
409
|
+
{n:synced, label:'完成同步', hint:'飞书上勾选的,本机已记为打卡', bar: synced>0?'ok':'', z:synced===0},
|
|
410
|
+
{n:backfilled, label:'补建到飞书', hint:'本机心愿 → 飞书任务', bar: backfilled>0?'ok':'', z:backfilled===0},
|
|
411
|
+
{n:dueChanged, label:'排期变更', hint:'已按飞书最新日期调整', bar: dueChanged>0?'warn':'', z:dueChanged===0},
|
|
412
|
+
{n:totalSkipped, label:'跳过', hint:'未匹配到本机心愿', bar: totalSkipped>0?'warn':'', z:totalSkipped===0},
|
|
413
|
+
];
|
|
414
|
+
document.getElementById('kpis').innerHTML = kpis.map(function(k){
|
|
415
|
+
return '<div class="kpi">' +
|
|
416
|
+
'<div class="kpi-bar ' + k.bar + '"></div>' +
|
|
417
|
+
'<div class="kpi-num ' + (k.z?'zero':'') + '">' + k.n + '</div>' +
|
|
418
|
+
'<div class="kpi-label">' + esc(k.label) + '</div>' +
|
|
419
|
+
'<div class="kpi-hint">' + esc(k.hint) + '</div>' +
|
|
420
|
+
'</div>';
|
|
421
|
+
}).join('');
|
|
422
|
+
|
|
423
|
+
/* ----- 明细区(原生 details,按需展示) ----- */
|
|
424
|
+
var details = [];
|
|
425
|
+
|
|
426
|
+
// 1. 完成同步明细
|
|
427
|
+
if(synced > 0){
|
|
428
|
+
var items = d.synced_items || [];
|
|
429
|
+
var body = '';
|
|
430
|
+
if(items.length > 0){
|
|
431
|
+
body = '<ul class="item-list">' + items.map(function(it){
|
|
432
|
+
return '<li>' +
|
|
433
|
+
'<span class="item-id">#' + esc(it.id) + '</span>' +
|
|
434
|
+
'<span class="item-content">' + esc(it.content) + '</span>' +
|
|
435
|
+
'<span class="item-mark">✓</span>' +
|
|
436
|
+
'</li>';
|
|
437
|
+
}).join('') + '</ul>';
|
|
438
|
+
}else{
|
|
439
|
+
body = '<p>本次有 <b>' + synced + '</b> 条心愿在飞书勾选完成,本机已转为打卡记录。</p>' +
|
|
440
|
+
'<p class="note">如需查看具体心愿,可用「查心愿」唤醒词查看本机心愿清单。</p>';
|
|
441
|
+
}
|
|
442
|
+
details.push(makeDetail('✓ 完成同步', 'ok', synced, body, true));
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// 2. 补建明细
|
|
446
|
+
if(backfilled > 0){
|
|
447
|
+
var body2 = '<p>本次有 <b>' + backfilled + '</b> 条本机心愿补建到飞书 task,已建立双向关联。</p>';
|
|
448
|
+
details.push(makeDetail('+ 补建到飞书', 'ok', backfilled, body2));
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// 3. 排期变更明细
|
|
452
|
+
if(dueChanged > 0){
|
|
453
|
+
var parts3 = [];
|
|
454
|
+
if(dueAdded > 0) parts3.push('新增 due ' + dueAdded + ' 条');
|
|
455
|
+
if(dueOverridden > 0) parts3.push('覆盖 due ' + dueOverridden + ' 条');
|
|
456
|
+
if(dueRemoved > 0) parts3.push('清除 due ' + dueRemoved + ' 条');
|
|
457
|
+
var body3 = '<p>本次排期变更:<b>' + parts3.join(' · ') + '</b>。</p>' +
|
|
458
|
+
'<p class="note">飞书 task 的 due 时间已同步到本机心愿。飞书优先,本机跟随。</p>';
|
|
459
|
+
details.push(makeDetail('📅 排期变更', 'warn', dueChanged, body3));
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// 4. 跳过明细(平静展示)
|
|
463
|
+
if(totalSkipped > 0){
|
|
464
|
+
var skipParts = [];
|
|
465
|
+
if(skippedNoLocal > 0) skipParts.push('<b>' + skippedNoLocal + '</b> 条在飞书已完成,但本机找不到对应心愿');
|
|
466
|
+
if(skippedNoMemo > 0) skipParts.push('<b>' + skippedNoMemo + '</b> 条飞书 task 缺少 memo_id 字段');
|
|
467
|
+
if(skippedAlready > 0) skipParts.push('<b>' + skippedAlready + '</b> 条之前已处理过');
|
|
468
|
+
var body4 = '<p>本次跳过 ' + totalSkipped + ' 条:</p>' +
|
|
469
|
+
'<p>' + skipParts.join(';<br>') + '。</p>';
|
|
470
|
+
if(skippedNoLocal > 0){
|
|
471
|
+
body4 += '<p class="note">可能你最近清理过本机库,或这些 task 是飞书原生建的。通常无需操作。如需排查可用「查心愿」唤醒词查看本机心愿清单。</p>';
|
|
472
|
+
}
|
|
473
|
+
details.push(makeDetail('○ 跳过', 'warn', totalSkipped, body4));
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// 5. 错误明细
|
|
477
|
+
if(errs > 0){
|
|
478
|
+
var body5 = '<ul class="err-list">' + (d.errors||[]).map(function(e){
|
|
479
|
+
return '<li>' + esc(e) + '</li>';
|
|
480
|
+
}).join('') + '</ul>';
|
|
481
|
+
details.push(makeDetail('⚠ 错误', 'err', errs, body5));
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// 6. 全空兜底(empty 状态 · #299 Base emptyState)
|
|
485
|
+
if(details.length === 0){
|
|
486
|
+
details.push('<div class="detail">' + window.emptyState({
|
|
487
|
+
icon: '—', text: '本次同步无任何变更或跳过', hint: '本机与飞书完全一致'
|
|
488
|
+
}) + '</div>');
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
document.getElementById('details').innerHTML = details.join('');
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function makeDetail(label, badgeClass, count, body, open){
|
|
495
|
+
return '<details class="detail"' + (open ? ' open' : '') + '>' +
|
|
496
|
+
'<summary>' +
|
|
497
|
+
'<span>' + esc(label) + '</span>' +
|
|
498
|
+
'<span class="detail-badge ' + badgeClass + '">' + count + '</span>' +
|
|
499
|
+
'</summary>' +
|
|
500
|
+
'<div class="detail-body">' + body + '</div>' +
|
|
501
|
+
'</details>';
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function copyData(){window.copyText(window.buildDataText(payload),{silent:true});window.toast('数据已复制','人类可读快照 · 可粘贴到笔记存档',{icon:'copy'});}
|
|
505
|
+
function copyLog(){window.copyText(window.buildLogText(payload),{silent:true});window.toast('日志已复制','诊断信息 · 有异常时粘贴给开发者排查',{icon:'copy'});}
|
|
506
|
+
window.copyData=copyData;
|
|
507
|
+
window.copyLog=copyLog;
|
|
508
|
+
init();
|
|
509
|
+
})();
|
|
510
|
+
</script>
|
|
511
|
+
</body>
|
|
512
|
+
</html>
|