import { useState, useEffect } from 'react';
import { trpc } from '@/lib/trpc';
import { BarChart2, Ruler, Zap, Play, Trash2, ChevronDown, ChevronRight, RefreshCw, Flame, Box, Layers, Crosshair, Cpu, Timer } from 'lucide-react';
import GenericResultView, { type Overlay3D } from './GenericResultView';
import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip';
/** 将毫秒数格式化为可读时长,如 2m 34s / 47s / 1h 5m */
function fmtDuration(ms: number): string {
const s = Math.floor(ms / 1000);
if (s < 60) return `${s}s`;
const m = Math.floor(s / 60);
if (m < 60) return `${m}m ${s % 60}s`;
return `${Math.floor(m / 60)}h ${m % 60}m`;
}
/** 运行中的任务:实时更新计时;已结束:显示静态 updatedAt - createdAt */
function ElapsedTime({ status, createdAt, updatedAt }: {
status: string;
createdAt: string | Date;
updatedAt: string | Date;
}) {
const start = new Date(createdAt).getTime();
const end = new Date(updatedAt).getTime();
const [now, setNow] = useState(() => Date.now());
useEffect(() => {
if (status !== 'processing' && status !== 'pending') return;
const id = setInterval(() => setNow(Date.now()), 1000);
return () => clearInterval(id);
}, [status]);
const ms = (status === 'processing' || status === 'pending')
? now - start
: end - start;
if (ms < 500) return null;
return (
| 项目 | 值 | 公差 | 结果 |
|---|---|---|---|
| {m.name} | {m.value.toFixed(3)} {m.unit} | ±{m.tolerance} | {m.status === 'pass' ? '合格' : m.status === 'warning' ? '警告' : '超差'} |
后台子进程执行,页面可继续操作;进度约每 1.2s 刷新。
{(r.resultData as SmoothHeatmapMeta | null)?.error ?? '分析失败'}
| 零件 | 点数 | min | max | mean | 合格率 |
|---|---|---|---|---|---|
| {p.name} | {p.pointCount} | {p.min.toFixed(4)} | {p.max.toFixed(4)} | {p.mean.toFixed(4)} | = 0.95 ? 'text-green-400' : p.passRate >= 0.85 ? 'text-amber-400' : 'text-red-400' } > {(p.passRate * 100).toFixed(1)}% |
{(r.resultData as AssemblyMeta | null)?.error ?? '装配检测失败'}
{(r.resultData as SmoothHeatmapMeta | null)?.error ?? '偏差分析失败'}