Add customs tablet frontend prototype
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
'use client';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Alert, Card, Row, Col, Typography, Space, Button, Tabs, Table, Image as AntImage, Empty, Spin, Flex } from 'antd';
|
||||
import { ArrowLeftOutlined } from '@ant-design/icons';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Breadcrumb } from '../../../components/Breadcrumb';
|
||||
import { MockApi } from '../../../services/mockApi';
|
||||
import { MachineDetail, ImageItem } from '../../../types';
|
||||
import { StatusBadge } from '../../../components/StatusBadge';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
export default function MachineDetailPage({ params }: { params: { serialNumber: string } }) {
|
||||
const router = useRouter();
|
||||
const [machine, setMachine] = useState<MachineDetail | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
|
||||
const loadMachineDetail = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setErrorMessage('');
|
||||
const data = await MockApi.getMachineDetail(params.serialNumber);
|
||||
if (!isMounted) return;
|
||||
setMachine(data);
|
||||
} catch {
|
||||
if (!isMounted) return;
|
||||
setMachine(null);
|
||||
setErrorMessage('机器详情加载失败,请稍后重试');
|
||||
} finally {
|
||||
if (isMounted) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
loadMachineDetail();
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, [params.serialNumber]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Flex vertical align="center" justify="center" style={{ padding: 48 }}>
|
||||
<Spin tip="正在加载机器详情..." />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
if (!machine) {
|
||||
return (
|
||||
<Flex vertical align="center" style={{ padding: 48 }}>
|
||||
{errorMessage && (
|
||||
<Alert
|
||||
type="error"
|
||||
message={errorMessage}
|
||||
showIcon
|
||||
style={{ maxWidth: 480, marginBottom: 16 }}
|
||||
/>
|
||||
)}
|
||||
<Empty description="暂无机器详情" />
|
||||
<Button type="primary" onClick={() => router.push('/machines')} style={{ marginTop: 16 }}>
|
||||
返回机器查询
|
||||
</Button>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
const renderImageGroup = (images: ImageItem[]) => {
|
||||
if (!images || images.length === 0) return <Empty description="暂无图片" />;
|
||||
|
||||
return (
|
||||
<AntImage.PreviewGroup>
|
||||
<Space size={[16, 16]} wrap>
|
||||
{images.map((img) => (
|
||||
<Flex
|
||||
key={img.id}
|
||||
vertical
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: 120,
|
||||
gap: 4
|
||||
}}
|
||||
>
|
||||
<div style={{ width: '100%', aspectRatio: '4/3', overflow: 'hidden', borderRadius: 8, background: '#f0f0f0' }}>
|
||||
<AntImage
|
||||
src={img.url}
|
||||
alt={img.name}
|
||||
width="100%"
|
||||
height="100%"
|
||||
style={{ objectFit: 'cover' }}
|
||||
preview={{
|
||||
src: img.url,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Text style={{ fontSize: 12, textAlign: 'center' }}>{img.name}</Text>
|
||||
<Text type="secondary" style={{ fontSize: 11, textAlign: 'center' }}>{img.createdAt}</Text>
|
||||
</Flex>
|
||||
))}
|
||||
</Space>
|
||||
</AntImage.PreviewGroup>
|
||||
);
|
||||
};
|
||||
|
||||
const imageTabs = [
|
||||
{ key: 'incoming', label: '来料检验单', children: renderImageGroup(machine.images.incomingInspection) },
|
||||
{ key: 'startup', label: '开机测试样张', children: renderImageGroup(machine.images.startupTestSample) },
|
||||
{ key: 'production', label: '生产加工单', children: renderImageGroup(machine.images.productionOrder) },
|
||||
{ key: 'robot', label: '机器人查验拍照', children: renderImageGroup(machine.images.robotInspection) },
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Flex justify="space-between" align="center" style={{ marginBottom: 16 }}>
|
||||
<Breadcrumb />
|
||||
<Button icon={<ArrowLeftOutlined />} onClick={() => router.back()}>返回查询</Button>
|
||||
</Flex>
|
||||
|
||||
<Card title="机器基本信息" style={{ marginBottom: 24 }}>
|
||||
<Row gutter={[24, 16]}>
|
||||
<Col span={8}>
|
||||
<Text type="secondary">序列号:</Text> <Text strong>{machine.serialNumber}</Text>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Text type="secondary">机器型号:</Text> <Text strong>{machine.modelName}</Text>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Text type="secondary">所属报关单:</Text> <Button type="link">{machine.customsId}</Button>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Text type="secondary">当前状态:</Text> <StatusBadge status={machine.status} />
|
||||
</Col>
|
||||
{Object.entries(machine.specs).map(([key, value]) => (
|
||||
<Col span={8} key={key}>
|
||||
<Text type="secondary">{key}:</Text> <Text>{value}</Text>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
<Card title="图片资料" style={{ marginBottom: 24 }}>
|
||||
<Tabs items={imageTabs} />
|
||||
</Card>
|
||||
|
||||
<Card title="查验记录">
|
||||
<Table
|
||||
dataSource={machine.inspectionRecords}
|
||||
rowKey="id"
|
||||
pagination={false}
|
||||
locale={{ emptyText: <Empty description="暂无查验记录" /> }}
|
||||
>
|
||||
<Table.Column title="查验时间" dataIndex="time" />
|
||||
<Table.Column title="操作人" dataIndex="operator" />
|
||||
<Table.Column title="结果" dataIndex="result" />
|
||||
<Table.Column title="备注" dataIndex="remark" />
|
||||
</Table>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user