报价单魔魁
This commit is contained in:
264
src/pages/company/quotation/view/index.jsx
Normal file
264
src/pages/company/quotation/view/index.jsx
Normal file
@@ -0,0 +1,264 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Card, Typography, Descriptions, Table, Button, Space, Spin } from 'antd';
|
||||
import { ArrowLeftOutlined, PrinterOutlined, EditOutlined } from '@ant-design/icons';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { supabase } from '@/config/supabase';
|
||||
import ReactDOMServer from 'react-dom/server';
|
||||
import PrintView from '@/components/PrintView';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
const printStyles = `
|
||||
@media print {
|
||||
/* 隐藏所有按钮和不需要的元素 */
|
||||
button, .no-print {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* 只打印卡片内容 */
|
||||
.ant-card {
|
||||
box-shadow: none !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* 移除背景色 */
|
||||
body, .bg-gray-50 {
|
||||
background: white !important;
|
||||
min-height: auto !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* 确保内容完整打印 */
|
||||
.ant-card-body {
|
||||
padding: 24px !important;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
/* 优化表格打印样式 */
|
||||
.ant-table {
|
||||
page-break-inside: auto !important;
|
||||
}
|
||||
|
||||
.ant-table-row {
|
||||
page-break-inside: avoid !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const QuotationView = () => {
|
||||
const navigate = useNavigate();
|
||||
const { id } = useParams();
|
||||
const [data, setData] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const fetchQuotationDetail = async () => {
|
||||
try {
|
||||
const { data: quotation, error } = await supabase
|
||||
.from('resources')
|
||||
.select('*')
|
||||
.eq('id', id)
|
||||
.single();
|
||||
|
||||
if (error) throw error;
|
||||
setData(quotation);
|
||||
} catch (error) {
|
||||
console.error('获取报价单<E4BBB7><E58D95>情失败:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
fetchQuotationDetail();
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
width: 100,
|
||||
render: (_, __, index) => index + 1,
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'productName',
|
||||
width: '40%',
|
||||
},
|
||||
{
|
||||
title: '数量',
|
||||
dataIndex: 'quantity',
|
||||
width: '20%',
|
||||
align: 'right',
|
||||
render: (value) => value?.toLocaleString('zh-CN', { minimumFractionDigits: 2 }),
|
||||
},
|
||||
{
|
||||
title: '单价',
|
||||
dataIndex: 'price',
|
||||
width: '20%',
|
||||
align: 'right',
|
||||
render: (value) => value?.toLocaleString('zh-CN', { minimumFractionDigits: 2 }),
|
||||
},
|
||||
{
|
||||
title: '小计',
|
||||
width: '20%',
|
||||
align: 'right',
|
||||
render: (_, record) => (
|
||||
(record.quantity * record.price)?.toLocaleString('zh-CN', { minimumFractionDigits: 2 })
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const handlePrint = () => {
|
||||
const printWindow = window.open('', '_blank');
|
||||
const printContent = ReactDOMServer.renderToString(<PrintView data={data} />);
|
||||
printWindow.document.write(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>打印报价单</title>
|
||||
<link rel="stylesheet" href="${window.location.origin}/antd.min.css">
|
||||
<style>
|
||||
@media print {
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${printContent}
|
||||
<script>
|
||||
window.onload = function() {
|
||||
window.print();
|
||||
window.onafterprint = function() {
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
printWindow.document.close();
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex justify-center items-center min-h-screen">
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{printStyles}</style>
|
||||
|
||||
<div className="bg-gray-50 min-h-screen ">
|
||||
<Card className="max-w-5xl mx-auto shadow-lg">
|
||||
<div className="flex justify-between items-center mb-6 no-print">
|
||||
<Space>
|
||||
<Button
|
||||
icon={<ArrowLeftOutlined />}
|
||||
onClick={() => navigate('/company/quotation')}
|
||||
>
|
||||
返回列表
|
||||
</Button>
|
||||
</Space>
|
||||
<Space>
|
||||
<Button
|
||||
icon={<EditOutlined />}
|
||||
type="primary"
|
||||
onClick={() => navigate(`/company/quotaInfo/${data.id}?edit=true`)}
|
||||
>
|
||||
编辑报价单
|
||||
</Button>
|
||||
<Button
|
||||
icon={<PrinterOutlined />}
|
||||
onClick={handlePrint}
|
||||
>
|
||||
打印报价单
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
<div className="text-center mb-8">
|
||||
<Title level={2} className="!mb-2">{data.attributes.quataName}</Title>
|
||||
<Text type="secondary">报价单号:{data.id}</Text>
|
||||
</div>
|
||||
|
||||
<div className="bg-gray-50 p-6 rounded-lg mb-8">
|
||||
<Descriptions column={2} bordered>
|
||||
<Descriptions.Item label="客户公司" span={1}>
|
||||
{data.attributes.companyName}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="供应商" span={1}>
|
||||
{data.attributes.supplierName}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="报价日期" span={1}>
|
||||
{new Date(data.created_at).toLocaleDateString('zh-CN')}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="报价有效期" span={1}>
|
||||
{new Date(Date.now() + 30*24*60*60*1000).toLocaleDateString('zh-CN')}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</div>
|
||||
|
||||
<div className="mb-8">
|
||||
<Title level={4} className="mb-4">报价明细</Title>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={data.attributes.items}
|
||||
pagination={false}
|
||||
rowKey={(record, index) => index}
|
||||
className="border rounded-lg"
|
||||
summary={() => (
|
||||
<Table.Summary fixed>
|
||||
<Table.Summary.Row className="bg-gray-50 font-bold">
|
||||
<Table.Summary.Cell index={0} colSpan={4} align="right">
|
||||
总计({data.attributes.currency}):
|
||||
</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={1} align="right">
|
||||
{data.attributes.totalAmount?.toLocaleString('zh-CN', {
|
||||
minimumFractionDigits: 2,
|
||||
style: 'currency',
|
||||
currency: data.attributes.currency
|
||||
})}
|
||||
</Table.Summary.Cell>
|
||||
</Table.Summary.Row>
|
||||
</Table.Summary>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{data.attributes.description && (
|
||||
<div className="bg-gray-50 p-6 rounded-lg">
|
||||
<Title level={4} className="mb-4">补充说明</Title>
|
||||
<Text>{data.attributes.description}</Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-8 pt-8 border-t border-gray-200">
|
||||
<Text type="secondary" className="block mb-2">
|
||||
注意事项:
|
||||
</Text>
|
||||
<ul className="text-gray-500 text-sm">
|
||||
<li>1. 本报价单有效期为30天</li>
|
||||
<li>2. 最终解释权归本公司所有</li>
|
||||
<li>3. 如有疑问请及时联系我们</li>
|
||||
</ul>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default QuotationView;
|
||||
Reference in New Issue
Block a user