343 lines
9.3 KiB
TypeScript
343 lines
9.3 KiB
TypeScript
import { DownloadOutlined } from '@ant-design/icons';
|
|
import { t } from '@lingui/macro';
|
|
import {
|
|
Button,
|
|
Space,
|
|
Table,
|
|
TableColumnsType,
|
|
Tooltip,
|
|
Typography,
|
|
} from 'antd';
|
|
import { SbtPageHeader } from 'components/page-header';
|
|
import { Dayjs } from 'dayjs';
|
|
import { ReportDetailList, ReportItemDetail } from 'models';
|
|
import { useReportDetailList } from 'queries/report';
|
|
import { useState } from 'react';
|
|
import { useParams } from 'react-router-dom';
|
|
import { downloadReport } from 'request/report';
|
|
import styled from 'styled-components';
|
|
|
|
export interface ReportFormValues {
|
|
dateRange: [Dayjs, Dayjs];
|
|
includeTest: string;
|
|
}
|
|
|
|
const ReportContainer = styled.div`
|
|
margin-bottom: 16px;
|
|
`;
|
|
|
|
const HeaderContainer = styled(Space)`
|
|
display: flex;
|
|
flex-direction: row;\
|
|
gap: 16px;
|
|
margin-bottom: 16px;
|
|
`;
|
|
|
|
const ReportInformationContainer = styled.div`
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
padding: 16px;
|
|
border-radius: 10px;
|
|
width: 100%;
|
|
height: 400px;
|
|
`;
|
|
|
|
const columns: TableColumnsType<ReportItemDetail> = [
|
|
{
|
|
title: 'Request ID',
|
|
dataIndex: 'Request ID',
|
|
key: 'Request ID',
|
|
width: 100,
|
|
render: (value, record, index) => {
|
|
const shortenedValue =
|
|
String(value).length > 20
|
|
? String(value).substring(0, 20) + '...'
|
|
: String(value);
|
|
return <Tooltip title={value}>{shortenedValue}</Tooltip>;
|
|
},
|
|
},
|
|
{
|
|
title: 'Redemption Number',
|
|
dataIndex: 'Redemption Number',
|
|
key: 'Redemption Number',
|
|
},
|
|
{
|
|
title: 'Image type',
|
|
dataIndex: 'Image type',
|
|
key: 'Image type',
|
|
},
|
|
{
|
|
title: 'IMEI_user submitted',
|
|
dataIndex: 'IMEI_user submitted',
|
|
key: 'IMEI_user submitted',
|
|
},
|
|
{
|
|
title: 'IMEI_OCR retrieved',
|
|
dataIndex: 'IMEI_OCR retrieved',
|
|
key: 'IMEI_OCR retrieved',
|
|
},
|
|
|
|
{
|
|
title: 'IMEI1 Accuracy',
|
|
dataIndex: 'IMEI1 Accuracy',
|
|
key: 'IMEI1 Accuracy',
|
|
render: (_, record) => {
|
|
const isAbnormal = Number(record['IMEI1 Accuracy']) < 25;
|
|
return (
|
|
<span style={{ color: isAbnormal ? 'red' : '' }}>
|
|
{record['IMEI1 Accuracy'] &&
|
|
Number(record['IMEI1 Accuracy']).toFixed(2)}
|
|
</span>
|
|
);
|
|
},
|
|
},
|
|
|
|
{
|
|
title: 'Invoice_Purchase Date_Consumer',
|
|
dataIndex: 'Invoice_Purchase Date_Consumer',
|
|
key: 'Invoice_Purchase Date_Consumer',
|
|
},
|
|
{
|
|
title: 'Invoice_Purchase Date_OCR',
|
|
dataIndex: 'Invoice_Purchase Date_OCR',
|
|
key: 'Invoice_Purchase Date_OCR',
|
|
},
|
|
{
|
|
title: 'Invoice_Purchase Date Accuracy',
|
|
dataIndex: 'Invoice_Purchase Date Accuracy',
|
|
key: 'Invoice_Purchase Date Accuracy',
|
|
render: (_, record) => {
|
|
const isAbnormal = Number(record['Invoice_Purchase Date Accuracy']) < 25;
|
|
return (
|
|
<span style={{ color: isAbnormal ? 'red' : '' }}>
|
|
{record['Invoice_Purchase Date Accuracy'] &&
|
|
Number(record['Invoice_Purchase Date Accuracy']).toFixed(2)}
|
|
</span>
|
|
);
|
|
},
|
|
},
|
|
|
|
{
|
|
title: 'Invoice_Retailer_Consumer',
|
|
dataIndex: 'Invoice_Retailer_Consumer',
|
|
key: 'Invoice_Retailer_Consumer',
|
|
},
|
|
{
|
|
title: 'Invoice_Retailer_OCR',
|
|
dataIndex: 'Invoice_Retailer_OCR',
|
|
key: 'Invoice_Retailer_OCR',
|
|
},
|
|
{
|
|
title: 'Invoice_Retailer Accuracy',
|
|
dataIndex: 'Invoice_Retailer Accuracy',
|
|
key: 'Invoice_Retailer Accuracy',
|
|
render: (_, record) => {
|
|
const isAbnormal = Number(record['Invoice_Retailer Accuracy']) < 25;
|
|
return (
|
|
<span style={{ color: isAbnormal ? 'red' : '' }}>
|
|
{record['Invoice_Retailer Accuracy'] &&
|
|
Number(record['Invoice_Retailer Accuracy']).toFixed(2)}
|
|
</span>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Retailer_Revised Accuracy',
|
|
dataIndex: 'Retailer_Revised Accuracy',
|
|
key: 'Retailer_Revised Accuracy',
|
|
render: (_, record) => {
|
|
const isAbnormal = Number(record['Retailer_Revised Accuracy']) < 25;
|
|
return (
|
|
<span style={{ color: isAbnormal ? 'red' : '' }}>
|
|
{record['Retailer_Revised Accuracy'] &&
|
|
Number(record['Retailer_Revised Accuracy']).toFixed(2)}
|
|
</span>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'OCR Image Accuracy',
|
|
dataIndex: 'OCR Image Accuracy',
|
|
key: 'OCR Image Accuracy',
|
|
render: (_, record) => {
|
|
const isAbnormal = Number(record['OCR Image Accuracy']) < 25;
|
|
return (
|
|
<span style={{ color: isAbnormal ? 'red' : '' }}>
|
|
{record['OCR Image Accuracy'] &&
|
|
Number(record['OCR Image Accuracy']).toFixed(2)}
|
|
</span>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'OCR Image Speed (seconds)',
|
|
dataIndex: 'OCR Image Speed (seconds)',
|
|
key: 'OCR Image Speed (seconds)',
|
|
render: (_, record) => {
|
|
const isAbnormal = Number(record['OCR Image Speed (seconds)']) > 2;
|
|
return (
|
|
<span style={{ color: isAbnormal ? 'red' : '' }}>
|
|
{record['OCR Image Speed (seconds)'] &&
|
|
Number(record['OCR Image Speed (seconds)']).toFixed(2)}
|
|
</span>
|
|
);
|
|
},
|
|
sorter: (a, b) =>
|
|
a['OCR Image Speed (seconds)'] - b['OCR Image Speed (seconds)'],
|
|
},
|
|
{
|
|
title: 'Reviewed',
|
|
dataIndex: 'Reviewed',
|
|
key: 'Reviewed',
|
|
},
|
|
{
|
|
title: 'Bad Image Reasons',
|
|
dataIndex: 'Bad Image Reasons',
|
|
key: 'Bad Image Reasons',
|
|
},
|
|
{
|
|
title: 'Countermeasures',
|
|
dataIndex: 'Countermeasures',
|
|
key: 'Countermeasures',
|
|
},
|
|
{
|
|
title: 'IMEI_Revised Accuracy',
|
|
dataIndex: 'IMEI_Revised Accuracy',
|
|
key: 'IMEI_Revised Accuracy',
|
|
render: (_, record) => {
|
|
const isAbnormal = Number(record['IMEI_Revised Accuracy']) * 100 < 25;
|
|
return (
|
|
<span style={{ color: isAbnormal ? 'red' : '' }}>
|
|
{record['IMEI_Revised Accuracy'] &&
|
|
(Number(record['IMEI_Revised Accuracy']) * 100).toFixed(2)}
|
|
</span>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Purchase Date_Revised Accuracy',
|
|
dataIndex: 'Purchase Date_Revised Accuracy',
|
|
key: 'Purchase Date_Revised Accuracy',
|
|
render: (_, record) => {
|
|
const isAbnormal =
|
|
Number(record['Purchase Date_Revised Accuracy']) * 100 < 25;
|
|
return (
|
|
<span style={{ color: isAbnormal ? 'red' : '' }}>
|
|
{record['Purchase Date_Revised Accuracy'] &&
|
|
(Number(record['Purchase Date_Revised Accuracy']) * 100).toFixed(2)}
|
|
</span>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Retailer_Revised Accuracy',
|
|
dataIndex: 'Retailer_Revised Accuracy',
|
|
key: 'Retailer_Revised Accuracy',
|
|
render: (_, record) => {
|
|
const isAbnormal = Number(record['Retailer_Revised Accuracy']) * 100 < 25;
|
|
return (
|
|
<span style={{ color: isAbnormal ? 'red' : '' }}>
|
|
{record['Retailer_Revised Accuracy'] &&
|
|
(Number(record['Retailer_Revised Accuracy']) * 100).toFixed(2)}
|
|
</span>
|
|
);
|
|
},
|
|
},
|
|
];
|
|
|
|
const ReportDetail = () => {
|
|
const [pagination, setPagination] = useState({
|
|
page: 1,
|
|
page_size: 10,
|
|
});
|
|
const { id } = useParams<{ id: string }>();
|
|
|
|
const { isLoading, data } = useReportDetailList({
|
|
report_id: id,
|
|
page: pagination.page,
|
|
});
|
|
const report_data = data as ReportDetailList;
|
|
const handleDownloadReport = async () => {
|
|
const reportFile = await downloadReport(id);
|
|
const anchorElement = document.createElement('a');
|
|
anchorElement.href = URL.createObjectURL(reportFile);
|
|
anchorElement.download = `${id}.xlsx`; // Set the desired new filename
|
|
|
|
document.body.appendChild(anchorElement);
|
|
anchorElement.click();
|
|
|
|
// Clean up
|
|
document.body.removeChild(anchorElement);
|
|
URL.revokeObjectURL(anchorElement.href);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<SbtPageHeader
|
|
title={
|
|
<Tooltip
|
|
title={id}
|
|
style={{ cursor: 'pointer' }}
|
|
>{t`Report ${id.slice(0, 16)}...`}</Tooltip>
|
|
}
|
|
extra={
|
|
<Button
|
|
size='large'
|
|
type='primary'
|
|
icon={<DownloadOutlined />}
|
|
onClick={handleDownloadReport}
|
|
>
|
|
{t`Download Report`}
|
|
</Button>
|
|
}
|
|
/>
|
|
<HeaderContainer>
|
|
<Typography.Title level={5}>
|
|
Subsidiary:{' '}
|
|
<span style={{ fontWeight: '400' }}>
|
|
{report_data?.metadata?.subsidiary}
|
|
</span>
|
|
</Typography.Title>
|
|
|
|
<Typography.Title level={5}>
|
|
Start date:{' '}
|
|
<span style={{ fontWeight: '400' }}>
|
|
{report_data?.metadata?.start_at}
|
|
</span>
|
|
</Typography.Title>
|
|
<Typography.Title level={5}>
|
|
End date:{' '}
|
|
<span style={{ fontWeight: '400' }}>
|
|
{report_data?.metadata?.end_at}
|
|
</span>
|
|
</Typography.Title>
|
|
</HeaderContainer>
|
|
<ReportContainer>
|
|
<Table
|
|
loading={isLoading}
|
|
columns={columns}
|
|
dataSource={report_data?.report_detail}
|
|
bordered
|
|
size='small'
|
|
pagination={{
|
|
current: pagination.page,
|
|
pageSize: pagination.page_size,
|
|
total: report_data?.page.count,
|
|
showTotal: (total, range) =>
|
|
`${range[0]}-${range[1]} of ${total} items`,
|
|
onChange: (page, pageSize) => {
|
|
setPagination({
|
|
page,
|
|
page_size: pageSize || 10,
|
|
});
|
|
},
|
|
showSizeChanger: false,
|
|
}}
|
|
scroll={{ x: 2000 }}
|
|
/>
|
|
</ReportContainer>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default ReportDetail;
|