dsh-task-ledger 0.0.56 → 0.0.58

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 CHANGED
@@ -202,11 +202,12 @@ window.__ModuleLoader__.load({
202
202
  finish: false,
203
203
  release: false
204
204
  };
205
- /** 状态档命中(停滞由 host 标记,前端不判阈值)——只作用于第二区。 */
205
+ /** 状态档命中(积压 / 超期 / 停滞由 host 标记,前端不判阈值)——只作用于第二区。 */
206
206
  function statusHit(task, status) {
207
207
  if (status === "all") return true;
208
208
  if (status === "active") return task.status === "doing" || task.status === "blocked";
209
209
  if (status === "open") return task.status === "open";
210
+ if (status === "backlog") return task.backlog === true;
210
211
  if (status === "overdue") return task.overdue === true;
211
212
  return task.stale === true;
212
213
  }
@@ -235,7 +236,8 @@ window.__ModuleLoader__.load({
235
236
  doing: 0,
236
237
  open: 0,
237
238
  overdue: 0,
238
- stale: 0
239
+ stale: 0,
240
+ backlog: 0
239
241
  }
240
242
  };
241
243
  const allTasks = board.tasks;
@@ -244,7 +246,8 @@ window.__ModuleLoader__.load({
244
246
  doing: allTasks.filter((task) => task.status === "doing").length,
245
247
  open: allTasks.filter((task) => task.status === "open").length,
246
248
  overdue: allTasks.filter((task) => task.overdue === true).length,
247
- stale: allTasks.filter((task) => task.stale === true).length
249
+ stale: allTasks.filter((task) => task.stale === true).length,
250
+ backlog: allTasks.filter((task) => task.backlog === true).length
248
251
  };
249
252
  const mineRows = board.tasks.filter((task) => isMine(task, board)).filter((task) => query.workspace === "" || task.workspace.id === query.workspace).filter((task) => hitKeyword(query.keyword, [
250
253
  task.title,
@@ -280,6 +283,7 @@ window.__ModuleLoader__.load({
280
283
  doingCount: entry.rows.filter((row) => row.kind === "task" && row.task.status === "doing").length,
281
284
  overdueCount: entry.rows.filter((row) => row.kind === "task" && row.task.overdue === true).length,
282
285
  staleCount: entry.rows.filter((row) => row.kind === "task" && row.task.stale === true).length,
286
+ backlogCount: entry.rows.filter((row) => row.kind === "task" && row.task.backlog === true).length,
283
287
  openCount: entry.rows.filter((row) => row.kind === "task" && row.task.status === "open").length,
284
288
  total: entry.rows.length,
285
289
  rows: entry.rows.sort(inGroupOrder)
@@ -374,6 +378,9 @@ body{
374
378
  /* ⚠️ 宿主是 state-warn(不是 state-warning,后者无此定义) */
375
379
  --dtl-warning:var(--dsw-alias-state-warn-primary,#f59e0b);
376
380
  --dtl-danger:var(--dsw-alias-state-error-primary,#ec1313);
381
+ /* 超期橙:在「积压黄」与「停滞红」之间再取一档(语义阶梯 灰→黄→橙→红),
382
+ 宿主没有现成的橙 token ⇒ 用 warn + error 两色现算,主题一换自动跟随 */
383
+ --dtl-overdue:color-mix(in srgb,var(--dtl-warning) 55%,var(--dtl-danger));
377
384
  --dtl-link:var(--dsw-alias-link,#3b5bdb);
378
385
  /* 语义色实面上的字(角标 / 实心提示):红绿黄都是中调 ⇒ 白字两个主题都可读 */
379
386
  --dtl-on-signal:#fff;
@@ -660,11 +667,12 @@ body[data-ds-dark-theme]{
660
667
  /* 「查看」钮在表格行里也要常驻布局(display:none 会不算宽度 ⇒ hover 一出就又把行撑开) */
661
668
  .dtl-orow .dtl-viewbtn{display:inline-flex;visibility:hidden;}
662
669
  .dtl-orow:hover .dtl-viewbtn{visibility:visible;}
663
- /* 行首状态圆点:灰=待认领 / 浅蓝=进行中(比「我的」蓝灰一档)/ 黄=阻塞 / 红=停滞;
670
+ /* 行首状态圆点:灰=待认领 / 浅蓝=进行中(比「我的」蓝灰一档)/ 黄=积压 / 橙=超期 / 红=停滞;
664
671
  6px(用户 2026-10-18:8px 太大) */
665
672
  .dtl-dot{display:inline-block;width:6px;height:6px;flex:none;border-radius:50%;}
666
673
  .dtl-dot--doing{background:var(--dtl-business-dim);}
667
- .dtl-dot--blocked{background:var(--dtl-warning);}
674
+ .dtl-dot--backlog{background:var(--dtl-warning);}
675
+ .dtl-dot--overdue{background:var(--dtl-overdue);}
668
676
  .dtl-dot--stale{background:var(--dtl-danger);}
669
677
  .dtl-dot--open,.dtl-dot--closed{background:var(--dtl-fg-3);}
670
678
 
@@ -693,7 +701,8 @@ body[data-ds-dark-theme]{
693
701
  /* 状态条:贴卡片左缘、与正文两行等高的竖向色条(dispatch StatusRail 同款 6×36) */
694
702
  .dtl-rail{display:inline-block;width:6px;height:36px;flex:none;border-radius:var(--dtl-radius-xs);}
695
703
  .dtl-rail--doing{background:var(--dtl-business);}
696
- .dtl-rail--blocked{background:var(--dtl-warning);}
704
+ .dtl-rail--backlog{background:var(--dtl-warning);}
705
+ .dtl-rail--overdue{background:var(--dtl-overdue);}
697
706
  .dtl-rail--stale{background:var(--dtl-danger);}
698
707
  .dtl-rail--open,.dtl-rail--closed{background:var(--dtl-fg-3);}
699
708
 
@@ -720,11 +729,12 @@ body[data-ds-dark-theme]{
720
729
  background:var(--dtl-chip-bg);color:var(--dtl-fg-3);font-size:10px;line-height:16px;
721
730
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;}
722
731
  /* 状态四色 = **实心色块**(用户 2026-10-18:彩色字看不清 ⇒ 改色块 + 反色字):
723
- 待认领灰 / 进行中蓝 / 阻塞黄 / 停滞红(与行首圆点同色系)。
732
+ 待认领灰 / 进行中蓝 / 积压黄 / 超期橙 / 停滞红(与行首圆点同色系)。
724
733
  红黄蓝都是中调 ⇒ 白字两个主题都可读;灰块用「字色底 + 面色字」⇒ 明暗自动反过来 */
725
734
  .dtl-tag--open{background:var(--dtl-fg-3);color:var(--dtl-surface-1);font-weight:600;}
726
735
  .dtl-tag--doing{background:var(--dtl-business);color:var(--dtl-on-signal);font-weight:600;}
727
- .dtl-tag--blocked{background:var(--dtl-warning);color:var(--dtl-on-signal);font-weight:600;}
736
+ .dtl-tag--backlog{background:var(--dtl-warning);color:var(--dtl-on-signal);font-weight:600;}
737
+ .dtl-tag--overdue{background:var(--dtl-overdue);color:var(--dtl-on-signal);font-weight:600;}
728
738
  .dtl-tag--stale{background:var(--dtl-danger);color:var(--dtl-on-signal);font-weight:600;}
729
739
  /* 执行人:浅蓝底(与状态色区分:状态是「事怎么样」,人是「谁在做」) */
730
740
  .dtl-tag--person{background:var(--dtl-open-bg-soft);color:var(--dtl-fg-2);}
@@ -935,11 +945,11 @@ body[data-ds-dark-theme]{
935
945
  */
936
946
  function Tag(props) {
937
947
  ensureUiBase();
938
- const { text, tone = "neutral", title } = props;
948
+ const { text, tone = "neutral", title, tip } = props;
939
949
  const long = displayWidth(text) > TAG_MAX_WIDTH;
940
950
  return (0, react.createElement)("span", {
941
951
  className: `dtl-tag dtl-tag--${tone}`,
942
- title: long ? title ?? text : void 0
952
+ title: tip ?? (long ? title ?? text : void 0)
943
953
  }, text);
944
954
  }
945
955
  /** 空态:`guide` = 真空引导卡(虚线),`filtered` = 筛选空小字。 */
@@ -1082,44 +1092,96 @@ body[data-ds-dark-theme]{
1082
1092
  * 行 = 一条淡分隔线格:上下居中的状态圆点 + 任务(标题行 + 标签行;**标签行最前是状态标签**)
1083
1093
  * + **执行人列**(原状态位,有执行人才摆 `@名字` 标签)+ 最右「@创建人 创建于 年-月-日 时:分:秒」
1084
1094
  * (悬停掉时分秒并让位给操作钮)+ 查看。
1085
- * 状态一律**标签型、四色**(用户 2026-10-18:原来是一排素字 / pill,现在与人员**位置互换**):
1086
- * 灰=待认领 / 蓝=进行中 / 黄=阻塞 / 红=停滞;停滞标签悬停给**配置出来的**阈值解释
1087
- * (staleDays 由 host 下发)。圆点颜色同色系。
1095
+ * 状态一律**标签型、五色**(用户 2026-10-18:原来是一排素字 / pill,现在与人员**位置互换**):
1096
+ * 灰=待认领 / 蓝=进行中 / 黄=积压 / 橙=超期 / 红=停滞;三个异常标签悬停给**配置出来的**
1097
+ * 阈值解释(staleDays / overdueDays / backlogDays 由 host 下发)。圆点颜色同色系。
1088
1098
  *
1089
1099
  * 按钮(含查看)**不各判各的**:权限一律问 `resolveActions()`(rows.ts),本文件只按返回值画。
1090
1100
  *
1091
1101
  * 按钮点击行为(含查看)归「任务按钮与会话交接」任务,本文件只做样子与提示。
1092
1102
  */
1103
+ /**
1104
+ * ⚠️ 调试态(用户 2026-10-19):第二区**第一条**把全部状态标签一次摆出来,看全五枚色块。
1105
+ * 定稿后:删掉本常量与 `debugAllTones` 这一路,标签行回到按 `tone` 取一枚。
1106
+ */
1107
+ const DEBUG_TONES = [
1108
+ "open",
1109
+ "backlog",
1110
+ "doing",
1111
+ "overdue",
1112
+ "stale"
1113
+ ];
1093
1114
  /** 行标题:在办 = 任务名(缺则任务号);已结案 = 任务包名(缺则「完成了什么」首句)。 */
1094
1115
  function titleOf(row) {
1095
1116
  if (row.kind === "task") return row.task.title ?? row.task.id;
1096
1117
  const title = row.record.workpackage ?? row.record.summary;
1097
1118
  return title !== void 0 && title !== "" ? title : row.record.src ?? "—";
1098
1119
  }
1099
- /** 状态语义(异常优先:stale 盖过 blocked;blocked 是 host 按 7 天算出来的,不是状态)。 */
1120
+ /** 状态语义(异常优先:停滞 > 超期 > 积压;三者都是 host 按时间算出来的,不是状态)。 */
1100
1121
  function toneOf(row) {
1101
1122
  if (row.kind !== "task") return "closed";
1102
1123
  if (row.task.stale === true) return "stale";
1103
- if (row.task.overdue === true) return "blocked";
1124
+ if (row.task.overdue === true) return "overdue";
1125
+ if (row.task.backlog === true) return "backlog";
1104
1126
  if (row.task.status === "open") return "open";
1105
1127
  return "doing";
1106
1128
  }
1107
1129
  /** 状态文案(已结案没有在办状态 ⇒ 不给标签)。 */
1108
1130
  function statusLabel(tone, t) {
1109
1131
  if (tone === "stale") return t("statusStale");
1110
- if (tone === "blocked") return t("statusBlocked");
1132
+ if (tone === "overdue") return t("statusOverdue");
1133
+ if (tone === "backlog") return t("statusBacklog");
1111
1134
  if (tone === "open") return t("statusOpen");
1112
1135
  if (tone === "doing") return t("statusActive");
1113
1136
  return null;
1114
1137
  }
1115
1138
  function TaskRowView(props) {
1116
- const { t, row, variant, staleDays, board } = props;
1139
+ const { t, row, variant, board, debugAllTones } = props;
1117
1140
  const tone = toneOf(row);
1118
1141
  const isTask = row.kind === "task";
1119
1142
  const tags = (row.kind === "task" ? row.task.tags : row.record.tags) ?? [];
1120
1143
  const created = row.kind === "task" ? row.task.created ?? null : row.record.created ?? null;
1121
1144
  const createdDay = created !== null && created !== void 0 && Date.parse(created) >= 0 ? formatDateTime(created).slice(0, 10) : null;
1122
- const staleTip = staleDays === null || staleDays === void 0 ? void 0 : t("statStaleTitle", { n: staleDays });
1145
+ const stamp = (value) => value === null || value === void 0 ? t("timeUnknown") : formatDateTime(value, { fallback: t("timeUnknown") });
1146
+ const dayText = (n) => n === null || n === void 0 ? t("daysNone") : t("daysValue", { n });
1147
+ const detailTip = (which) => {
1148
+ if (row.kind !== "task") return void 0;
1149
+ const { task } = row;
1150
+ const owner = task.owner ?? "";
1151
+ const who = owner === "" ? t("ownerUnclaimed") : `@${owner}`;
1152
+ const started = stamp(task.started ?? task.created);
1153
+ const updated = stamp(task.updated ?? task.started ?? task.created);
1154
+ if (which === "open") return t("tipOpen", { created: stamp(task.created) });
1155
+ if (which === "backlog") return t("tipBacklog", {
1156
+ created: stamp(task.created),
1157
+ d: dayText(task.waitingDays)
1158
+ });
1159
+ if (which === "doing") return t("tipDoing", {
1160
+ who,
1161
+ started,
1162
+ updated
1163
+ });
1164
+ if (which === "overdue") return t("tipOverdue", {
1165
+ who,
1166
+ started,
1167
+ updated,
1168
+ d: dayText(task.ageDays)
1169
+ });
1170
+ return t("tipStale", {
1171
+ who,
1172
+ started,
1173
+ updated,
1174
+ d: dayText(task.idleDays)
1175
+ });
1176
+ };
1177
+ const thresholdTip = (which) => {
1178
+ const stats = board?.stats;
1179
+ if (stats === void 0) return statusLabel(which, t) ?? "";
1180
+ if (which === "backlog") return t("statBacklogTitle", { n: stats.backlogDays });
1181
+ if (which === "overdue") return t("statOverdueTitle", { n: stats.overdueDays });
1182
+ if (which === "stale") return t("statStaleTitle", { n: stats.staleDays });
1183
+ return statusLabel(which, t) ?? "";
1184
+ };
1123
1185
  const actions = isTask ? resolveActions(row.task, board) : CLOSED_ACTIONS;
1124
1186
  const viewButton = (0, react.createElement)("button", {
1125
1187
  type: "button",
@@ -1147,17 +1209,17 @@ body[data-ds-dark-theme]{
1147
1209
  className: "dtl-minibtn",
1148
1210
  "data-tip": t("tipRelease")
1149
1211
  }, t("actionRelease"));
1150
- const statusText = statusLabel(tone, t);
1151
- const statusTag = statusText === null || tone === "closed" ? null : (0, react.createElement)(Tag, {
1152
- text: statusText,
1153
- tone,
1154
- title: tone === "stale" ? staleTip ?? statusText : statusText
1155
- });
1156
- const alarmTag = tone === "blocked" || tone === "stale" ? (0, react.createElement)(Tag, {
1157
- text: statusLabel(tone, t) ?? "",
1158
- tone,
1159
- title: tone === "stale" ? staleTip : void 0
1160
- }) : null;
1212
+ const tagOf = (which, tip) => {
1213
+ const text = statusLabel(which, t) ?? "";
1214
+ return (0, react.createElement)(Tag, {
1215
+ key: which,
1216
+ text,
1217
+ tone: which,
1218
+ tip: tip ?? detailTip(which)
1219
+ });
1220
+ };
1221
+ const statusTag = tone === "closed" ? null : tagOf(tone);
1222
+ const alarmTag = tone === "backlog" || tone === "overdue" || tone === "stale" ? tagOf(tone) : null;
1161
1223
  const titleLine = (0, react.createElement)("div", { className: "dtl-taskrow__l1" }, (0, react.createElement)("span", {
1162
1224
  className: "dtl-taskrow__title dtl-ellipsis",
1163
1225
  title: titleOf(row)
@@ -1177,7 +1239,7 @@ body[data-ds-dark-theme]{
1177
1239
  who: String(owner),
1178
1240
  when: startedOk ? formatDateTime(String(row.task.started)) : t("timeUnknown")
1179
1241
  });
1180
- const tagLine = (0, react.createElement)("div", { className: "dtl-orow__tags" }, statusTag, tags.map((tag) => (0, react.createElement)(Tag, {
1242
+ const tagLine = (0, react.createElement)("div", { className: "dtl-orow__tags" }, debugAllTones === true ? DEBUG_TONES.map((which) => tagOf(which, thresholdTip(which))) : statusTag, tags.map((tag) => (0, react.createElement)(Tag, {
1181
1243
  key: tag,
1182
1244
  text: `#${tag}`
1183
1245
  })));
@@ -1375,13 +1437,18 @@ body[data-ds-dark-theme]{
1375
1437
  className: "dtl-stats",
1376
1438
  style: statsRowStyle
1377
1439
  }, (0, react.createElement)("div", { className: "dtl-stats__cards" }, card("statMyActive", stats.myActive, t("statMyActiveHint", { n: stats.myOverdue })), card("statOpen", stats.open, t("statOpenHint", { n: days(stats.oldestOpenDays) })), card("statDoing", stats.doing, t("statDoingHint", { n: stats.doing - stats.myActive })), (0, react.createElement)(StatCard, {
1378
- label: t("statBlockedStale"),
1379
- value: stats.overdue + stats.stale,
1380
- hint: t("statBlockedSplit", {
1381
- blocked: stats.overdue,
1440
+ label: t("statAlarm"),
1441
+ value: stats.backlog + stats.overdue + stats.stale,
1442
+ hint: t("statAlarmSplit", {
1443
+ backlog: stats.backlog,
1444
+ overdue: stats.overdue,
1382
1445
  stale: stats.stale
1383
1446
  }),
1384
- title: t("statStaleTitle", { n: stats.staleDays }),
1447
+ title: [
1448
+ t("statBacklogTitle", { n: stats.backlogDays }),
1449
+ t("statOverdueTitle", { n: stats.overdueDays }),
1450
+ t("statStaleTitle", { n: stats.staleDays })
1451
+ ].join(";"),
1385
1452
  interactive: false
1386
1453
  }), periodCard("statWeekDone", periods?.thisWeek), periodCard("statLastWeekDone", periods?.lastWeek), periodCard("statMonthDone", periods?.thisMonth), periodCard("statLastMonthDone", periods?.lastMonth)), (0, react.createElement)("div", {
1387
1454
  className: "dtl-card",
@@ -1482,7 +1549,6 @@ body[data-ds-dark-theme]{
1482
1549
  t,
1483
1550
  row,
1484
1551
  variant: "mine",
1485
- staleDays: board?.stats.staleDays ?? null,
1486
1552
  board
1487
1553
  })), (0, react.createElement)("div", null, (0, react.createElement)("div", { style: regionHeadRowStyle }, (0, react.createElement)("span", { style: {
1488
1554
  color: "var(--dtl-fg-3)",
@@ -1511,9 +1577,14 @@ body[data-ds-dark-theme]{
1511
1577
  label: t("statusOpen"),
1512
1578
  badge: orZero(view.allCounts.open)
1513
1579
  },
1580
+ {
1581
+ value: "backlog",
1582
+ label: t("statusBacklog"),
1583
+ badge: orZero(view.allCounts.backlog)
1584
+ },
1514
1585
  {
1515
1586
  value: "overdue",
1516
- label: t("statusBlocked"),
1587
+ label: t("statusOverdue"),
1517
1588
  badge: orZero(view.allCounts.overdue)
1518
1589
  },
1519
1590
  {
@@ -1550,12 +1621,12 @@ body[data-ds-dark-theme]{
1550
1621
  variant: "primary",
1551
1622
  size: "md",
1552
1623
  onClick: onBack
1553
- }, t("allEmptyAction"))) : (0, react.createElement)("div", { style: { marginTop: "var(--dtl-space-2)" } }, view.groups.map((group) => (0, react.createElement)(WorkspaceGroupView, {
1624
+ }, t("allEmptyAction"))) : (0, react.createElement)("div", { style: { marginTop: "var(--dtl-space-2)" } }, view.groups.map((group, index) => (0, react.createElement)(WorkspaceGroupView, {
1554
1625
  key: group.workspaceId,
1555
1626
  t,
1556
1627
  group,
1557
- staleDays: board?.stats.staleDays ?? null,
1558
- board
1628
+ board,
1629
+ debugFirstRow: index === 0
1559
1630
  })))))))));
1560
1631
  }
1561
1632
  /** 角标:>0 才给数字,0 = undefined(不标)。 */
@@ -1564,15 +1635,16 @@ body[data-ds-dark-theme]{
1564
1635
  }
1565
1636
  /** 一个工作区分组(全部待办表格段):段头(点+名+统计)→ 列头行 → 任务行。
1566
1637
  * 统计口径(用户 2026-10-18):共 N|待办 N|进行中 N 常显(0 也显);
1567
- * 阻塞 / 停滞**只在 >0 时出现**。 */
1638
+ * 积压 / 超期 / 停滞**只在 >0 时出现**。 */
1568
1639
  function WorkspaceGroupView(props) {
1569
- const { t, group, staleDays, board } = props;
1640
+ const { t, group, board, debugFirstRow } = props;
1570
1641
  const [open, setOpen] = (0, react.useState)(group.rows.length <= GROUP_COLLAPSE_OVER);
1571
1642
  const stats = [
1572
1643
  t("groupTotal", { n: group.total }),
1573
1644
  t("groupOpen", { n: group.openCount }),
1574
1645
  t("groupDoing", { n: group.doingCount }),
1575
- ...group.overdueCount > 0 ? [t("groupBlocked", { n: group.overdueCount })] : [],
1646
+ ...group.backlogCount > 0 ? [t("groupBacklog", { n: group.backlogCount })] : [],
1647
+ ...group.overdueCount > 0 ? [t("groupOverdue", { n: group.overdueCount })] : [],
1576
1648
  ...group.staleCount > 0 ? [t("groupStale", { n: group.staleCount })] : []
1577
1649
  ].join(" | ");
1578
1650
  return (0, react.createElement)("div", { className: "dtl-group" }, (0, react.createElement)("button", {
@@ -1587,13 +1659,13 @@ body[data-ds-dark-theme]{
1587
1659
  display: "inline-flex",
1588
1660
  flex: "none",
1589
1661
  color: "var(--dtl-fg-3)"
1590
- } }, (0, react.createElement)(open ? _deepseek_ai_dsh_client_ui_primitives.IconFolderOpenRegular : _deepseek_ai_dsh_client_ui_primitives.IconFolderCloseRegular, { size: 14 })), (0, react.createElement)("span", { className: "dtl-group__name dtl-ellipsis" }, group.title), (0, react.createElement)("span", { style: { flex: "1 1 auto" } }), (0, react.createElement)("span", { className: "dtl-group__stats" }, stats)), open ? (0, react.createElement)("div", null, group.rows.map((row) => (0, react.createElement)(TaskRowView, {
1662
+ } }, (0, react.createElement)(open ? _deepseek_ai_dsh_client_ui_primitives.IconFolderOpenRegular : _deepseek_ai_dsh_client_ui_primitives.IconFolderCloseRegular, { size: 14 })), (0, react.createElement)("span", { className: "dtl-group__name dtl-ellipsis" }, group.title), (0, react.createElement)("span", { style: { flex: "1 1 auto" } }), (0, react.createElement)("span", { className: "dtl-group__stats" }, stats)), open ? (0, react.createElement)("div", null, group.rows.map((row, index) => (0, react.createElement)(TaskRowView, {
1591
1663
  key: row.key,
1592
1664
  t,
1593
1665
  row,
1594
1666
  variant: "others",
1595
- staleDays,
1596
- board
1667
+ board,
1668
+ debugAllTones: debugFirstRow === true && index === 0
1597
1669
  }))) : null);
1598
1670
  }
1599
1671
  //#endregion
@@ -1613,16 +1685,18 @@ body[data-ds-dark-theme]{
1613
1685
  degradedItem: "{title}:{message}",
1614
1686
  statsPlaceholder: "统计报表尚未开建(另立任务):这里以后放分类分布、按人完成数、时间线。",
1615
1687
  statMyActive: "我的待办",
1616
- statMyActiveHint: "阻塞 {n} 条",
1688
+ statMyActiveHint: "超期 {n} 条",
1617
1689
  statOpen: "待认领",
1618
1690
  statOpenHint: "最长未认领 {n}",
1619
1691
  statDoing: "进行中",
1620
1692
  statDoingHint: "其他成员负责 {n} 条",
1621
- statBlockedStale: "阻塞 · 停滞",
1693
+ statAlarm: "积压 · 超期 · 停滞",
1622
1694
  statStaleWord: "停滞",
1623
1695
  statStaleHint: "{n} 条",
1624
- statBlockedSplit: "阻塞 {blocked} | 停滞 {stale}",
1625
- statStaleTitle: "停滞 = 进行中或阻塞超过 {n} 天未更新",
1696
+ statAlarmSplit: "积压 {backlog} | 超期 {overdue} | 停滞 {stale}",
1697
+ statStaleTitle: "停滞 = 进行中满 {n} 天没更新",
1698
+ statOverdueTitle: "超期 = 认领后满 {n} 天还没结案",
1699
+ statBacklogTitle: "积压 = 待认领满 {n} 天没人接",
1626
1700
  statWeekDone: "本周完成",
1627
1701
  statLastWeekDone: "上周完成",
1628
1702
  statMonthDone: "本月完成",
@@ -1651,8 +1725,14 @@ body[data-ds-dark-theme]{
1651
1725
  statusAll: "全部",
1652
1726
  statusActive: "进行中",
1653
1727
  statusOpen: "待认领",
1654
- statusBlocked: "阻塞",
1728
+ statusBacklog: "积压",
1729
+ statusOverdue: "超期",
1655
1730
  statusStale: "停滞",
1731
+ tipOpen: "任务创建于 {created},尚未有人认领。",
1732
+ tipBacklog: "任务创建于 {created},无人认领已满 {d}。",
1733
+ tipDoing: "{who} 于 {started} 开始执行,最后更新于 {updated}。",
1734
+ tipOverdue: "{who} 于 {started} 开始执行,最后更新于 {updated};任务已开始 {d}。",
1735
+ tipStale: "{who} 于 {started} 开始执行,最后更新于 {updated};已停滞 {d}。",
1656
1736
  workspaceLabel: "工作区",
1657
1737
  workspaceAll: "全部工作区",
1658
1738
  searchPlaceholder: "搜索",
@@ -1662,7 +1742,8 @@ body[data-ds-dark-theme]{
1662
1742
  groupTotal: "共 {n} 条",
1663
1743
  groupOpen: "待办 {n} 条",
1664
1744
  groupDoing: "进行中 {n} 条",
1665
- groupBlocked: "阻塞 {n} 条",
1745
+ groupBacklog: "积压 {n} 条",
1746
+ groupOverdue: "超期 {n} 条",
1666
1747
  groupStale: "停滞 {n} 条",
1667
1748
  colTask: "任务",
1668
1749
  colCreator: "创建人",
@@ -1727,16 +1808,18 @@ body[data-ds-dark-theme]{
1727
1808
  degradedItem: "{title}: {message}",
1728
1809
  statsPlaceholder: "Stats reports are not built yet (separate task): category breakdown, completions by person, timeline.",
1729
1810
  statMyActive: "My todos",
1730
- statMyActiveHint: "blocked {n}",
1811
+ statMyActiveHint: "overdue {n}",
1731
1812
  statOpen: "Unclaimed",
1732
1813
  statOpenHint: "longest unclaimed {n}",
1733
1814
  statDoing: "In progress",
1734
1815
  statDoingHint: "owned by other members: {n}",
1735
- statBlockedStale: "Blocked · Stale",
1816
+ statAlarm: "Backlog · Overdue · Stale",
1736
1817
  statStaleWord: "Stale",
1737
1818
  statStaleHint: "{n}",
1738
- statBlockedSplit: "{blocked} blocked | {stale} stale",
1739
- statStaleTitle: "stale = active or blocked with no update for {n}+ days",
1819
+ statAlarmSplit: "{backlog} backlog | {overdue} overdue | {stale} stale",
1820
+ statStaleTitle: "stale = active with no update for {n}+ days",
1821
+ statOverdueTitle: "overdue = claimed {n}+ days ago and still open",
1822
+ statBacklogTitle: "backlog = unclaimed for {n}+ days",
1740
1823
  statWeekDone: "Done this week",
1741
1824
  statLastWeekDone: "Done last week",
1742
1825
  statMonthDone: "Done this month",
@@ -1765,8 +1848,14 @@ body[data-ds-dark-theme]{
1765
1848
  statusAll: "All",
1766
1849
  statusActive: "Active",
1767
1850
  statusOpen: "Unclaimed",
1768
- statusBlocked: "Blocked",
1851
+ statusBacklog: "Backlog",
1852
+ statusOverdue: "Overdue",
1769
1853
  statusStale: "Stale",
1854
+ tipOpen: "Created on {created}; not claimed yet.",
1855
+ tipBacklog: "Created on {created}; unclaimed for {d}.",
1856
+ tipDoing: "{who} started on {started}; last updated {updated}.",
1857
+ tipOverdue: "{who} started on {started}; last updated {updated}; active for {d}.",
1858
+ tipStale: "{who} started on {started}; last updated {updated}; stalled for {d}.",
1770
1859
  workspaceLabel: "Workspace",
1771
1860
  workspaceAll: "All workspaces",
1772
1861
  searchPlaceholder: "Search",
@@ -1776,7 +1865,8 @@ body[data-ds-dark-theme]{
1776
1865
  groupTotal: "{n} total",
1777
1866
  groupOpen: "{n} open",
1778
1867
  groupDoing: "{n} active",
1779
- groupBlocked: "{n} blocked",
1868
+ groupBacklog: "{n} backlog",
1869
+ groupOverdue: "{n} overdue",
1780
1870
  groupStale: "{n} stale",
1781
1871
  colTask: "Task",
1782
1872
  colCreator: "Created by",