feat(bigscreen): 任务展示页 + 暂时关闭语音对话页 + 导航/文档同步

- App.jsx 移除 /voice、新增 /tasks→TaskDisplay。
- pageNav PAGE_ORDER 移除 voice、加 tasks(方向键/页眉/MQTT navigate_rel 自动跟随)。
- useMqttControl:PAGE_ALIAS 加 tasks;移除 voice_*、改 task_refresh。
- PageHeader STATUS_BY_PATH 加 /tasks。
- 新增 TaskDisplay.jsx + task-display.css:轮播卡(分类/状态/标题/摘要/标签/预算/任务ID+QRCodeSVG 扫码接单)、useTasks 轮询 /park/api/tasks、接受 MQTT task_refresh。
- 新增 utils/taskData.js(useTasks, tenantFetch 带租户身份)。
- docs/mqtt-commands.md:navigate 列表/语音章节标注语音页关闭、tasks 页指令。

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Pine
2026-08-25 18:42:32 +08:00
parent 1566477b97
commit d61b59acf5
13 changed files with 441 additions and 41 deletions
+15 -8
View File
@@ -43,8 +43,15 @@ const TOOL_RANK = [
];
/* ---------- 工具函数 ---------- */
const fmtInt = (n) => Math.round(n).toLocaleString('zh-CN');
const fmtWan = (n) => (n >= 10000 ? (n / 10000).toFixed(2) + '亿' : n >= 100 ? n.toFixed(1) + '万' : n.toFixed(1));
const fmtInt = (n) => (Number.isFinite(Number(n)) ? Math.round(Number(n)).toLocaleString('zh-CN') : '--');
/** 万/亿格式化:非有限数值(缺失/不一致口径)安全显示 '--',避免崩溃 */
const fmtWan = (n) => {
const v = Number(n);
if (!Number.isFinite(v)) return '--';
return (v >= 10000 ? (v / 10000).toFixed(2) + '亿' : v >= 100 ? v.toFixed(1) + '万' : v.toFixed(1));
};
/** 安全取数:缺失/非数值回退 0,供直接 .toFixed 调用点使用 */
const num = (v) => (Number.isFinite(Number(v)) ? Number(v) : 0);
/* 数据源:后端 /api/dashboard/snapshot(离线时本地模拟兜底),见 utils/parkData.js */
@@ -265,7 +272,7 @@ function TodayOverview({ d }) {
</div>
<div className="bd-cell bd-cell-tools">
<KpiCard tone="tool" icon="wrench" label="工具调用" value={d.tools.today} unit="次"
sub={`累计 ${(d.tools.total / 10000).toFixed(1)}万次 · 成功率 ${d.tools.success}%`} />
sub={`累计 ${(num(d.tools.total) / 10000).toFixed(1)}万次 · 成功率 ${d.tools.success}%`} />
</div>
<div className="bd-cell bd-cell-jobs">
<KpiCard tone="job" icon="users" label="带动就业" value={d.jobs.total} unit="人"
@@ -294,10 +301,10 @@ function TokenBig({ d }) {
</div>
} />
<div className="bd-real-metrics">
<span>首 token 平均 <b>{d.live.firstToken.toFixed(1)}s</b></span>
<span>首 token 平均 <b>{num(d.live.firstToken).toFixed(1)}s</b></span>
<span>吞吐 <b>{d.live.throughput}</b> tok/s</span>
<span>缓存命中 <b>{d.live.cacheHit.toFixed(1)}%</b></span>
<span>会话输入 <b>{d.live.inputM.toFixed(1)}M</b> / 输出 <b>{d.live.outputM.toFixed(1)}M</b> tok</span>
<span>缓存命中 <b>{num(d.live.cacheHit).toFixed(1)}%</b></span>
<span>会话输入 <b>{num(d.live.inputM).toFixed(1)}M</b> / 输出 <b>{num(d.live.outputM).toFixed(1)}M</b> tok</span>
<span><b>{d.live.rounds}</b> 轮 · <b>{d.live.steps}</b> 步</span>
</div>
<div className="bd-big-body">
@@ -338,7 +345,7 @@ function ToolsBig({ d }) {
<CardHead title="工具调用" icon="wrench" right={
<div className="bd-head-stats">
<span className="bd-ost-chip"><i>今日调用</i><b>{fmtInt(d.tools.today)} 次</b></span>
<span className="bd-ost-chip"><i>累计调用</i><b>{(d.tools.total / 10000).toFixed(1)}万 次</b></span>
<span className="bd-ost-chip"><i>累计调用</i><b>{(num(d.tools.total) / 10000).toFixed(1)}万 次</b></span>
<span className="bd-ost-chip"><i>成功率</i><b>{d.tools.success}%</b></span>
<span className="bd-ost-chip"><i>服务节点</i><b>{d.tools.nodes} / {d.tools.nodes} 在线</b></span>
</div>
@@ -346,7 +353,7 @@ function ToolsBig({ d }) {
<div className="bd-big-body">
<div className="bd-big-right bd-big-stats">
<div className="bd-big-stat"><span>今日调用</span><b>{fmtInt(d.tools.today)}<em>次</em></b></div>
<div className="bd-big-stat"><span>累计调用</span><b>{(d.tools.total / 10000).toFixed(1)}<em>万次</em></b></div>
<div className="bd-big-stat"><span>累计调用</span><b>{(num(d.tools.total) / 10000).toFixed(1)}<em>万次</em></b></div>
<div className="bd-big-stat"><span>成功率</span><b>{d.tools.success}<em>%</em></b></div>
<div className="bd-big-stat"><span>AI 服务节点</span><b>12<em>/12 在线</em></b></div>
</div>