dsh-task-ledger 0.0.45 → 0.0.47
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/client.js +130 -46
- package/dist/client.js.map +1 -1
- package/dist/host/board.d.ts +13 -108
- package/dist/host/board.js +19 -285
- package/dist/host/errors.d.ts +42 -0
- package/dist/host/errors.js +55 -0
- package/dist/host/repositories/cache.d.ts +27 -0
- package/dist/host/repositories/cache.js +57 -0
- package/dist/host/repositories/identity.repository.d.ts +9 -0
- package/dist/host/repositories/identity.repository.js +20 -0
- package/dist/host/{ledger-read.d.ts → repositories/ledger.repository.d.ts} +10 -4
- package/dist/host/repositories/ledger.repository.js +85 -0
- package/dist/host/repositories/records.d.ts +5 -0
- package/dist/host/repositories/records.js +48 -0
- package/dist/host/{script.js → repositories/runner.js} +3 -2
- package/dist/host/routes.d.ts +17 -0
- package/dist/host/routes.js +215 -64
- package/dist/host/services/dates.d.ts +37 -0
- package/dist/host/services/dates.js +71 -0
- package/dist/host/services/history.service.d.ts +24 -0
- package/dist/host/services/history.service.js +61 -0
- package/dist/host/services/home.service.d.ts +13 -0
- package/dist/host/services/home.service.js +50 -0
- package/dist/host/services/session.service.d.ts +110 -0
- package/dist/host/services/session.service.js +145 -0
- package/dist/host/services/trend.service.d.ts +26 -0
- package/dist/host/services/trend.service.js +134 -0
- package/dist/host/{skill-registration.d.ts → skill/registration.d.ts} +2 -0
- package/dist/host/{skill-registration.js → skill/registration.js} +5 -2
- package/dist/host/types.d.ts +94 -0
- package/dist/host/workspace.d.ts +8 -0
- package/dist/host/workspace.js +6 -9
- package/dist/index.js +31 -2
- package/package.json +4 -3
- package/dist/host/ledger-read.js +0 -64
- /package/dist/host/{script.d.ts → repositories/runner.d.ts} +0 -0
package/dist/client.js
CHANGED
|
@@ -10,6 +10,8 @@ window.__ModuleLoader__.load({
|
|
|
10
10
|
/** host 路由前缀(全仓唯一;与 host/routes.ts 的 API_PREFIX 对应)。 */
|
|
11
11
|
const API_PREFIX = "api/task-ledger";
|
|
12
12
|
const DEFAULT_TIMEOUT_MS = 8e3;
|
|
13
|
+
/** 趋势端点读 history,比快路径慢一个量级(20 万条实测 4s+),超时单给。 */
|
|
14
|
+
const TREND_TIMEOUT_MS = 3e4;
|
|
13
15
|
/**
|
|
14
16
|
* 错误响应榨人话:host 路由(routes.ts)发的是 `{ error: "..." }`,那里的话是**能直接上界面的**
|
|
15
17
|
* (带工作区名、python3 起不来之类的原文)。不带它界面上只剩「HTTP 500」,等于没报错。
|
|
@@ -40,9 +42,24 @@ window.__ModuleLoader__.load({
|
|
|
40
42
|
clearTimeout(timer);
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
|
-
/**
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
/**
|
|
46
|
+
* 首页快照(快路径:在办全量 + 统计 + 各工作区身份;**不含趋势**)。
|
|
47
|
+
* `fresh` = 让 host 先清 1.5s 读缓存再算(手动刷新 / 首读都要最新,不吃上一屏的缓存)。
|
|
48
|
+
*/
|
|
49
|
+
function fetchBoardSnapshot(opts = {}) {
|
|
50
|
+
return fetchJson(`/board/snapshot${freshSuffix(opts)}`);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 趋势(慢路径:近 8 周 + 四个自然周期,host 侧要读 history)。
|
|
54
|
+
* 超时给得比默认宽:历史量大时读得久(实测 20 万条量级 4s+);
|
|
55
|
+
* 旧宿主没有该端点 ⇒ 404,直接抛给调用方兜底,不阻塞列表。
|
|
56
|
+
*/
|
|
57
|
+
function fetchTrend(opts = {}) {
|
|
58
|
+
return fetchJson(`/board/trend${freshSuffix(opts)}`, {}, TREND_TIMEOUT_MS);
|
|
59
|
+
}
|
|
60
|
+
/** `?fresh=1` 只在真要最新值时带;不带就吃 host 的 1.5s 缓存。 */
|
|
61
|
+
function freshSuffix(opts) {
|
|
62
|
+
return opts.fresh === true ? "?fresh=1" : "";
|
|
46
63
|
}
|
|
47
64
|
//#endregion
|
|
48
65
|
//#region src/client/store.ts
|
|
@@ -66,7 +83,10 @@ window.__ModuleLoader__.load({
|
|
|
66
83
|
keyword: "",
|
|
67
84
|
othersKeyword: ""
|
|
68
85
|
},
|
|
69
|
-
refreshing: false
|
|
86
|
+
refreshing: false,
|
|
87
|
+
trend: null,
|
|
88
|
+
trendStatus: "idle",
|
|
89
|
+
trendError: null
|
|
70
90
|
};
|
|
71
91
|
const listeners = /* @__PURE__ */ new Set();
|
|
72
92
|
/** 首读只触发一次(谁先订阅谁触发),之后一律靠 `refresh()` / `setQuery()`。 */
|
|
@@ -96,17 +116,24 @@ window.__ModuleLoader__.load({
|
|
|
96
116
|
listeners.delete(listener);
|
|
97
117
|
};
|
|
98
118
|
}
|
|
99
|
-
/**
|
|
119
|
+
/**
|
|
120
|
+
* 重读(2026-10-18 拆端点):**两段**——先快路径 `/board/snapshot`(只读在办,首屏立即可渲染),
|
|
121
|
+
* 再慢路径 `/board/trend`(读 history,后台拉;迟到按 token 丢弃,不盖新快照)。
|
|
122
|
+
* 趋势失败(含旧宿主 404)不阻塞列表:trendStatus 置 error,图表区显示兜底文案。
|
|
123
|
+
* 两段都带 `fresh=1`:本函数只由首读与手动刷新触发,都要最新值(host 缓存清两次无害,清是全局的)。
|
|
124
|
+
*/
|
|
100
125
|
async function refresh() {
|
|
101
126
|
const token = ++runToken;
|
|
102
127
|
set({ refreshing: true });
|
|
103
128
|
try {
|
|
104
|
-
const board = await
|
|
129
|
+
const board = await fetchBoardSnapshot({ fresh: true });
|
|
105
130
|
if (token !== runToken) return;
|
|
106
131
|
set({
|
|
107
132
|
status: "ready",
|
|
108
133
|
board,
|
|
109
|
-
error: null
|
|
134
|
+
error: null,
|
|
135
|
+
trendStatus: "loading",
|
|
136
|
+
trendError: null
|
|
110
137
|
});
|
|
111
138
|
} catch (error) {
|
|
112
139
|
if (token !== runToken) return;
|
|
@@ -114,9 +141,26 @@ window.__ModuleLoader__.load({
|
|
|
114
141
|
status: "error",
|
|
115
142
|
error: error instanceof Error ? error.message : String(error)
|
|
116
143
|
});
|
|
144
|
+
return;
|
|
117
145
|
} finally {
|
|
118
146
|
if (token === runToken) set({ refreshing: false });
|
|
119
147
|
}
|
|
148
|
+
try {
|
|
149
|
+
const trend = await fetchTrend({ fresh: true });
|
|
150
|
+
if (token !== runToken) return;
|
|
151
|
+
set({
|
|
152
|
+
trend,
|
|
153
|
+
trendStatus: "ready",
|
|
154
|
+
trendError: null
|
|
155
|
+
});
|
|
156
|
+
} catch (error) {
|
|
157
|
+
if (token !== runToken) return;
|
|
158
|
+
set({
|
|
159
|
+
trend: null,
|
|
160
|
+
trendStatus: "error",
|
|
161
|
+
trendError: error instanceof Error ? error.message : String(error)
|
|
162
|
+
});
|
|
163
|
+
}
|
|
120
164
|
}
|
|
121
165
|
/** 改筛选:全部在浏览器里完成(快照已含全部在办),不发请求。 */
|
|
122
166
|
function setQuery(patch) {
|
|
@@ -156,10 +200,11 @@ window.__ModuleLoader__.load({
|
|
|
156
200
|
return String(b.task.created ?? b.task.started ?? "").localeCompare(String(a.task.created ?? a.task.started ?? ""));
|
|
157
201
|
}
|
|
158
202
|
/**
|
|
159
|
-
* 当前筛选下的两区视图(用户 2026-10-
|
|
203
|
+
* 当前筛选下的两区视图(用户 2026-10-18 调整):
|
|
160
204
|
* - 第一区「我的待办」= 我名下 doing/blocked,吃工作区下拉 + 标题搜索,按创建时间倒序;
|
|
161
|
-
* -
|
|
162
|
-
* **标题 / 执行人搜索**(
|
|
205
|
+
* - 第二区「全部待办」= **所有**在办任务按工作区分组(含我的——用户明确不要过滤掉自己),
|
|
206
|
+
* 吃**状态档**(segmented)+ **标题 / 执行人搜索**(othersKeyword);一个整表(外框连着)。
|
|
207
|
+
* ⇒ 我的任务会同时出现在两个区,这是预期(顶部快看 / 底部全量)。
|
|
163
208
|
*/
|
|
164
209
|
function selectView(current) {
|
|
165
210
|
const { board, query } = current;
|
|
@@ -167,7 +212,7 @@ window.__ModuleLoader__.load({
|
|
|
167
212
|
mine: [],
|
|
168
213
|
groups: [],
|
|
169
214
|
total: 0,
|
|
170
|
-
|
|
215
|
+
allCounts: {
|
|
171
216
|
total: 0,
|
|
172
217
|
doing: 0,
|
|
173
218
|
open: 0,
|
|
@@ -175,13 +220,13 @@ window.__ModuleLoader__.load({
|
|
|
175
220
|
stale: 0
|
|
176
221
|
}
|
|
177
222
|
};
|
|
178
|
-
const
|
|
179
|
-
const
|
|
180
|
-
total:
|
|
181
|
-
doing:
|
|
182
|
-
open:
|
|
183
|
-
blocked:
|
|
184
|
-
stale:
|
|
223
|
+
const allTasks = board.tasks;
|
|
224
|
+
const allCounts = {
|
|
225
|
+
total: allTasks.length,
|
|
226
|
+
doing: allTasks.filter((task) => task.status === "doing").length,
|
|
227
|
+
open: allTasks.filter((task) => task.status === "open").length,
|
|
228
|
+
blocked: allTasks.filter((task) => task.status === "blocked").length,
|
|
229
|
+
stale: allTasks.filter((task) => task.stale === true).length
|
|
185
230
|
};
|
|
186
231
|
const mineRows = board.tasks.filter((task) => isMine(task, board)).filter((task) => query.workspace === "" || task.workspace.id === query.workspace).filter((task) => hitKeyword(query.keyword, [
|
|
187
232
|
task.title,
|
|
@@ -196,7 +241,7 @@ window.__ModuleLoader__.load({
|
|
|
196
241
|
task,
|
|
197
242
|
mine: true
|
|
198
243
|
}));
|
|
199
|
-
const rest = query.scope === "mine" ? [] : board.tasks.filter((task) =>
|
|
244
|
+
const rest = query.scope === "mine" ? [] : board.tasks.filter((task) => statusHit(task, query.status)).filter((task) => hitKeyword(query.othersKeyword, [task.title, task.owner]));
|
|
200
245
|
const byWorkspace = /* @__PURE__ */ new Map();
|
|
201
246
|
for (const task of rest) {
|
|
202
247
|
const entry = byWorkspace.get(task.workspace.id) ?? {
|
|
@@ -224,8 +269,8 @@ window.__ModuleLoader__.load({
|
|
|
224
269
|
return {
|
|
225
270
|
mine: mineRows,
|
|
226
271
|
groups,
|
|
227
|
-
total:
|
|
228
|
-
|
|
272
|
+
total: groups.reduce((sum, group) => sum + group.rows.length, 0),
|
|
273
|
+
allCounts
|
|
229
274
|
};
|
|
230
275
|
}
|
|
231
276
|
//#endregion
|
|
@@ -1166,6 +1211,11 @@ body[data-ds-dark-theme]{
|
|
|
1166
1211
|
const board = state.board;
|
|
1167
1212
|
const view = (0, react.useMemo)(() => selectView(state), [state]);
|
|
1168
1213
|
const stats = board?.stats;
|
|
1214
|
+
const trend = state.trend;
|
|
1215
|
+
const periods = trend?.trend;
|
|
1216
|
+
const trendPending = state.trendStatus === "idle" || state.trendStatus === "loading";
|
|
1217
|
+
/** 快照 + 趋势两段各自的降级工作区(op 不同,合并展示,别装没看见)。 */
|
|
1218
|
+
const degraded = [...board?.degraded ?? [], ...trend?.degraded ?? []];
|
|
1169
1219
|
const workspaceOptions = (0, react.useMemo)(() => [{
|
|
1170
1220
|
value: "",
|
|
1171
1221
|
label: t("workspaceAll")
|
|
@@ -1181,11 +1231,12 @@ body[data-ds-dark-theme]{
|
|
|
1181
1231
|
hint,
|
|
1182
1232
|
interactive: false
|
|
1183
1233
|
});
|
|
1184
|
-
/** 统计台卡:不可点(首页没有已结案可筛),hover 给具体日期区间。
|
|
1234
|
+
/** 统计台卡:不可点(首页没有已结案可筛),hover 给具体日期区间。
|
|
1235
|
+
* 趋势未到 / 读挂 ⇒ 数字留 '—'(StatCard 对 0 的处理)、小字整条不显示,**不拿 0 充数**。 */
|
|
1185
1236
|
const periodCard = (label, period) => (0, react.createElement)(StatCard, {
|
|
1186
1237
|
label: t(label),
|
|
1187
1238
|
value: period?.done ?? 0,
|
|
1188
|
-
hint: t("statCreatedHint", { n: period
|
|
1239
|
+
hint: period === void 0 ? void 0 : t("statCreatedHint", { n: period.created }),
|
|
1189
1240
|
interactive: false,
|
|
1190
1241
|
title: period === void 0 ? void 0 : t("periodRange", {
|
|
1191
1242
|
from: period.from,
|
|
@@ -1193,7 +1244,7 @@ body[data-ds-dark-theme]{
|
|
|
1193
1244
|
})
|
|
1194
1245
|
});
|
|
1195
1246
|
const [chartScope, setChartScope] = (0, react.useState)("all");
|
|
1196
|
-
const chartWeeks = (0, react.useMemo)(() => (
|
|
1247
|
+
const chartWeeks = (0, react.useMemo)(() => (trend?.closed.weekly[chartScope] ?? []).map((bucket) => {
|
|
1197
1248
|
const end = bucket.end ?? bucket.week ?? "";
|
|
1198
1249
|
return {
|
|
1199
1250
|
label: end.slice(5) || bucket.week?.slice(5) || "",
|
|
@@ -1203,7 +1254,7 @@ body[data-ds-dark-theme]{
|
|
|
1203
1254
|
title: chartScope === "mine" ? `截至 ${end}(${t("chartOnlyMine")})` : `截至 ${end}`
|
|
1204
1255
|
};
|
|
1205
1256
|
}), [
|
|
1206
|
-
|
|
1257
|
+
trend,
|
|
1207
1258
|
chartScope,
|
|
1208
1259
|
t
|
|
1209
1260
|
]);
|
|
@@ -1262,7 +1313,7 @@ body[data-ds-dark-theme]{
|
|
|
1262
1313
|
}),
|
|
1263
1314
|
title: t("statStaleTitle", { n: stats.staleDays }),
|
|
1264
1315
|
interactive: false
|
|
1265
|
-
}), periodCard("statWeekDone",
|
|
1316
|
+
}), periodCard("statWeekDone", periods?.thisWeek), periodCard("statLastWeekDone", periods?.lastWeek), periodCard("statMonthDone", periods?.thisMonth), periodCard("statLastMonthDone", periods?.lastMonth)), (0, react.createElement)("div", {
|
|
1266
1317
|
className: "dtl-card",
|
|
1267
1318
|
style: chartCardStyle
|
|
1268
1319
|
}, (0, react.createElement)("div", { style: {
|
|
@@ -1275,7 +1326,13 @@ body[data-ds-dark-theme]{
|
|
|
1275
1326
|
onChange: (event) => {
|
|
1276
1327
|
setChartScope(event.target.checked ? "mine" : "all");
|
|
1277
1328
|
}
|
|
1278
|
-
}), t("chartOnlyMine"))),
|
|
1329
|
+
}), t("chartOnlyMine"))), trendPending ? (0, react.createElement)("div", { style: {
|
|
1330
|
+
...hintStyle,
|
|
1331
|
+
padding: "var(--dtl-space-4) 0"
|
|
1332
|
+
} }, t("chartLoading")) : state.trendStatus === "error" ? (0, react.createElement)("div", { style: {
|
|
1333
|
+
...hintStyle,
|
|
1334
|
+
padding: "var(--dtl-space-4) 0"
|
|
1335
|
+
} }, `${t("chartUnavailable")}${state.trendError === null ? "" : `:${state.trendError}`}`) : chartEmpty ? (0, react.createElement)("div", { style: {
|
|
1279
1336
|
...hintStyle,
|
|
1280
1337
|
padding: "var(--dtl-space-4) 0"
|
|
1281
1338
|
} }, t("chartEmpty")) : (0, react.createElement)(GroupedBarChart, {
|
|
@@ -1305,7 +1362,26 @@ body[data-ds-dark-theme]{
|
|
|
1305
1362
|
tone: "guide",
|
|
1306
1363
|
title: t("emptyNoWorkspace"),
|
|
1307
1364
|
hint: t("emptyNoWorkspaceHint")
|
|
1308
|
-
}) : (0, react.createElement)("div", null, (0
|
|
1365
|
+
}) : (0, react.createElement)("div", null, board !== null && (board.degraded?.length ?? 0) > 0 ? (0, react.createElement)("div", { style: {
|
|
1366
|
+
display: "flex",
|
|
1367
|
+
alignItems: "flex-start",
|
|
1368
|
+
gap: "var(--dtl-space-2)",
|
|
1369
|
+
padding: "var(--dtl-space-2) var(--dtl-space-3)",
|
|
1370
|
+
marginBottom: "var(--dtl-space-3)",
|
|
1371
|
+
border: "1px solid var(--dtl-danger)",
|
|
1372
|
+
borderRadius: "var(--dtl-radius-md)",
|
|
1373
|
+
background: "var(--dtl-danger-soft)",
|
|
1374
|
+
color: "var(--dtl-fg)",
|
|
1375
|
+
fontSize: "var(--dtl-font-sm)",
|
|
1376
|
+
lineHeight: "var(--dtl-line-sm)"
|
|
1377
|
+
} }, (0, react.createElement)("span", { style: {
|
|
1378
|
+
color: "var(--dtl-danger)",
|
|
1379
|
+
flex: "none",
|
|
1380
|
+
fontWeight: 600
|
|
1381
|
+
} }, t("degradedTitle")), (0, react.createElement)("span", null, degraded.map((item) => t("degradedItem", {
|
|
1382
|
+
title: item.workspaceTitle,
|
|
1383
|
+
message: item.message
|
|
1384
|
+
})).join(";"))) : null, (0, react.createElement)("div", { style: regionHeadRowStyle }, (0, react.createElement)("span", { style: {
|
|
1309
1385
|
color: "var(--dtl-fg-3)",
|
|
1310
1386
|
display: "inline-flex",
|
|
1311
1387
|
flex: "none"
|
|
@@ -1344,7 +1420,7 @@ body[data-ds-dark-theme]{
|
|
|
1344
1420
|
} }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconFlatListOutlineRegular, { size: 16 })), (0, react.createElement)("span", { style: {
|
|
1345
1421
|
...regionHeadTitleStyle,
|
|
1346
1422
|
fontSize: "var(--dtl-font-md)"
|
|
1347
|
-
} }, t("
|
|
1423
|
+
} }, t("regionAll")), (0, react.createElement)("span", { style: { flex: "1 1 auto" } }), (0, react.createElement)(Segmented, {
|
|
1348
1424
|
id: "dtl-others-status",
|
|
1349
1425
|
value: state.query.status,
|
|
1350
1426
|
label: t("statusLabel"),
|
|
@@ -1352,27 +1428,27 @@ body[data-ds-dark-theme]{
|
|
|
1352
1428
|
{
|
|
1353
1429
|
value: "all",
|
|
1354
1430
|
label: t("statusAll"),
|
|
1355
|
-
badge: orZero(view.
|
|
1431
|
+
badge: orZero(view.allCounts.total)
|
|
1356
1432
|
},
|
|
1357
1433
|
{
|
|
1358
1434
|
value: "active",
|
|
1359
1435
|
label: t("statusActive"),
|
|
1360
|
-
badge: orZero(view.
|
|
1436
|
+
badge: orZero(view.allCounts.doing)
|
|
1361
1437
|
},
|
|
1362
1438
|
{
|
|
1363
1439
|
value: "open",
|
|
1364
1440
|
label: t("statusOpen"),
|
|
1365
|
-
badge: orZero(view.
|
|
1441
|
+
badge: orZero(view.allCounts.open)
|
|
1366
1442
|
},
|
|
1367
1443
|
{
|
|
1368
1444
|
value: "blocked",
|
|
1369
1445
|
label: t("statusBlocked"),
|
|
1370
|
-
badge: orZero(view.
|
|
1446
|
+
badge: orZero(view.allCounts.blocked)
|
|
1371
1447
|
},
|
|
1372
1448
|
{
|
|
1373
1449
|
value: "stale",
|
|
1374
1450
|
label: t("statusStale"),
|
|
1375
|
-
badge: orZero(view.
|
|
1451
|
+
badge: orZero(view.allCounts.stale)
|
|
1376
1452
|
}
|
|
1377
1453
|
],
|
|
1378
1454
|
onChange: (next) => {
|
|
@@ -1395,15 +1471,15 @@ body[data-ds-dark-theme]{
|
|
|
1395
1471
|
fontSize: "var(--dtl-font-lg)",
|
|
1396
1472
|
fontWeight: 600,
|
|
1397
1473
|
marginBottom: "var(--dtl-space-1)"
|
|
1398
|
-
} }, t("
|
|
1474
|
+
} }, t("allEmptyTitle")), (0, react.createElement)("div", { style: {
|
|
1399
1475
|
fontSize: "var(--dtl-font-md)",
|
|
1400
1476
|
color: "var(--dtl-fg-2)",
|
|
1401
1477
|
marginBottom: "var(--dtl-space-3)"
|
|
1402
|
-
} }, t("
|
|
1478
|
+
} }, t("allEmptyHint")), (0, react.createElement)(Button, {
|
|
1403
1479
|
variant: "primary",
|
|
1404
1480
|
size: "md",
|
|
1405
1481
|
onClick: onBack
|
|
1406
|
-
}, t("
|
|
1482
|
+
}, t("allEmptyAction"))) : (0, react.createElement)("div", { style: { marginTop: "var(--dtl-space-2)" } }, view.groups.map((group) => (0, react.createElement)(WorkspaceGroupView, {
|
|
1407
1483
|
key: group.workspaceId,
|
|
1408
1484
|
t,
|
|
1409
1485
|
group,
|
|
@@ -1414,7 +1490,7 @@ body[data-ds-dark-theme]{
|
|
|
1414
1490
|
function orZero(n) {
|
|
1415
1491
|
return n > 0 ? n : void 0;
|
|
1416
1492
|
}
|
|
1417
|
-
/**
|
|
1493
|
+
/** 一个工作区分组(全部待办表格段):段头(点+名+统计)→ 列头行 → 任务行。
|
|
1418
1494
|
* 统计口径(用户 2026-10-18):共 N|待办 N|进行中 N 常显(0 也显);
|
|
1419
1495
|
* 阻塞 / 停滞**只在 >0 时出现**。 */
|
|
1420
1496
|
function WorkspaceGroupView(props) {
|
|
@@ -1460,6 +1536,8 @@ body[data-ds-dark-theme]{
|
|
|
1460
1536
|
loading: "读取中…",
|
|
1461
1537
|
retry: "重试",
|
|
1462
1538
|
loadFailed: "读取失败",
|
|
1539
|
+
degradedTitle: "部分工作区读取失败",
|
|
1540
|
+
degradedItem: "{title}:{message}",
|
|
1463
1541
|
statsPlaceholder: "统计报表尚未开建(另立任务):这里以后放分类分布、按人完成数、时间线。",
|
|
1464
1542
|
statMyActive: "我的待办",
|
|
1465
1543
|
statMyActiveHint: "阻塞 {n} 条",
|
|
@@ -1483,6 +1561,8 @@ body[data-ds-dark-theme]{
|
|
|
1483
1561
|
chartCaption: "完成(按结案时间)/ 新增(按创建时间),周一起桶;我的 = owner 是我",
|
|
1484
1562
|
chartBucket: "{week} 当周:完成 {done} 条,新增 {created} 条",
|
|
1485
1563
|
chartEmpty: "近 8 周没有记录",
|
|
1564
|
+
chartLoading: "趋势读取中…(列表已就绪,统计稍后到)",
|
|
1565
|
+
chartUnavailable: "趋势暂时读不到(不影响上面的任务列表)",
|
|
1486
1566
|
chartScopeAll: "所有",
|
|
1487
1567
|
chartScopeMine: "我的",
|
|
1488
1568
|
chartOnlyMine: "只看我的",
|
|
@@ -1504,7 +1584,7 @@ body[data-ds-dark-theme]{
|
|
|
1504
1584
|
workspaceAll: "全部工作区",
|
|
1505
1585
|
searchPlaceholder: "搜索",
|
|
1506
1586
|
regionMine: "我的待办",
|
|
1507
|
-
|
|
1587
|
+
regionAll: "全部待办",
|
|
1508
1588
|
showingCount: "显示 {n} 条",
|
|
1509
1589
|
groupTotal: "共 {n} 条",
|
|
1510
1590
|
groupOpen: "待办 {n} 条",
|
|
@@ -1516,9 +1596,9 @@ body[data-ds-dark-theme]{
|
|
|
1516
1596
|
colOwner: "执行人",
|
|
1517
1597
|
colStatus: "状态",
|
|
1518
1598
|
colTime: "时长",
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1599
|
+
allEmptyTitle: "没有可显示的事项",
|
|
1600
|
+
allEmptyHint: "切换上面的状态过滤试试,或新建一个任务。",
|
|
1601
|
+
allEmptyAction: "新建任务",
|
|
1522
1602
|
expandAria: "展开过程文档",
|
|
1523
1603
|
collapseAria: "收起",
|
|
1524
1604
|
ownerUnclaimed: "待认领",
|
|
@@ -1569,6 +1649,8 @@ body[data-ds-dark-theme]{
|
|
|
1569
1649
|
loading: "Loading…",
|
|
1570
1650
|
retry: "Retry",
|
|
1571
1651
|
loadFailed: "Load failed",
|
|
1652
|
+
degradedTitle: "Some workspaces failed to load",
|
|
1653
|
+
degradedItem: "{title}: {message}",
|
|
1572
1654
|
statsPlaceholder: "Stats reports are not built yet (separate task): category breakdown, completions by person, timeline.",
|
|
1573
1655
|
statMyActive: "My todos",
|
|
1574
1656
|
statMyActiveHint: "blocked {n}",
|
|
@@ -1592,6 +1674,8 @@ body[data-ds-dark-theme]{
|
|
|
1592
1674
|
chartCaption: "done (by close time) / created (by create time), weeks start Monday; mine = owner is me",
|
|
1593
1675
|
chartBucket: "week of {week}: {done} done, {created} created",
|
|
1594
1676
|
chartEmpty: "Nothing in the last 8 weeks",
|
|
1677
|
+
chartLoading: "Loading trend… (list is ready, stats will follow)",
|
|
1678
|
+
chartUnavailable: "Trend is unavailable right now (the task lists above are unaffected)",
|
|
1595
1679
|
chartScopeAll: "All",
|
|
1596
1680
|
chartScopeMine: "Mine",
|
|
1597
1681
|
chartOnlyMine: "Mine only",
|
|
@@ -1613,7 +1697,7 @@ body[data-ds-dark-theme]{
|
|
|
1613
1697
|
workspaceAll: "All workspaces",
|
|
1614
1698
|
searchPlaceholder: "Search",
|
|
1615
1699
|
regionMine: "My todos",
|
|
1616
|
-
|
|
1700
|
+
regionAll: "All tasks",
|
|
1617
1701
|
showingCount: "{n} shown",
|
|
1618
1702
|
groupTotal: "{n} total",
|
|
1619
1703
|
groupOpen: "{n} open",
|
|
@@ -1625,9 +1709,9 @@ body[data-ds-dark-theme]{
|
|
|
1625
1709
|
colOwner: "Owner",
|
|
1626
1710
|
colStatus: "Status",
|
|
1627
1711
|
colTime: "Duration",
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1712
|
+
allEmptyTitle: "Nothing to show",
|
|
1713
|
+
allEmptyHint: "Try another status filter above, or create a task.",
|
|
1714
|
+
allEmptyAction: "New task",
|
|
1631
1715
|
expandAria: "Expand worklog",
|
|
1632
1716
|
collapseAria: "Collapse",
|
|
1633
1717
|
ownerUnclaimed: "unclaimed",
|