'use client' import { useState, useMemo } from 'react' import Link from 'next/link' import { ChevronLeft, ChevronRight, Plus, Download, Eye, X, FileText, Download as DownloadIcon, Trash2 } from 'lucide-react' import { useApi } from '@/lib/hooks' interface BoardCard { id: number sn: string name: string category: string type: string device_model: string version: string description: string firmware: string status: string device_sn: string production_date: string calib_status: string calib_date: string } interface CategoryItem { id: number; name: string; status: string } const statusOptions = ['全部', '在库', '已装配', '故障', '报废'] const calibStatusOptions = ['全部', '合格', '不合格', '待校准'] /** 模拟校准文件数据:key 为板卡 SN */ const calibrationFilesMap: Record = { 'ACB-6000-20250110001': [ { id: 'cf-1', fileName: 'ACB-6000-20250110001_calib_20250112.csv', fileSize: 24576, md5: 'a1b2c3d4e5f6', uploadTime: '2025-01-12 14:30:00', channels: [ { channel: 'CH1', refValue: 100.0, measuredValue: 99.8, deviation: -0.2, result: '合格' }, { channel: 'CH2', refValue: 200.0, measuredValue: 200.3, deviation: 0.15, result: '合格' }, { channel: 'CH3', refValue: 500.0, measuredValue: 499.5, deviation: -0.1, result: '合格' }, { channel: 'CH4', refValue: 1000.0, measuredValue: 999.2, deviation: -0.08, result: '合格' }, ]}, ], 'ACB-6000-20250110002': [ { id: 'cf-2', fileName: 'ACB-6000-20250110002_calib_20250112.csv', fileSize: 23040, md5: 'b2c3d4e5f6a1', uploadTime: '2025-01-12 15:10:00', channels: [ { channel: 'CH1', refValue: 100.0, measuredValue: 100.1, deviation: 0.1, result: '合格' }, { channel: 'CH2', refValue: 200.0, measuredValue: 199.7, deviation: -0.15, result: '合格' }, { channel: 'CH3', refValue: 500.0, measuredValue: 500.8, deviation: 0.16, result: '合格' }, ]}, ], 'ACB-5000-20241205001': [ { id: 'cf-3', fileName: 'ACB-5000-20241205001_calib_20241208.csv', fileSize: 18432, md5: 'c3d4e5f6a1b2', uploadTime: '2024-12-08 09:45:00', channels: [ { channel: 'CH1', refValue: 100.0, measuredValue: 99.9, deviation: -0.1, result: '合格' }, { channel: 'CH2', refValue: 200.0, measuredValue: 200.5, deviation: 0.25, result: '合格' }, ]}, ], 'ACB-6000-20241120001': [ { id: 'cf-4', fileName: 'ACB-6000-20241120001_calib_20250210.csv', fileSize: 25600, md5: 'd4e5f6a1b2c3', uploadTime: '2025-02-10 11:20:00', channels: [ { channel: 'CH1', refValue: 100.0, measuredValue: 98.2, deviation: -1.8, result: '不合格' }, { channel: 'CH2', refValue: 200.0, measuredValue: 203.6, deviation: 1.8, result: '不合格' }, { channel: 'CH3', refValue: 500.0, measuredValue: 500.1, deviation: 0.02, result: '合格' }, ]}, ], } function formatFileSize(bytes: number): string { if (bytes < 1024) return bytes + ' B' return (bytes / 1024).toFixed(1) + ' KB' } function getStatusStyle(status: string) { switch (status) { case '在库': return { backgroundColor: '#E6F7FF', color: '#1890FF', border: '1px solid #91D5FF' } case '已装配': return { backgroundColor: '#F6FFED', color: '#52C41A', border: '1px solid #B7EB8F' } case '故障': return { backgroundColor: '#FFF1F0', color: '#FF4D4F', border: '1px solid #FFCCC7' } case '报废': return { backgroundColor: '#FAFAFA', color: 'rgba(0,0,0,0.45)', border: '1px solid #D9D9D9' } default: return { backgroundColor: '#FAFAFA', color: 'rgba(0,0,0,0.45)', border: '1px solid #D9D9D9' } } } function getCalibStyle(status: string) { switch (status) { case '合格': return { backgroundColor: '#F6FFED', color: '#52C41A', border: '1px solid #B7EB8F' } case '不合格': return { backgroundColor: '#FFF1F0', color: '#FF4D4F', border: '1px solid #FFCCC7' } case '待校准': return { backgroundColor: '#FFFBE6', color: '#FAAD14', border: '1px solid #FFE58F' } default: return {} } } export default function BoardCardsPage() { const { data: boardCardsData, loading, refetch } = useApi('/api/materials', []) const { data: categoriesData } = useApi('/api/material-categories', []) const typeOptions = ['全部', ...categoriesData.filter(c => c.status === '启用').map(c => c.name)] const [filterType, setFilterType] = useState('全部') const [filterStatus, setFilterStatus] = useState('全部') const [filterCalib, setFilterCalib] = useState('全部') const [searchText, setSearchText] = useState('') const [currentPage, setCurrentPage] = useState(1) const [detailDrawer, setDetailDrawer] = useState(null) const [calibFileDrawer, setCalibFileDrawer] = useState(null) const pageSize = 8 if (loading) return
加载中...
const filtered = boardCardsData.filter(b => { if (filterType !== '全部' && b.category !== filterType) return false if (filterStatus !== '全部' && b.status !== filterStatus) return false if (filterCalib !== '全部' && b.calib_status !== filterCalib) return false if (searchText && !b.sn.toLowerCase().includes(searchText.toLowerCase()) && !(b.category || b.name).toLowerCase().includes(searchText.toLowerCase())) return false return true }) const totalPages = Math.ceil(filtered.length / pageSize) const paged = filtered.slice((currentPage - 1) * pageSize, currentPage * pageSize) // 统计 const stats = { total: boardCardsData.length, inStock: boardCardsData.filter(b => b.status === '在库').length, assembled: boardCardsData.filter(b => b.status === '已装配').length, faulty: boardCardsData.filter(b => b.status === '故障').length, pendingCalib: boardCardsData.filter(b => b.calib_status === '待校准').length, } return (
{/* Header */}

物料列表

管理所有物料实例,跟踪物料状态与校准信息

登记物料
{/* Stats Cards */}
{[ { label: '物料总数', value: stats.total, color: '#4a7c59', bg: '#eef5f0' }, { label: '在库', value: stats.inStock, color: '#1890FF', bg: '#E6F7FF' }, { label: '已装配', value: stats.assembled, color: '#52C41A', bg: '#F6FFED' }, { label: '故障', value: stats.faulty, color: '#FF4D4F', bg: '#FFF1F0' }, { label: '待校准', value: stats.pendingCalib, color: '#FAAD14', bg: '#FFFBE6' }, ].map(s => (
{s.label}
{s.value}
))}
{/* Filter */}
{ setSearchText(e.target.value); setCurrentPage(1) }} placeholder="搜索SN或物料分类" style={{ width: '100%', padding: '6px 12px', border: '1px solid #D9D9D9', borderRadius: 6, fontSize: 14, boxSizing: 'border-box' }} />
{/* Table */}
{['物料SN', '物料分类', '物料版本', '生产日期', '状态', '所属设备', '操作'].map(h => ( ))} {paged.map(row => ( ))}
{h}
{row.sn} {row.category || row.name} {row.version} {row.production_date} {row.status} {row.device_sn}
{row.type === '采集板' && ( )}
{/* Pagination */}
显示 {filtered.length > 0 ? (currentPage - 1) * pageSize + 1 : 0}-{Math.min(currentPage * pageSize, filtered.length)} / 共 {filtered.length} 条
{Array.from({ length: totalPages }, (_, i) => ( ))}
{/* Detail Drawer */} {detailDrawer && (
setDetailDrawer(null)} style={{ position: 'absolute', inset: 0, backgroundColor: 'rgba(0,0,0,0.45)' }} />

物料详情

{/* 基本信息 */}

基本信息

物料SN:{detailDrawer.sn}
物料分类:{detailDrawer.category || detailDrawer.name}
物料版本:{detailDrawer.version}
生产日期:{detailDrawer.production_date}
状态: {detailDrawer.status}
{detailDrawer.description &&
备注:{detailDrawer.description}
}
{/* 装配信息 */}

装配信息

所属设备: {detailDrawer.device_sn === '-' ? ( 未装配 ) : ( {detailDrawer.device_sn} )}
{/* 校准信息 */} {detailDrawer.calib_status && detailDrawer.calib_status !== '-' && (

校准信息

校准状态: {detailDrawer.calib_status !== '-' ? ( {detailDrawer.calib_status} ) : ( - )}
校准日期:{detailDrawer.calib_date}
)}
)} {/* Calibration File Drawer */} {calibFileDrawer && (() => { const files = calibrationFilesMap[calibFileDrawer.sn] || [] return (
setCalibFileDrawer(null)} style={{ position: 'absolute', inset: 0, backgroundColor: 'rgba(0,0,0,0.45)' }} />

校准文件 - {calibFileDrawer.sn}

{files.length === 0 ? (
暂无校准文件
) : ( files.map(file => (
{/* 文件信息卡片 */}
{file.fileName}
文件大小:{formatFileSize(file.fileSize)}
MD5:{file.md5}
上传时间:{file.uploadTime}
{/* 校准数据内容 */}
校准数据
{['通道', '参考值', '测量值', '偏差(%)', '结果'].map(h => ( ))} {file.channels.map(ch => ( ))}
{h}
{ch.channel} {ch.refValue.toFixed(1)} {ch.measuredValue.toFixed(1)} 1 ? '#FF4D4F' : 'rgba(0,0,0,0.65)' }}>{ch.deviation > 0 ? '+' : ''}{ch.deviation.toFixed(2)} {ch.result}
)) )}
) })()}
) }