import React from 'react'; import Invoice from '../../..'; import { IGoodPassenger } from '../../../InvoiceController'; import { Drawer, Button, Upload, Table, Alert, Tag, Space, Typography, message, Input, Progress, } from 'kts-components-antd-x4'; import { DownloadOutlined, InboxOutlined } from '@ant-design/icons'; import type { UploadProps } from 'kts-components-antd-x4'; // 引入 UploadProps 用于类型提取 import { CheckCircleFilled } from '@ant-design/icons'; import idGenerator from '@/Invoice/tools/idGenerator'; const { Dragger } = Upload; const { Text } = Typography; export default () => { const controller = Invoice.useInvoiceController(); const visible = controller.useMemo(s => s.passengerListState.isVisibleDrawer, []); const dataSource = controller.useMemo(s => s.passengerListState.dataSource, []); const onClose = React.useCallback(() => { controller.pipeline(async s => { s.passengerListState.isVisibleDrawer = false; s.passengerListState.dataSource = []; })(); }, [controller]); const onConfirm = React.useCallback(async () => { if (dataSource.length) { await controller.pipeline(async s => { const data = dataSource.map(item => { return { $index: idGenerator(), ...item } }) s.passengerListState.goodsList = [...s.passengerListState.goodsList, ...data]; s.passengerListState.dataSource = []; })(); await controller.wait() } onClose(); }, [controller, dataSource]); return ( } > ); }; const DrawerBody = () => { const controller = Invoice.useInvoiceController(); const [fileName, setFileName] = React.useState(''); const [status, setStatus] = React.useState<'idle' | 'uploading' | 'done' | 'error'>('idle'); const [percent, setPercent] = React.useState(0); const columns = controller.useMemo(s => s.passengerListState.columns, []); const dataSource = controller.useMemo(s => s.passengerListState.dataSource, []); const pagination = controller.useMemo(s => s.passengerListState.pagination, []); const handleDownloadTemplate = React.useCallback(() => { if (controller.downloadPassengerTpt) { controller.downloadPassengerTpt(); } }, [controller]) // 1. 前置校验:限制文件类型为 .xls, .xlsx const beforeUpload = React.useCallback((file: any) => { const isExcel = file.type === 'application/vnd.ms-excel' || file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || /\.(xls|xlsx)$/.test(file.name); // 兜底判断文件名后缀 if (!isExcel) { message.error('只能上传 .xls 或 .xlsx 格式的Excel文件!'); return Upload.LIST_IGNORE; // 阻止上传 } setFileName(file.name); setStatus('uploading'); setPercent(0); return true; }, []); // 2. 正确类型定义的 customRequest // 直接使用 UploadProps['customRequest'] 可以完美推导出 options 内所有的类型! const customRequest: UploadProps['customRequest'] = async (options) => { const { file, onSuccess, onError, onProgress } = options; if (controller.uploadPassenger) { const res = await controller.uploadPassenger(file as any); if (res) { setStatus('done'); setPercent(100); } } }; // 3. 处理文件选择状态(更新左侧 Input 显示的文件名) const handleChange = (info: any) => { if (info.file.status === 'done') { // 上传成功后可以获取后端返回的信息 console.log('上传成功返回的数据:', info.file.response); } // 更新文件名 if (info.file.name) { setFileName(info.file.name); } }; React.useEffect(() => { controller.getBuyerList && controller.getBuyerList({ pagination: { current: 1 } }); }, [controller]); return (
请先下载模板 《旅客运输服务特定信息-批量导入模板》 ,按照模板填写后上传。 } />
{percent}%
) : status === 'done' ? ( ) : null } />
{dataSource && dataSource.length > 0 &&
文件导入成功,处理旅客运输服务特定信息记录{dataSource.length}条,处理成功{dataSource.length}条。 } />
} ); };