antd upload组件上传表格文件(React jsx TS写法),modal弹窗重新打开时强制销毁历史导入文件

根据需求完成下图功能:

  限制只能上传表格文件,本地上传显示进度条,点击确认上传表格数据保存到云端,并关闭弹窗刷新table。

 

// 上传弹窗渲染
const uploadProps: UploadProps = {
  name: 'file',
  action: `${API_HOST}/monitor/monitorAirflowAlarmConfig/uploadFile`,
  // antd 上传组件上传文件成功直接调用上传接口,不符合本次需求所以注释,通过Modal确认按钮去触发
  // headers: {
  //   // 'Content-Type': 'multipart/form-data',
  //   'page-path': '/monitor/scheduling/warningConfig',
  //   'token-id': TOKEN,
  //   'menu-id': '4086dcdd82d8417e9a0294a6454d1894'
  // },
  withCredentials: true,
  maxCount: 1, // 文件最大上传个数
  // 限制类型
  accept: '.csv,.xls,.xlsx, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel', // 限制只能上传表格文件
  beforeUpload: file => {
    const isPNG = ['.csv', '.xls', '.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-excel'].includes(file.type)
    if (!isPNG) {
      message.error(`文件格式不正确!`);
    } else {
      // console.log('beforeUpload', file);
      //转化为formData格式
      const formData = new FormData();
      formData.append('file', file);
      setFormDataParams(formData)
    }
    return isPNG || Upload.LIST_IGNORE;
  },
  onChange: info => {
    if (info.file.status !== 'uploading') {
      console.log('onChange', info, info.fileList);
    }
    if (info.file.status === 'done') {
      setReqUpload(true)
      message.success(`本地导入文件成功,点击确认上传到数据库`);
    } else if (info.file.status === 'error') {
      setReqUpload(false)
      message.error(`本地导入文件失败`);
    } else if (info.file.status === 'removed') {
      setReqUpload(false)
    }
  },
  progress: { // 文件上传展示的上传进度条样式
    strokeColor: {
      '0%': '#108ee9',
      '100%': '#87d068',
    },
    strokeWidth: 3,
    format: percent => percent && `${parseFloat(percent.toFixed(2))}%`,
  },
};

// 上传组件渲染
const basicNodeUpload = (
    <>
      <Upload {...uploadProps}>
        <Button icon={<CloudUploadOutlined />}>上传文件</Button>
      </Upload>
      <div className={styles.uploadRemark}>支持扩展名:.xls .xlsx</div>
    </>
  )

//导入Modal确定
const handleUploadOk = async () => {
  if (!reqUpload) {
    message.error('未导入文件!')
    return
  }
  setLoading(true);
  setRefresh(false)
  try {
    await request.post(`${API_HOST}/monitor/monitorAirflowAlarmConfig/uploadFile`, {
      data: formDataParams,
      requestType: 'form',  // 请求报文类型为表单
      headers: {
        'page-path': '/monitor/scheduling/warningConfig',
        'token-id': TOKEN,
        'menu-id': '4086dcdd82d8417e9a0294a6454d1894'
      },
    }).then((res: any) => {
      setLoading(false);
      if (res.code === '1') {
        message.success(res?.msg || '文件上传成功');
        setRefresh(true)
        Modal.destroyAll(); // 销毁弹窗,这种写法好像不生效不赞成使用
        handleCancelModal()
      } else {
        message.error(res?.msg || '文件上传失败');
      }
    })
  } catch (errorInfo) {
  }
}

// 弹窗
< Modal
  title="文件导入"
  destroyOnClose // 弹窗关闭时销毁组件,解决再次打开时组件内存在历史上传文件!!!
  visible={openUploadModal}
  className={styles.uploadModal}
  onOk={handleUploadOk}
  onCancel={handleCancelModal}
  footer={[
    <Button key="back" onClick={handleCancelModal}>
      取消
    </Button>,
    <Button key="submit" type="primary" loading={loading} onClick={handleUploadOk}>
      确认
    </Button>,
  ]}
>
  {basicNodeUpload}
</Modal>

总结:

  上述方案不完善存在缺陷,成熟方案应该是这样:上传文件触发应该将文件传给后端,后端接收缓存但并不直接存入库中而是返回该文件生成id标识(标识后端生成)给前端。前端拿到标识在此条件下,用户操作确认按钮前端本次仅将id标识传给后端,后端接收后才将对应文件数据保存下来。以上为个人思考,供大家学习讨论。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现 React Antd 弹窗的拖动并防止超出屏幕,可以使用 React DnD(React Drag and Drop)和 AntdModal 组件结合使用。具体步骤如下: 1. 安装 React DnD:`npm install react-dnd react-dnd-html5-backend` 2. 创建一个可拖拽的组件,例如 `DraggableModal` 组件,并使用 `DragSource` 高阶组件将其包装为可拖拽组件。 ```jsx import { DragSource } from 'react-dnd'; const modalSource = { beginDrag(props) { return { id: props.id, left: props.left, top: props.top, }; }, }; function collect(connect, monitor) { return { connectDragSource: connect.dragSource(), isDragging: monitor.isDragging(), }; } class DraggableModal extends React.Component { render() { const { connectDragSource, isDragging, children } = this.props; const opacity = isDragging ? 0.5 : 1; return connectDragSource( <div style={{ opacity }}> {children} </div> ); } } export default DragSource('modal', modalSource, collect)(DraggableModal); ``` 3. 在 `Modal` 组件中使用 `DraggableModal` 组件,并在 `onMouseMove` 事件中更新 `Modal` 组件的位置,同限制其移动的范围。 ```jsx import DraggableModal from './DraggableModal'; class App extends React.Component { constructor(props) { super(props); this.state = { left: 0, top: 0, }; } handleMouseMove = (e) => { const { left, top } = this.state; const { clientWidth, clientHeight } = document.documentElement; const modalWidth = 520; const modalHeight = 400; const mouseX = e.clientX; const mouseY = e.clientY; let newLeft = mouseX - this.offsetX; let newTop = mouseY - this.offsetY; if (newLeft < 0) { newLeft = 0; } else if (newLeft + modalWidth > clientWidth) { newLeft = clientWidth - modalWidth; } if (newTop < 0) { newTop = 0; } else if (newTop + modalHeight > clientHeight) { newTop = clientHeight - modalHeight; } this.setState({ left: newLeft, top: newTop, }); } handleMouseDown = (e) => { this.offsetX = e.clientX - this.state.left; this.offsetY = e.clientY - this.state.top; document.addEventListener('mousemove', this.handleMouseMove); } handleMouseUp = () => { document.removeEventListener('mousemove', this.handleMouseMove); } render() { const { left, top } = this.state; return ( <DraggableModal left={left} top={top}> <Modal title="Draggable Modal" style={{ top, left }} visible={true} onCancel={this.handleCancel} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} > <p>Content of the modal</p> </Modal> </DraggableModal> ); } } ``` 在上面的代码中,我们通过 `onMouseDown` 和 `onMouseUp` 事件监听鼠标拖动事件,并在 `onMouseMove` 事件中更新 `Modal` 组件的位置,同限制其移动的范围不超过屏幕。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值