skill-schedule 0.3.3 → 0.3.13
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/SKILL.md +12 -3
- package/dist/.gen-inputs.json +4 -4
- package/dist/admin/adminDocs.d.ts +57 -0
- package/dist/admin/adminDocs.d.ts.map +1 -0
- package/dist/admin/adminDocs.js +190 -0
- package/dist/admin/adminDocs.js.map +1 -0
- package/dist/admin/adminParts.d.ts +37 -0
- package/dist/admin/adminParts.d.ts.map +1 -0
- package/dist/admin/adminParts.js +83 -0
- package/dist/admin/adminParts.js.map +1 -0
- package/dist/admin/handlers.d.ts.map +1 -1
- package/dist/admin/handlers.js +196 -6
- package/dist/admin/handlers.js.map +1 -1
- package/dist/admin/routes.d.ts +10 -1
- package/dist/admin/routes.d.ts.map +1 -1
- package/dist/admin/routes.js +2 -0
- package/dist/admin/routes.js.map +1 -1
- package/dist/analyze/analyzeDocs.d.ts +51 -0
- package/dist/analyze/analyzeDocs.d.ts.map +1 -0
- package/dist/analyze/analyzeDocs.js +442 -0
- package/dist/analyze/analyzeDocs.js.map +1 -0
- package/dist/analyze/analyzeParts.d.ts +53 -0
- package/dist/analyze/analyzeParts.d.ts.map +1 -0
- package/dist/analyze/analyzeParts.js +229 -0
- package/dist/analyze/analyzeParts.js.map +1 -0
- package/dist/analyze/handlers.d.ts.map +1 -1
- package/dist/analyze/handlers.js +41 -4
- package/dist/analyze/handlers.js.map +1 -1
- package/dist/cli/cmd_read.js +8 -2
- package/dist/cli/cmd_read.js.map +1 -1
- package/dist/cli/config.d.ts +0 -9
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +20 -1
- package/dist/cli/config.js.map +1 -1
- package/dist/fetch/feishu.d.ts +6 -0
- package/dist/fetch/feishu.d.ts.map +1 -1
- package/dist/fetch/feishu.js +18 -7
- package/dist/fetch/feishu.js.map +1 -1
- package/dist/fetch/index.d.ts +1 -1
- package/dist/fetch/index.d.ts.map +1 -1
- package/dist/fetch/index.js +1 -1
- package/dist/fetch/index.js.map +1 -1
- package/dist/health.d.ts +11 -0
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js +48 -22
- package/dist/health.js.map +1 -1
- package/dist/help/index.d.ts +1 -0
- package/dist/help/index.d.ts.map +1 -1
- package/dist/help/index.js +3 -0
- package/dist/help/index.js.map +1 -1
- package/dist/plan/discussDocs.d.ts +8 -0
- package/dist/plan/discussDocs.d.ts.map +1 -0
- package/dist/plan/discussDocs.js +321 -0
- package/dist/plan/discussDocs.js.map +1 -0
- package/dist/plan/feishuDocs.d.ts +19 -0
- package/dist/plan/feishuDocs.d.ts.map +1 -0
- package/dist/plan/feishuDocs.js +257 -0
- package/dist/plan/feishuDocs.js.map +1 -0
- package/dist/plan/handlers.d.ts.map +1 -1
- package/dist/plan/handlers.js +107 -3
- package/dist/plan/handlers.js.map +1 -1
- package/dist/plan/index.d.ts +2 -0
- package/dist/plan/index.d.ts.map +1 -1
- package/dist/plan/index.js +16 -9
- package/dist/plan/index.js.map +1 -1
- package/dist/plan/iso.d.ts +2 -0
- package/dist/plan/iso.d.ts.map +1 -1
- package/dist/plan/iso.js +6 -2
- package/dist/plan/iso.js.map +1 -1
- package/dist/plan/planDocs.d.ts +47 -0
- package/dist/plan/planDocs.d.ts.map +1 -0
- package/dist/plan/planDocs.js +159 -0
- package/dist/plan/planDocs.js.map +1 -0
- package/dist/plan/planParts.d.ts +38 -0
- package/dist/plan/planParts.d.ts.map +1 -0
- package/dist/plan/planParts.js +96 -0
- package/dist/plan/planParts.js.map +1 -0
- package/dist/plan/probe.d.ts +28 -0
- package/dist/plan/probe.d.ts.map +1 -0
- package/dist/plan/probe.js +114 -0
- package/dist/plan/probe.js.map +1 -0
- package/dist/plan/receipt.d.ts +12 -0
- package/dist/plan/receipt.d.ts.map +1 -1
- package/dist/plan/receipt.js +17 -0
- package/dist/plan/receipt.js.map +1 -1
- package/dist/plan/receiptDocs.d.ts +26 -0
- package/dist/plan/receiptDocs.d.ts.map +1 -0
- package/dist/plan/receiptDocs.js +341 -0
- package/dist/plan/receiptDocs.js.map +1 -0
- package/dist/plan/replayDocs.d.ts +165 -0
- package/dist/plan/replayDocs.d.ts.map +1 -0
- package/dist/plan/replayDocs.js +226 -0
- package/dist/plan/replayDocs.js.map +1 -0
- package/dist/plan/replaySections.d.ts +5 -0
- package/dist/plan/replaySections.d.ts.map +1 -0
- package/dist/plan/replaySections.js +471 -0
- package/dist/plan/replaySections.js.map +1 -0
- package/dist/plan/reviewDocs.d.ts +4 -0
- package/dist/plan/reviewDocs.d.ts.map +1 -0
- package/dist/plan/reviewDocs.js +130 -0
- package/dist/plan/reviewDocs.js.map +1 -0
- package/dist/plan/sync.d.ts.map +1 -1
- package/dist/plan/sync.js +5 -0
- package/dist/plan/sync.js.map +1 -1
- package/dist/policy/index.d.ts +1 -1
- package/dist/policy/index.d.ts.map +1 -1
- package/dist/policy/index.js +1 -1
- package/dist/policy/index.js.map +1 -1
- package/dist/policy/plan.d.ts +8 -0
- package/dist/policy/plan.d.ts.map +1 -1
- package/dist/policy/plan.js +20 -0
- package/dist/policy/plan.js.map +1 -1
- package/dist/query/handlers.d.ts +3 -0
- package/dist/query/handlers.d.ts.map +1 -1
- package/dist/query/handlers.js +86 -12
- package/dist/query/handlers.js.map +1 -1
- package/dist/query/queryDocs.d.ts +64 -0
- package/dist/query/queryDocs.d.ts.map +1 -0
- package/dist/query/queryDocs.js +554 -0
- package/dist/query/queryDocs.js.map +1 -0
- package/dist/query/routes.d.ts +11 -1
- package/dist/query/routes.d.ts.map +1 -1
- package/dist/query/routes.js +5 -1
- package/dist/query/routes.js.map +1 -1
- package/dist/render/copyArea.d.ts +61 -0
- package/dist/render/copyArea.d.ts.map +1 -0
- package/dist/render/copyArea.js +80 -0
- package/dist/render/copyArea.js.map +1 -0
- package/dist/render/html.d.ts.map +1 -1
- package/dist/render/html.js +3 -1
- package/dist/render/html.js.map +1 -1
- package/dist/render/index.d.ts +3 -0
- package/dist/render/index.d.ts.map +1 -1
- package/dist/render/index.js +2 -0
- package/dist/render/index.js.map +1 -1
- package/dist/shared/dayPage.d.ts +67 -0
- package/dist/shared/dayPage.d.ts.map +1 -0
- package/dist/shared/dayPage.js +92 -0
- package/dist/shared/dayPage.js.map +1 -0
- package/dist/shared/detailPage.d.ts +55 -0
- package/dist/shared/detailPage.d.ts.map +1 -0
- package/dist/shared/detailPage.js +65 -0
- package/dist/shared/detailPage.js.map +1 -0
- package/dist/shared/docPage.d.ts +22 -0
- package/dist/shared/docPage.d.ts.map +1 -0
- package/dist/shared/docPage.js +52 -0
- package/dist/shared/docPage.js.map +1 -0
- package/dist/shared/overviewPage.d.ts +52 -0
- package/dist/shared/overviewPage.d.ts.map +1 -0
- package/dist/shared/overviewPage.js +65 -0
- package/dist/shared/overviewPage.js.map +1 -0
- package/dist/shared/pageNav.d.ts +24 -0
- package/dist/shared/pageNav.d.ts.map +1 -0
- package/dist/shared/pageNav.js +70 -0
- package/dist/shared/pageNav.js.map +1 -0
- package/dist/shared/pageParts.d.ts +45 -0
- package/dist/shared/pageParts.d.ts.map +1 -0
- package/dist/shared/pageParts.js +154 -0
- package/dist/shared/pageParts.js.map +1 -0
- package/dist/shared/planPage.d.ts +49 -0
- package/dist/shared/planPage.d.ts.map +1 -0
- package/dist/shared/planPage.js +48 -0
- package/dist/shared/planPage.js.map +1 -0
- package/dist/shared/rangePage.d.ts +44 -0
- package/dist/shared/rangePage.d.ts.map +1 -0
- package/dist/shared/rangePage.js +50 -0
- package/dist/shared/rangePage.js.map +1 -0
- package/dist/shared/weekPage.d.ts +36 -0
- package/dist/shared/weekPage.d.ts.map +1 -0
- package/dist/shared/weekPage.js +42 -0
- package/dist/shared/weekPage.js.map +1 -0
- package/dist/triggers/routes.generated.d.ts +23 -1
- package/dist/triggers/routes.generated.d.ts.map +1 -1
- package/dist/triggers/routes.generated.js +4 -1
- package/dist/triggers/routes.generated.js.map +1 -1
- package/dist/write/handlers.d.ts.map +1 -1
- package/dist/write/handlers.js +101 -5
- package/dist/write/handlers.js.map +1 -1
- package/dist/write/writeDocs.d.ts +27 -0
- package/dist/write/writeDocs.d.ts.map +1 -0
- package/dist/write/writeDocs.js +423 -0
- package/dist/write/writeDocs.js.map +1 -0
- package/dist/write/writeParts.d.ts +54 -0
- package/dist/write/writeParts.d.ts.map +1 -0
- package/dist/write/writeParts.js +117 -0
- package/dist/write/writeParts.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/** #787 · 「商量计划」的**两张页**(口径与页装配):过程型预览(f12)与制定次日计划结果(f17)。
|
|
2
|
+
*
|
|
3
|
+
* 为什么两张页分开(照地图裁决):预览**不写库**,结果页写完之后才有——「先出候选、确认后才写库」,
|
|
4
|
+
* 两张各自能独立跑(`op=preview` 与 `op=upsert`)。
|
|
5
|
+
*
|
|
6
|
+
* 口径住这里(共用位不许出现任何一个能力的名字):
|
|
7
|
+
* · **空隙**=候选之间没排上的连续时段——与「查日程」的空档同一条规则,函数只此一处(`planDocs`);
|
|
8
|
+
* · **重叠**=候选段与这一天原有事件在时间上搭着边(不要求整段包住);
|
|
9
|
+
* · **历史贴**=拿这一天往前 7 天的**作息记录**按整点归类,取该事件覆盖时段里出现最多的那个分类做主档
|
|
10
|
+
* (老侧 `plan_scenarios.py` 的 `build_history_habits` 与 `fit_events`,默认窗口 7 天);
|
|
11
|
+
* 候选那条的一级分类……**不折算**,就按库里那一串分类名比(老侧同口径)。
|
|
12
|
+
*
|
|
13
|
+
* **页上文案纪律**:不出现命令键、库列名、参数名、票号;并列关系用表格列与对照行表达,不拿
|
|
14
|
+
* `·`/`|`/`~`/`、`/`;` 顶替设计。范围一律写「至」。
|
|
15
|
+
*/
|
|
16
|
+
import { renderCaliberLine, renderConclusionBar, renderDataTable, renderDisclosure, renderFeedbackBlock, renderKpiGrid, renderListRows, renderPreBlock, } from 'base-paint/blocks';
|
|
17
|
+
import { renderFactStrip } from 'base-paint';
|
|
18
|
+
import { listPlanEvents, listRecordsRange } from '../fetch/index.js';
|
|
19
|
+
import { LEVEL1_WHITELIST, fmtDur, fmtDurShort, l1Of, } from '../policy/index.js';
|
|
20
|
+
import { scheduleCopyArea } from '../render/copyArea.js';
|
|
21
|
+
import { assembleDocPage } from '../shared/docPage.js';
|
|
22
|
+
import { pageSections } from '../shared/pageNav.js';
|
|
23
|
+
import { hourCellsOf, renderHourBand } from '../shared/pageParts.js';
|
|
24
|
+
import { clockOf, gapsOf, minutesOfDayEnd } from './planDocs.js';
|
|
25
|
+
import { shiftDay } from './iso.js';
|
|
26
|
+
import { REMOTE_LABEL, planCopyArea } from './receipt.js';
|
|
27
|
+
import { planPartsCss } from './planParts.js';
|
|
28
|
+
const EYEBROW = '作息管家 日程与计划';
|
|
29
|
+
/** 一级分类的权威顺序(色带配色与图例都照它),定义只此一处:`policy` 的白名单。 */
|
|
30
|
+
const L1_ORDER = [...LEVEL1_WHITELIST];
|
|
31
|
+
/** 历史窗口(天):老侧 `plan_scenarios.DEFAULT_HISTORY_DAYS`。 */
|
|
32
|
+
const HISTORY_DAYS = 7;
|
|
33
|
+
const HOURS_PER_DAY = 24;
|
|
34
|
+
const span = (start, end) => start + ' 至 ' + end;
|
|
35
|
+
const categoryOf = (c) => (c === null || c === undefined || c === '' ? '未分类' : c);
|
|
36
|
+
/** 钟点 → 分钟(**这一天末尾那一格按 24:00 算**,与空档同一条口径):定义在 `planDocs`,本件只引用。 */
|
|
37
|
+
const minutesOf = minutesOfDayEnd;
|
|
38
|
+
function cellsOf(events) {
|
|
39
|
+
return hourCellsOf(events.map((e) => ({
|
|
40
|
+
start: minutesOf(e.time_start),
|
|
41
|
+
end: minutesOf(e.time_end),
|
|
42
|
+
key: l1Of(e.category ?? ''),
|
|
43
|
+
})));
|
|
44
|
+
}
|
|
45
|
+
/** 这一段覆盖到哪几个整点(末段 24:00 收在 23 点)。 */
|
|
46
|
+
function hoursOf(start, end) {
|
|
47
|
+
const from = Math.floor(minutesOf(start) / 60);
|
|
48
|
+
const to = Math.ceil(minutesOf(end) / 60);
|
|
49
|
+
const out = [];
|
|
50
|
+
for (let h = from; h < to && h < HOURS_PER_DAY; h += 1)
|
|
51
|
+
out.push(h);
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
/** 历史作息按整点归类:小时 → 分类 → 出现次数(老侧 `build_history_habits` 同口径)。 */
|
|
55
|
+
function habitsOf(records) {
|
|
56
|
+
const out = new Map();
|
|
57
|
+
for (const r of records) {
|
|
58
|
+
const name = categoryOf(r.category);
|
|
59
|
+
for (const h of hoursOf(r.time_start, r.time_end)) {
|
|
60
|
+
const bucket = out.get(h) ?? new Map();
|
|
61
|
+
bucket.set(name, (bucket.get(name) ?? 0) + 1);
|
|
62
|
+
out.set(h, bucket);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
/** 某几个整点里出现最多的那个分类(次数并列时取字典序在前的那个,读数才可复现)。 */
|
|
68
|
+
function dominantOf(habits, hours) {
|
|
69
|
+
const total = new Map();
|
|
70
|
+
for (const h of hours) {
|
|
71
|
+
for (const [name, n] of habits.get(h) ?? [])
|
|
72
|
+
total.set(name, (total.get(name) ?? 0) + n);
|
|
73
|
+
}
|
|
74
|
+
let best = null;
|
|
75
|
+
for (const [category, count] of [...total.entries()].sort((a, b) => (a[0] < b[0] ? -1 : 1))) {
|
|
76
|
+
if (best === null || count > best.count)
|
|
77
|
+
best = { category, count };
|
|
78
|
+
}
|
|
79
|
+
return best;
|
|
80
|
+
}
|
|
81
|
+
/** 一条候选与历史的贴合:贴合/偏离/无参考 + 一句人话提示(老侧 `fit_events` 的三档)。 */
|
|
82
|
+
function fitOf(category, habits, start, end) {
|
|
83
|
+
const top = dominantOf(habits, hoursOf(start, end));
|
|
84
|
+
if (top === null)
|
|
85
|
+
return { fit: 'none', hint: '该时段近几天没有作息记录,这一条没有历史可参照。' };
|
|
86
|
+
const mine = categoryOf(category);
|
|
87
|
+
if (category === null || category === undefined || category === '') {
|
|
88
|
+
return { fit: 'none', hint: '这一条没有标分类,历史该时段主要是「' + top.category + '」。' };
|
|
89
|
+
}
|
|
90
|
+
if (mine === top.category) {
|
|
91
|
+
return { fit: 'match', hint: '贴合历史:该时段近几天主要是「' + top.category + '」。' };
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
fit: 'drift',
|
|
95
|
+
hint: '与历史不同:该时段近几天主要是「' + top.category + '」(' + String(top.count) + ' 次),这一条排的是「' + mine + '」。',
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function overlapsOf(candidates, locked) {
|
|
99
|
+
const out = [];
|
|
100
|
+
for (const c of candidates) {
|
|
101
|
+
for (const l of locked) {
|
|
102
|
+
const lo = Math.max(minutesOf(c.time_start), minutesOf(l.time_start));
|
|
103
|
+
const hi = Math.min(minutesOf(c.time_end), minutesOf(l.time_end));
|
|
104
|
+
if (hi > lo) {
|
|
105
|
+
out.push({
|
|
106
|
+
candidate: c.title + '(' + span(c.time_start, c.time_end) + ')',
|
|
107
|
+
locked: l.title + '(' + span(l.time_start, l.time_end) + ')',
|
|
108
|
+
overlap: span(clockOf(lo), clockOf(hi)),
|
|
109
|
+
minutes: hi - lo,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
/* ─────────────────────── ① 商量计划预览(老侧 f12,过程型) ─────────────────────── */
|
|
117
|
+
/** 「商量计划预览」整页:候选事件表 + 锁定事件区 + 空隙提示。**这一页不写库**。 */
|
|
118
|
+
export function previewPage(handle, date, candidates) {
|
|
119
|
+
const locked = listPlanEvents(handle, date);
|
|
120
|
+
const gaps = gapsOf(candidates);
|
|
121
|
+
const overlaps = overlapsOf(candidates, locked);
|
|
122
|
+
const covered = candidates.reduce((sum, e) => sum + (minutesOf(e.time_end) - minutesOf(e.time_start)), 0);
|
|
123
|
+
const rows = candidates.map((e) => ({
|
|
124
|
+
time: span(e.time_start, e.time_end),
|
|
125
|
+
title: e.title,
|
|
126
|
+
category: categoryOf(e.category),
|
|
127
|
+
notes: e.notes === undefined || e.notes === null || e.notes === '' ? '—' : e.notes,
|
|
128
|
+
}));
|
|
129
|
+
const lockedRows = locked.map((e) => ({
|
|
130
|
+
left: span(e.time_start, e.time_end),
|
|
131
|
+
main: e.title,
|
|
132
|
+
right: categoryOf(e.category),
|
|
133
|
+
}));
|
|
134
|
+
const head = {
|
|
135
|
+
docTitle: '作息管家 商量计划预览',
|
|
136
|
+
eyebrow: EYEBROW,
|
|
137
|
+
title: '商量计划预览',
|
|
138
|
+
subtitle: '候选 ' + String(candidates.length) + ' 段排的是 ' + date + ',这一步只预览,没有写库。',
|
|
139
|
+
};
|
|
140
|
+
const { toc, body } = pageSections([
|
|
141
|
+
{ html: renderConclusionBar('候选 ' + String(candidates.length) + ' 段把 ' + date + ' 的 24 小时接满,'
|
|
142
|
+
+ '共 ' + fmtDur(covered) + '。这一天现在已有 ' + String(locked.length) + ' 件,其中 '
|
|
143
|
+
+ String(overlaps.length) + ' 处与候选时段重叠。') },
|
|
144
|
+
{ navText: '这一版候选的读数', html: renderKpiGrid([
|
|
145
|
+
{ label: '候选段数', value: String(candidates.length) + ' 段', detail: '这一版商量出来的' },
|
|
146
|
+
{
|
|
147
|
+
label: '24 小时覆盖', value: fmtDur(covered),
|
|
148
|
+
detail: covered >= HOURS_PER_DAY * 60 ? '整天接满,可以落盘' : '还没接满,先补上缺口',
|
|
149
|
+
bar: { pct: Math.min(100, Math.round((covered / (HOURS_PER_DAY * 60)) * 100)) },
|
|
150
|
+
},
|
|
151
|
+
{ label: '与已有重叠', value: String(overlaps.length) + ' 处', detail: overlaps.length === 0 ? '与原有排布不搭边' : '落盘前先看一眼' },
|
|
152
|
+
{ label: '这一天已有', value: String(locked.length) + ' 件', detail: '现在库里的排布' },
|
|
153
|
+
], { title: '这一版候选的读数' }) },
|
|
154
|
+
// 段名是「候选的 24 小时」;目录项逐字用它。
|
|
155
|
+
{ navText: '候选的 24 小时', html: renderHourBand(cellsOf(candidates), { order: L1_ORDER, title: '候选的 24 小时', height: 120 }) },
|
|
156
|
+
{ html: renderDataTable({
|
|
157
|
+
caption: '候选事件',
|
|
158
|
+
columns: [
|
|
159
|
+
{ key: 'time', label: '时段' },
|
|
160
|
+
{ key: 'title', label: '标题' },
|
|
161
|
+
{ key: 'category', label: '分类' },
|
|
162
|
+
{ key: 'notes', label: '备注' },
|
|
163
|
+
],
|
|
164
|
+
rows,
|
|
165
|
+
emptyText: '这一版一段也没给',
|
|
166
|
+
}) },
|
|
167
|
+
{ html: renderCaliberLine('候选是把这一天整段重排 | 落盘时先按日期整日覆盖,候选之外的那些会被标记成不再算') },
|
|
168
|
+
{ html: renderDisclosure({
|
|
169
|
+
title: '锁定事件区',
|
|
170
|
+
contentHtml: (locked.length === 0
|
|
171
|
+
? '<p class="sch-pl-note">这一天现在库里没有别的安排,落盘不会顶掉任何一件。</p>'
|
|
172
|
+
: '<p class="sch-pl-note">这些是这一天现在库里的排布,落盘时会被候选整段换掉。</p>')
|
|
173
|
+
+ renderListRows({ items: lockedRows, emptyText: '这一天现在库里没有别的安排' }),
|
|
174
|
+
}) },
|
|
175
|
+
{ html: renderDisclosure({
|
|
176
|
+
title: '空隙提示',
|
|
177
|
+
contentHtml: renderListRows({
|
|
178
|
+
items: gaps.map((g) => ({ left: span(clockOf(g.start), clockOf(g.end)), main: '空隙', right: fmtDurShort(g.end - g.start) })),
|
|
179
|
+
emptyText: '候选把 24 小时一段接一段接满了,没有空隙。',
|
|
180
|
+
}),
|
|
181
|
+
}) },
|
|
182
|
+
{ html: renderPreBlock({
|
|
183
|
+
label: '认可这一版就说这一句',
|
|
184
|
+
command: '按这一版把 ' + date + ' 的计划落下来',
|
|
185
|
+
actionId: 'ilife-sch-plan-copy-next',
|
|
186
|
+
copyLabel: '复制这句话',
|
|
187
|
+
}) },
|
|
188
|
+
{ navText: '复制与留档', html: scheduleCopyArea({
|
|
189
|
+
title: '复制与留档',
|
|
190
|
+
dataActionId: 'ilife-sch-plan-copy-data',
|
|
191
|
+
logActionId: 'ilife-sch-plan-copy-log',
|
|
192
|
+
...planCopyArea({
|
|
193
|
+
message: '商量计划预览:日期 ' + date + ',候选 ' + String(candidates.length) + ' 段共 ' + fmtDur(covered)
|
|
194
|
+
+ ',与已有重叠 ' + String(overlaps.length) + ' 处',
|
|
195
|
+
command: 'schedule-cmd-read schedule.plan.write --params {"op":"preview","date":"' + date + '"}',
|
|
196
|
+
source: '日程计划表与作息记录表(近 ' + String(HISTORY_DAYS) + ' 天)',
|
|
197
|
+
}),
|
|
198
|
+
}) },
|
|
199
|
+
]);
|
|
200
|
+
return assembleDocPage({ head, content: toc + body, extraCss: planPartsCss() });
|
|
201
|
+
}
|
|
202
|
+
/* ─────────────────────── ② 制定次日计划结果(老侧 f17) ─────────────────────── */
|
|
203
|
+
/** 「制定次日计划结果」整页:时间轴与分类色带 + 历史贴合提示 + 冲突与警告 + 复制 prompt 位。 */
|
|
204
|
+
export function resultPage(handle, date, candidates, locked, remote) {
|
|
205
|
+
const written = listPlanEvents(handle, date);
|
|
206
|
+
const records = listRecordsRange(handle, shiftDay(date, -HISTORY_DAYS), shiftDay(date, -1));
|
|
207
|
+
const habits = habitsOf(records);
|
|
208
|
+
const fits = candidates.map((e) => ({ event: e, ...fitOf(e.category, habits, e.time_start, e.time_end) }));
|
|
209
|
+
const match = fits.filter((f) => f.fit === 'match').length;
|
|
210
|
+
const drift = fits.filter((f) => f.fit === 'drift').length;
|
|
211
|
+
const none = fits.filter((f) => f.fit === 'none').length;
|
|
212
|
+
const referred = match + drift;
|
|
213
|
+
const rate = referred === 0 ? null : Math.round((match / referred) * 1000) / 10;
|
|
214
|
+
const overlaps = overlapsOf(candidates, locked);
|
|
215
|
+
const covered = candidates.reduce((sum, e) => sum + (minutesOf(e.time_end) - minutesOf(e.time_start)), 0);
|
|
216
|
+
/** 逐段贴合(四列:时段/标题/贴合/说明):**不再单列分类那一栏**——说明句里已经点名
|
|
217
|
+
* 两边各是什么,五列挤在 880 里会把「贴合」两个字折成两行(复看时抓到的版式债)。 */
|
|
218
|
+
const fitRows = fits.map((f) => ({
|
|
219
|
+
time: span(f.event.time_start, f.event.time_end),
|
|
220
|
+
title: f.event.title,
|
|
221
|
+
fit: f.fit === 'match' ? '贴合' : (f.fit === 'drift' ? '偏离' : '无参考'),
|
|
222
|
+
hint: f.hint,
|
|
223
|
+
}));
|
|
224
|
+
const head = {
|
|
225
|
+
docTitle: '作息管家 制定次日计划结果',
|
|
226
|
+
eyebrow: EYEBROW,
|
|
227
|
+
title: '制定次日计划结果',
|
|
228
|
+
subtitle: '落下来的是 ' + date + ',候选 ' + String(candidates.length) + ' 段,'
|
|
229
|
+
+ '贴历史 ' + String(match) + ' 段,偏离 ' + String(drift) + ' 段。',
|
|
230
|
+
};
|
|
231
|
+
const { toc, body } = pageSections([
|
|
232
|
+
{ html: renderConclusionBar('这一版已经落盘:' + date + ' 现在排着 ' + String(written.length) + ' 件,'
|
|
233
|
+
+ '共 ' + fmtDur(covered) + '。' + (rate === null
|
|
234
|
+
? '近 ' + String(HISTORY_DAYS) + ' 天没有作息记录,贴合与否无从比较。'
|
|
235
|
+
: '与近 ' + String(HISTORY_DAYS) + ' 天的作息习惯贴合率 ' + String(rate) + '%。')) },
|
|
236
|
+
{ navText: '这一版的读数', html: renderKpiGrid([
|
|
237
|
+
{ label: '候选段数', value: String(candidates.length) + ' 段', detail: date },
|
|
238
|
+
{
|
|
239
|
+
label: '历史贴合率', value: rate === null ? '—' : String(rate) + '%',
|
|
240
|
+
detail: rate === null ? '没有可比的记录' : '贴合 ' + String(match) + ' 段,偏离 ' + String(drift) + ' 段',
|
|
241
|
+
...(rate === null ? {} : { bar: { pct: Math.round(rate) } }),
|
|
242
|
+
},
|
|
243
|
+
{ label: '偏离与无参考', value: String(drift) + ' 段偏离', detail: '另有 ' + String(none) + ' 段无历史可参照' },
|
|
244
|
+
{ label: '冲突', value: String(overlaps.length) + ' 处', detail: overlaps.length === 0 ? '与原有排布不搭边' : '采纳前先看一眼' },
|
|
245
|
+
], { title: '这一版的读数' }) },
|
|
246
|
+
// 段名是「24 小时时间轴与分类色带」;目录项逐字用它。
|
|
247
|
+
{ navText: '24 小时时间轴与分类色带', html: renderHourBand(cellsOf(written), { order: L1_ORDER, title: '24 小时时间轴与分类色带', height: 140 }) },
|
|
248
|
+
{ html: renderFactStrip({
|
|
249
|
+
items: [
|
|
250
|
+
{ label: '历史窗口', value: String(HISTORY_DAYS) + ' 天' },
|
|
251
|
+
{ label: '这段窗口的作息记录', value: String(records.length) + ' 条' },
|
|
252
|
+
{ label: '远端侧', value: REMOTE_LABEL[remote] },
|
|
253
|
+
{ label: '这一天现在', value: String(written.length) + ' 件' },
|
|
254
|
+
],
|
|
255
|
+
}) },
|
|
256
|
+
{ navText: '历史贴合提示', html: renderFeedbackBlock({
|
|
257
|
+
title: '历史贴合提示',
|
|
258
|
+
toast: {
|
|
259
|
+
icon: rate === null ? 'info' : (drift === 0 ? 'ok' : 'warn'),
|
|
260
|
+
msg: rate === null
|
|
261
|
+
? '近 ' + String(HISTORY_DAYS) + ' 天没有作息记录,这一版没有历史可参照,逐段都按无参考算。'
|
|
262
|
+
: '拿近 ' + String(HISTORY_DAYS) + ' 天的作息记录按整点归类:贴合 ' + String(match) + ' 段,偏离 '
|
|
263
|
+
+ String(drift) + ' 段,无参考 ' + String(none) + ' 段。'
|
|
264
|
+
+ (drift === 0 ? '' : '逐段原因见下表「逐段贴合」。'),
|
|
265
|
+
},
|
|
266
|
+
staticNotice: true,
|
|
267
|
+
}) },
|
|
268
|
+
{ html: renderDataTable({
|
|
269
|
+
caption: '逐段贴合',
|
|
270
|
+
columns: [
|
|
271
|
+
{ key: 'time', label: '时段' },
|
|
272
|
+
{ key: 'title', label: '标题' },
|
|
273
|
+
{ key: 'fit', label: '贴合' },
|
|
274
|
+
{ key: 'hint', label: '说明' },
|
|
275
|
+
],
|
|
276
|
+
rows: fitRows,
|
|
277
|
+
emptyText: '这一版一段也没给',
|
|
278
|
+
}) },
|
|
279
|
+
{ navText: drift === 0 ? '' : '偏离警示', html: drift === 0 ? '' : renderFeedbackBlock({
|
|
280
|
+
title: '偏离警示',
|
|
281
|
+
toast: {
|
|
282
|
+
icon: 'warn',
|
|
283
|
+
msg: '有 ' + String(drift) + ' 段与近 ' + String(HISTORY_DAYS) + ' 天的作息习惯不同,可能是刻意安排,也可能是排错了。',
|
|
284
|
+
lines: fits.filter((f) => f.fit === 'drift').map((f) => span(f.event.time_start, f.event.time_end) + ' ' + f.event.title),
|
|
285
|
+
},
|
|
286
|
+
staticNotice: true,
|
|
287
|
+
}) },
|
|
288
|
+
{ navText: '冲突与警告', html: renderFeedbackBlock({
|
|
289
|
+
title: '冲突与警告',
|
|
290
|
+
toast: overlaps.length === 0
|
|
291
|
+
? { icon: 'ok', msg: '这一版候选与这一天原来的排布没有时段重叠。' }
|
|
292
|
+
: {
|
|
293
|
+
icon: 'danger',
|
|
294
|
+
msg: '有 ' + String(overlaps.length) + ' 处候选与落盘前原有的事件时段重叠。',
|
|
295
|
+
lines: overlaps.map((o) => o.candidate + ' ↔ ' + o.locked + ',重叠 ' + o.overlap + '(' + String(o.minutes) + ' 分钟)'),
|
|
296
|
+
},
|
|
297
|
+
staticNotice: true,
|
|
298
|
+
}) },
|
|
299
|
+
{ html: renderPreBlock({
|
|
300
|
+
label: '要再改这一版就说这一句',
|
|
301
|
+
command: '把 ' + date + ' 的计划再调整一版',
|
|
302
|
+
actionId: 'ilife-sch-plan-copy-next',
|
|
303
|
+
copyLabel: '复制这句话',
|
|
304
|
+
}) },
|
|
305
|
+
{ navText: '复制与留档', html: scheduleCopyArea({
|
|
306
|
+
title: '复制与留档',
|
|
307
|
+
dataActionId: 'ilife-sch-plan-copy-data',
|
|
308
|
+
logActionId: 'ilife-sch-plan-copy-log',
|
|
309
|
+
...planCopyArea({
|
|
310
|
+
message: '制定次日计划结果:日期 ' + date + ',候选 ' + String(candidates.length) + ' 段共 ' + fmtDur(covered)
|
|
311
|
+
+ ',历史窗口近 ' + String(HISTORY_DAYS) + ' 天共 ' + String(records.length) + ' 条作息记录,贴合率 '
|
|
312
|
+
+ (rate === null ? '—' : String(rate) + '%') + '(贴合 ' + String(match) + ' 段,偏离 ' + String(drift)
|
|
313
|
+
+ ' 段,无参考 ' + String(none) + ' 段),远端侧 ' + REMOTE_LABEL[remote],
|
|
314
|
+
command: 'schedule-cmd-read schedule.plan.write --params {"op":"upsert","date":"' + date + '"}',
|
|
315
|
+
source: '日程计划表(' + date + ' 落库 ' + String(written.length) + ' 件)',
|
|
316
|
+
}),
|
|
317
|
+
}) },
|
|
318
|
+
]);
|
|
319
|
+
return assembleDocPage({ head, content: toc + body, extraCss: planPartsCss() });
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=discussDocs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discussDocs.js","sourceRoot":"","sources":["../../src/plan/discussDocs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ScheduleDb } from '../fetch/db.js';
|
|
2
|
+
import { type RemoteState } from './receipt.js';
|
|
3
|
+
import { type TierReport } from './probe.js';
|
|
4
|
+
/** 「飞书探测」整页:三档结论 + 下一步 + 本地这一天的账(**这一趟没写任何对象**)。
|
|
5
|
+
*
|
|
6
|
+
* #896 · 「授权登录过」与进度条读 `report.authenticated`(布尔位),不读 `report.openId` 原值:
|
|
7
|
+
* 回执不带 openId 原串(隐私),`handlers.ts` 重建时 `openId` 置 null 仅占形状,显示以布尔位为准。
|
|
8
|
+
*/
|
|
9
|
+
export declare function probePage(handle: ScheduleDb, date: string, report: TierReport): string;
|
|
10
|
+
export interface SyncPayload {
|
|
11
|
+
readonly message: string;
|
|
12
|
+
readonly remote: RemoteState;
|
|
13
|
+
readonly counts: Record<string, number>;
|
|
14
|
+
readonly notes: readonly string[];
|
|
15
|
+
readonly errors: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
/** 「日程管家同步」整页:这一趟做了什么分格报出来,没成的逐条点名。 */
|
|
18
|
+
export declare function syncPage(handle: ScheduleDb, date: string, payload: SyncPayload): string;
|
|
19
|
+
//# sourceMappingURL=feishuDocs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feishuDocs.d.ts","sourceRoot":"","sources":["../../src/plan/feishuDocs.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAa,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAQ5D,OAAO,EAA8B,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAkC,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAiD7E;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAqFtF;AAID,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAuBD,uCAAuC;AACvC,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,MAAM,CAiFvF"}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/** #788 · 飞书两条唤醒词的**两张页**:能力探测(只读)与日程管家同步(回执)。
|
|
2
|
+
*
|
|
3
|
+
* 为什么两张分开(照老侧的分工,也与 #787 的接缝对上):
|
|
4
|
+
* · 「飞书探测」(`op=sync` + `dryRun`)——**先看**:三档能力门探一遍,一门写都不发;
|
|
5
|
+
* · 「日程管家同步」(`op=sync`)——**执行**:回填标识、补齐远端、清孤儿,然后把这一趟做了什么
|
|
6
|
+
* 分格报出来。老侧那种「写之前先问一句」的交互,落在这两张页的分工上:要问就先跑探测,
|
|
7
|
+
* 要写就说同步(#787 的证据件把这一问划给了本票)。
|
|
8
|
+
*
|
|
9
|
+
* **页上文案纪律**:不出现命令键、库列名、参数名、票号与远端对象标识(那一串是内部标识,只进回执,
|
|
10
|
+
* 不进页);并列关系用读数卡与表格表达,不拿 `·`/`;`/`|`/`、`/`~` 顶替。
|
|
11
|
+
*/
|
|
12
|
+
import { renderCaliberLine, renderConclusionBar, renderDataTable, renderFeedbackBlock, renderKpiGrid, renderListRows, renderPreBlock, } from 'base-paint/blocks';
|
|
13
|
+
import { renderFactStrip } from 'base-paint';
|
|
14
|
+
import { listPlanEvents, shortLarkVersion } from '../fetch/index.js';
|
|
15
|
+
import { fmtDurShort, l1Of } from '../policy/index.js';
|
|
16
|
+
import { scheduleCopyArea } from '../render/copyArea.js';
|
|
17
|
+
import { assembleDocPage } from '../shared/docPage.js';
|
|
18
|
+
import { pageSections } from '../shared/pageNav.js';
|
|
19
|
+
import { minutesOfDayEnd } from './planDocs.js';
|
|
20
|
+
import { planPartsCss, renderSectionTitle } from './planParts.js';
|
|
21
|
+
import { REMOTE_LABEL, planCopyArea } from './receipt.js';
|
|
22
|
+
import { TIER_CN, TIER_NEXT, TIER_VALUE } from './probe.js';
|
|
23
|
+
const EYEBROW = '作息管家 日程与计划';
|
|
24
|
+
/** 外部来的原话(命令行 stderr、回执 message、错误串)上屏前过分隔符门(#516):
|
|
25
|
+
* 页自己的文案本来就照纪律写,这几处是**别的进程吐出来的字**——真让它把 `/`/`、` 带上屏,
|
|
26
|
+
* 就是设计债进门。做法是把那几种并列符号换成行文逗号,只动上屏这一份,回执载荷一字不改。 */
|
|
27
|
+
function plain(text) {
|
|
28
|
+
return text
|
|
29
|
+
.replace(/[·;;||//、+~~]/g, ',')
|
|
30
|
+
.replace(/,{2,}/g, ',')
|
|
31
|
+
.replace(/,([))】」])/g, '$1');
|
|
32
|
+
}
|
|
33
|
+
/** 事实条「命令行版本」只印数字(口径唯一定义地是 `fetch` 门的 `shortLarkVersion`)。
|
|
34
|
+
* `null`(没装)印「没装」,`unknown`/无数字印「读不到」。 */
|
|
35
|
+
/** 同步回执的分格(`runSync` 的 `counts`)在页上的名字与读法,一处定义。 */
|
|
36
|
+
const COUNT_LABELS = [
|
|
37
|
+
{ key: 'backfilled', label: '回填标识', hint: '远端本来就有但本地缺标识的,这一趟认回来的' },
|
|
38
|
+
{ key: 'created', label: '远端新建', hint: '本地有但远端没有,这一趟补上去的' },
|
|
39
|
+
{ key: 'updated', label: '远端改动', hint: '两边标题或备注不一样,按本地那一条改过去的' },
|
|
40
|
+
{ key: 'timeSynced', label: '时段回写', hint: '你在飞书里改过时段,尊重你,把它写回本地的' },
|
|
41
|
+
{ key: 'deleted', label: '远端清理', hint: '孤儿与同槽冗余,这一趟清掉的' },
|
|
42
|
+
{ key: 'pastSkipped', label: '过去日期跳过', hint: '昨天以前的计划不补建,免得死灰复燃' },
|
|
43
|
+
{ key: 'duplicates', label: '同槽冗余', hint: '同一时段里历史留下的重复对象' },
|
|
44
|
+
{ key: 'failed', label: '失败', hint: '这一趟没成的那几件' },
|
|
45
|
+
];
|
|
46
|
+
function eventRows(events) {
|
|
47
|
+
return events.map((p) => ({
|
|
48
|
+
time: p.time_start + ' 至 ' + p.time_end,
|
|
49
|
+
title: p.title,
|
|
50
|
+
category: l1Of(p.category ?? ''),
|
|
51
|
+
remote: p.feishu_event_id === null ? '没同步过' : '已同步飞书',
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
function localCounts(handle, date) {
|
|
55
|
+
const events = listPlanEvents(handle, date);
|
|
56
|
+
return {
|
|
57
|
+
total: events.length,
|
|
58
|
+
synced: events.filter((p) => p.feishu_event_id !== null).length,
|
|
59
|
+
minutes: events.reduce((sum, p) => sum + Math.max(0, minutesOfDayEnd(p.time_end) - minutesOfDayEnd(p.time_start)), 0),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/* ─────────────────────── ① 飞书探测(只读,三档) ─────────────────────── */
|
|
63
|
+
/** 「飞书探测」整页:三档结论 + 下一步 + 本地这一天的账(**这一趟没写任何对象**)。
|
|
64
|
+
*
|
|
65
|
+
* #896 · 「授权登录过」与进度条读 `report.authenticated`(布尔位),不读 `report.openId` 原值:
|
|
66
|
+
* 回执不带 openId 原串(隐私),`handlers.ts` 重建时 `openId` 置 null 仅占形状,显示以布尔位为准。
|
|
67
|
+
*/
|
|
68
|
+
export function probePage(handle, date, report) {
|
|
69
|
+
const local = localCounts(handle, date);
|
|
70
|
+
const kpis = [
|
|
71
|
+
{ label: '能力档位', value: TIER_VALUE[report.tier], detail: plain(report.why) },
|
|
72
|
+
{ label: '这一天本地计划', value: String(local.total), unit: '条', detail: '共 ' + fmtDurShort(local.minutes) },
|
|
73
|
+
{ label: '带远端标识的', value: String(local.synced), unit: '条', detail: '同步过的那些' },
|
|
74
|
+
{
|
|
75
|
+
label: '这一趟写了几笔',
|
|
76
|
+
value: '0',
|
|
77
|
+
detail: '只读探测,远端一行没动',
|
|
78
|
+
// 三档全通时给满,其余档按三门过了几门给(读数同源:探测结果那一份)。
|
|
79
|
+
// #896 · 读 authenticated 布尔位,不读 openId 原值(回执不带原串,见 probe.ts 件头)。
|
|
80
|
+
bar: { pct: Math.round(([report.cliPath === null ? 0 : 1, report.authenticated ? 1 : 0, report.calendar ? 1 : 0]
|
|
81
|
+
.reduce((a, b) => a + b, 0) / 3) * 100) },
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
const head = {
|
|
85
|
+
docTitle: '作息管家 飞书探测',
|
|
86
|
+
eyebrow: EYEBROW,
|
|
87
|
+
title: '飞书探测',
|
|
88
|
+
subtitle: '看本机的飞书能力到哪一档,以及 ' + date + ' 这一天本地排了什么。这一步只读,不写任何对象。',
|
|
89
|
+
};
|
|
90
|
+
const steps = [
|
|
91
|
+
{ step: '装有命令行', state: report.cliPath === null ? '没找到' : '在场', why: report.cliPath === null ? '家目录与查找路径里都没有' : '找到了可执行文件' },
|
|
92
|
+
{ step: '授权登录过', state: report.authenticated ? '过了' : '没过', why: report.authenticated ? '查到了登录身份' : '终端里查不到登录身份' },
|
|
93
|
+
{ step: '日历拉得动', state: report.calendar ? '拉得动' : '拉不动', why: report.calendar ? '今日议程这一问有回应' : '今日议程那一问没成' },
|
|
94
|
+
];
|
|
95
|
+
const { toc, body } = pageSections([
|
|
96
|
+
{ navText: '这一趟探测的结论', html: renderKpiGrid(kpis, { title: '这一趟探测的结论' }) },
|
|
97
|
+
{ html: renderConclusionBar('飞书能力:' + TIER_CN[report.tier] + '。' + plain(report.why)
|
|
98
|
+
+ '。要动远端就说「日程管家同步」,要留个只读的快照就是这一页。') },
|
|
99
|
+
{ navText: '三道门逐道看', html: renderSectionTitle('三道门逐道看')
|
|
100
|
+
+ renderDataTable({
|
|
101
|
+
columns: [
|
|
102
|
+
{ key: 'step', label: '探什么' },
|
|
103
|
+
{ key: 'state', label: '结果' },
|
|
104
|
+
{ key: 'why', label: '怎么看出来的' },
|
|
105
|
+
],
|
|
106
|
+
rows: steps,
|
|
107
|
+
}) },
|
|
108
|
+
{ html: renderFactStrip({
|
|
109
|
+
items: [
|
|
110
|
+
{ label: '命令行版本', value: report.version === null ? '没装' : shortLarkVersion(report.version) },
|
|
111
|
+
{ label: '探测日期', value: date },
|
|
112
|
+
{ label: '本地这一天的计划', value: String(local.total) + ' 条' },
|
|
113
|
+
{ label: '远端这一趟', value: '没碰' },
|
|
114
|
+
],
|
|
115
|
+
}) },
|
|
116
|
+
{ navText: '下一步怎么走', html: renderSectionTitle('下一步怎么走')
|
|
117
|
+
+ renderListRows({
|
|
118
|
+
items: TIER_NEXT[report.tier].map((text) => ({ main: text })),
|
|
119
|
+
emptyText: '没有下一步',
|
|
120
|
+
}) },
|
|
121
|
+
{ navText: '本地这一天的账', html: renderSectionTitle('本地这一天的账')
|
|
122
|
+
+ '<p class="sch-pl-note">这一份读的是本地库:这一天排了几条计划,其中几条已经带上远端标识。远端那一边这一趟没拉,故不报对方的条数。</p>'
|
|
123
|
+
+ renderDataTable({
|
|
124
|
+
columns: [
|
|
125
|
+
{ key: 'time', label: '时段' },
|
|
126
|
+
{ key: 'title', label: '计划' },
|
|
127
|
+
{ key: 'category', label: '分类' },
|
|
128
|
+
{ key: 'remote', label: '远端标识' },
|
|
129
|
+
],
|
|
130
|
+
rows: eventRows(listPlanEvents(handle, date)),
|
|
131
|
+
emptyText: '这一天本地没有计划',
|
|
132
|
+
})
|
|
133
|
+
+ renderCaliberLine('探测只读,三道门都只问不写,本地库这一趟也没动过') },
|
|
134
|
+
{ html: renderPreBlock({
|
|
135
|
+
label: '要真同步就说这一句',
|
|
136
|
+
command: '同步 ' + date + ' 的日程到飞书',
|
|
137
|
+
actionId: 'ilife-sch-probe-copy-next',
|
|
138
|
+
copyLabel: '复制这句话',
|
|
139
|
+
}) },
|
|
140
|
+
{ navText: '复制与留档', html: scheduleCopyArea({
|
|
141
|
+
title: '复制与留档',
|
|
142
|
+
dataActionId: 'ilife-sch-probe-copy-data',
|
|
143
|
+
logActionId: 'ilife-sch-probe-copy-log',
|
|
144
|
+
...planCopyArea({
|
|
145
|
+
message: '飞书探测:日期 ' + date + ',档位 ' + TIER_CN[report.tier] + ',原因 ' + report.why
|
|
146
|
+
+ ',本地这一天计划 ' + String(local.total) + ' 条、带远端标识 ' + String(local.synced) + ' 条,这一趟写入 0 笔',
|
|
147
|
+
command: 'schedule-cmd-read schedule.plan.write --params {"op":"sync","dryRun":true,"date":"' + date + '"}',
|
|
148
|
+
source: '本机命令行探测与本地日程计划表',
|
|
149
|
+
}),
|
|
150
|
+
}) },
|
|
151
|
+
]);
|
|
152
|
+
return assembleDocPage({ head, content: toc + body, extraCss: planPartsCss() });
|
|
153
|
+
}
|
|
154
|
+
/** 这一趟的结论(页自己的句子,不照抄回执那一串以并列符号分隔的计数):
|
|
155
|
+
* 远端在场就报对齐结果,远端没成/跳过也照实说,失败数单独点名。 */
|
|
156
|
+
function syncConclusion(payload) {
|
|
157
|
+
const c = payload.counts;
|
|
158
|
+
const moved = (c.backfilled ?? 0) + (c.created ?? 0) + (c.updated ?? 0) + (c.timeSynced ?? 0) + (c.deleted ?? 0);
|
|
159
|
+
const head = payload.remote === 'unavailable'
|
|
160
|
+
? '这一趟远端没成,本地那边没有改动。'
|
|
161
|
+
: (moved === 0 ? '两边本来就是对得上,这一趟没有要动的东西。' : '这一趟一共动了 ' + String(moved) + ' 处。');
|
|
162
|
+
const parts = [
|
|
163
|
+
'回填标识 ' + String(c.backfilled ?? 0) + ' 笔',
|
|
164
|
+
'远端新建 ' + String(c.created ?? 0) + ' 笔',
|
|
165
|
+
'远端改动 ' + String(c.updated ?? 0) + ' 笔',
|
|
166
|
+
'时段回写 ' + String(c.timeSynced ?? 0) + ' 笔',
|
|
167
|
+
'远端清理 ' + String(c.deleted ?? 0) + ' 笔',
|
|
168
|
+
].join(',');
|
|
169
|
+
const tail = (c.failed ?? 0) === 0
|
|
170
|
+
? '失败 0 笔。'
|
|
171
|
+
: '失败 ' + String(c.failed ?? 0) + ' 笔,逐条在下面。';
|
|
172
|
+
return head + parts + '。' + tail;
|
|
173
|
+
}
|
|
174
|
+
/** 「日程管家同步」整页:这一趟做了什么分格报出来,没成的逐条点名。 */
|
|
175
|
+
export function syncPage(handle, date, payload) {
|
|
176
|
+
const events = listPlanEvents(handle, date);
|
|
177
|
+
const failed = payload.counts.failed ?? 0;
|
|
178
|
+
const kpis = COUNT_LABELS.map((c) => ({
|
|
179
|
+
label: c.label,
|
|
180
|
+
value: String(payload.counts[c.key] ?? 0),
|
|
181
|
+
unit: '笔',
|
|
182
|
+
detail: c.hint,
|
|
183
|
+
}));
|
|
184
|
+
const { toc, body } = pageSections([
|
|
185
|
+
{ navText: '这一趟的账', html: renderKpiGrid(kpis, { title: '这一趟的账' }) },
|
|
186
|
+
{ html: renderConclusionBar(syncConclusion(payload)) },
|
|
187
|
+
{ html: renderFactStrip({
|
|
188
|
+
items: [
|
|
189
|
+
{ label: '同步的日期', value: date },
|
|
190
|
+
{ label: '远端侧', value: REMOTE_LABEL[payload.remote] },
|
|
191
|
+
{ label: '本地这一天的计划', value: String(events.length) + ' 条' },
|
|
192
|
+
{ label: '没成的', value: String(failed) + ' 笔' },
|
|
193
|
+
],
|
|
194
|
+
}) },
|
|
195
|
+
{ navText: '这一趟的结果', html: renderFeedbackBlock({
|
|
196
|
+
title: '这一趟的结果',
|
|
197
|
+
toast: failed === 0
|
|
198
|
+
? { icon: payload.remote === 'unavailable' ? 'warn' : 'ok', msg: plain(payload.message) }
|
|
199
|
+
: { icon: 'danger', msg: plain(payload.message), lines: payload.errors.map(plain) },
|
|
200
|
+
staticNotice: true,
|
|
201
|
+
}) },
|
|
202
|
+
{ navText: payload.notes.length === 0 ? '' : '顺带记下的', html: payload.notes.length === 0 ? '' : renderSectionTitle('顺带记下的')
|
|
203
|
+
+ renderListRows({ items: payload.notes.map((text) => ({ main: plain(text) })), emptyText: '没有顺带记下的' }) },
|
|
204
|
+
{ navText: payload.errors.length === 0 ? '' : '没成的逐条名单', html: payload.errors.length === 0 ? '' : renderSectionTitle('没成的逐条名单')
|
|
205
|
+
+ renderListRows({ items: payload.errors.map((text) => ({ main: plain(text) })), emptyText: '没有没成的' }) },
|
|
206
|
+
{ navText: '本地这一天的排布', html: renderSectionTitle('本地这一天的排布')
|
|
207
|
+
+ renderCaliberLine('远端只动带归属标记的对象,你在飞书日历上自己加的那些一律不碰')
|
|
208
|
+
+ renderDataTable({
|
|
209
|
+
columns: [
|
|
210
|
+
{ key: 'time', label: '时段' },
|
|
211
|
+
{ key: 'title', label: '计划' },
|
|
212
|
+
{ key: 'category', label: '分类' },
|
|
213
|
+
{ key: 'remote', label: '远端标识' },
|
|
214
|
+
],
|
|
215
|
+
rows: eventRows(events),
|
|
216
|
+
emptyText: '这一天本地没有计划',
|
|
217
|
+
}) },
|
|
218
|
+
{ navText: '下一步', html: renderSectionTitle('下一步')
|
|
219
|
+
+ renderListRows({
|
|
220
|
+
items: [
|
|
221
|
+
{ main: '要看另一天的差异,把日期一并说清楚,比如「同步 2026-09-22 的日程」。' },
|
|
222
|
+
{ main: '只想先看一眼而不动远端,就说「飞书探测」,那一页只读。' },
|
|
223
|
+
],
|
|
224
|
+
emptyText: '没有下一步',
|
|
225
|
+
}) },
|
|
226
|
+
{ html: renderPreBlock({
|
|
227
|
+
label: '再同步一天就说这一句',
|
|
228
|
+
command: '同步 ' + date + ' 的日程到飞书',
|
|
229
|
+
actionId: 'ilife-sch-sync-copy-next',
|
|
230
|
+
copyLabel: '复制这句话',
|
|
231
|
+
}) },
|
|
232
|
+
{ navText: '复制与留档', html: scheduleCopyArea({
|
|
233
|
+
title: '复制与留档',
|
|
234
|
+
dataActionId: 'ilife-sch-sync-copy-data',
|
|
235
|
+
logActionId: 'ilife-sch-sync-copy-log',
|
|
236
|
+
...planCopyArea({
|
|
237
|
+
message: '日程管家同步:日期 ' + date + ',' + payload.message + ','
|
|
238
|
+
+ COUNT_LABELS.map((c) => c.label + ' ' + String(payload.counts[c.key] ?? 0) + ' 笔').join(',')
|
|
239
|
+
+ (payload.errors.length === 0 ? '' : ',没成的 ' + payload.errors.join(',')),
|
|
240
|
+
command: 'schedule-cmd-read schedule.plan.write --params {"op":"sync","date":"' + date + '"}',
|
|
241
|
+
source: '本地日程计划表与飞书日历',
|
|
242
|
+
ok: payload.errors.length === 0,
|
|
243
|
+
}),
|
|
244
|
+
}) },
|
|
245
|
+
]);
|
|
246
|
+
return assembleDocPage({
|
|
247
|
+
head: {
|
|
248
|
+
docTitle: '作息管家 日程管家同步',
|
|
249
|
+
eyebrow: EYEBROW,
|
|
250
|
+
title: '日程管家同步',
|
|
251
|
+
subtitle: date + ' 这一天本地与飞书对了一遍,这一页报的是这一趟真做了什么。',
|
|
252
|
+
},
|
|
253
|
+
content: toc + body,
|
|
254
|
+
extraCss: planPartsCss(),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=feishuDocs.js.map
|