/** * 汇报要素 —— 自 `~/coding/JCAI_PRD/workbench/_components/ModuleWorkspace.tsx` * 的 `ReportModule` 平移;mock 数据换成服务端投影。 * * 「按日 / 周 / 月 / 年**自动**总结此员工的工作——由本人各任务的**任务日志**聚合生成, * 确认即提交,**零手工汇报**。」结构化部分零 LLM(事件流骨架 + 归侧分栏)。 */ import { useState } from 'react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import type { ReportPeriodName, ReportView } from '@contracts'; import { REPORT_PERIOD_LABEL, draftReportRoute, submitReportRoute } from '@contracts'; import { Ico } from '@web-shared/Ico.tsx'; import ScrollArea from '@web-shared/ScrollArea.tsx'; import { call } from '@web-shared/typed-fetch.ts'; import { Chip, DocPanel, Hero, ListEmpty, NoteBand, Section, SidebarHead } from '@web-shared/desk/module-kit.tsx'; const PERIODS: ReadonlyArray<{ k: ReportPeriodName; ico: string }> = [ { k: 'day', ico: 'calendar-days' }, { k: 'week', ico: 'calendar-clock' }, { k: 'month', ico: 'calendar-days' }, { k: 'year', ico: 'history' }, ]; const pct = (v: number): string => `${Math.round(v * 100)}%`; export function ReportDesk() { const queryClient = useQueryClient(); const [period, setPeriod] = useState('day'); const [note, setNote] = useState(''); const q = useQuery({ queryKey: ['report', period], queryFn: () => call(draftReportRoute, { params: { period } }), }); const report = q.data; const submitted = report?.submittedAt !== undefined; const submit = useMutation({ mutationFn: () => call(submitReportRoute, { params: { reportId: report!.id }, body: note.trim() === '' ? {} : { note: note.trim() }, }), onSuccess: () => void queryClient.invalidateQueries({ queryKey: ['report'] }), }); return (
{report === undefined ? (
正在聚合…
) : ( 系统自动生成 由本人各任务的任务日志聚合 } chip={} />
{[ { ico: 'bot', label: '自主率', v: pct(report.metrics.autonomy) }, { ico: 'rotate-ccw', label: '纠正率', v: pct(report.metrics.correction) }, { ico: 'gauge', label: '有效自主率', v: pct(report.metrics.effectiveAutonomy) }, { ico: 'hand', label: '打扰率', v: report.metrics.interruption.toFixed(1) }, { ico: 'git-commit', label: 'DMN 覆盖率', v: pct(report.metrics.dmnCoverage) }, { ico: 'circle-dot', label: '断点率', v: pct(report.metrics.breakpoint) }, ].map((s) => (
{s.v} {s.label}
))}
自主率 = 机器产出 ÷(机器产出 + 人产出),裁决与等待不进分母;它与纠正率 成对读,复合为有效自主率 —— 单看任一都会被优化坏。 单位成本 {Math.round(report.metrics.unitCost.tokens)} token / {report.metrics.unitCost.minutes.toFixed(1)} 分钟每放行单,分母只认放行通过。
{report.sections.map((s) => (
{s.title} {s.terminalLabel !== undefined && {s.terminalLabel}}
{s.lines.map((line, i) => (

{line}

))}
))} {report.sections.length === 0 && 这个周期内没有动作}