react轻量级新型弹窗类组件,不同以往的传参方式

该代码段展示了在React应用中实现批量导入功能的逻辑,包括使用AntDesign的Modal和Upload组件处理文件上传,调用Axios进行API交互,以及处理导入后的数据验证和错误反馈。功能涵盖了从用户界面到服务端通信的完整流程。

1、引入方式

import BatchImport from '@/components/Modal/batchImport';

<Button type="primary" onClick={batchImport}>

                批量导入

              </Button>

const batchImport = () => {

    BatchImport.show({

      datatype: dataName,

      taskId: taskId,

      projectName: detailsData?.projectName,

      projectCode: projectCode,

      isAlone: 'false',

      sceneType: 2,

      processId: isNopass === 'true' ? processId : '',

      relationFlag: isNopass === 'true' ? true : false,

      onOk(resData) {

        // console.log('【resData】:', resData);

// 这里是弹窗组件method过来的值

      },

      title: '批量导入' + dataName + '数据',

    });

  };

2、import弹窗组件内容

import React, { useState, useEffect, useRef, NamedExoticComponent } from 'react';

import { Modal, Button, Upload, Radio, message, Progress, Col } from 'antd';

import env from '@/utils/env';

import axios from 'axios';

import exportExcel from '@/models/excel';

import publics from '@/utils/public';

import { onloadExcel } from '@/utils/exportExcel';

import Icons from '@/components/SvgIcon';

import _ from 'lodash';

import BatchImportApi from '@/services/batchImport';

import { taskEntityNameFunc, radioOptions } from '@/pages/TaskManage/fastDelivery/components/fastStatusType';

interface Payload {

  onOk?: (l: any[], m: string) => void;

  onCancel?: () => void;

  [others: string]: any;

}

interface IProps extends NamedExoticComponent {

  show: (payload: Payload) => void;

}

const { Dragger } = Upload;

const FastBatchImport: IProps = React.memo((props) => {

  const [visible, setVisible] = useState(false);

  const payloadRef = useRef<Payload>({});

  const [value, setValue] = useState('2');

  const [file, setFile] = useState('');

  const [fileName, setFileName] = useState('');

  const [imgColor, setImgColor] = useState(false);

  const [progressLine, setProgressLine] = useState(1);

  const [percent, setPercent] = useState(0);

  const [fastImportTypes, setFastImportTypes] = useState<any[]>([]);

  const [errorData, setErrorData] = useState<any[]>([]);

  const [importNumber, setImportNumber] = useState('');

  useEffect(() => {

    const lastShow = FastBatchImport.show;

    FastBatchImport.show = (payload: Payload) => {

      sessionStorage.removeItem('batchNumber2');

      setFastImportTypes([]);

      setVisible(true);

      setValue('2');

      payloadRef.current = payload;

    };

    return () => {

      FastBatchImport.show = lastShow;

    };

  }, [visible]);

  const wrapWithClose = (method?: (l: any[]) => void) => async () => {

    let arr: any[] = [];

    method?.(arr);

    setVisible(false);

    setProgressLine(1);

    setImgColor(false);

    setFileName('');

    setPercent(0);

  };

  const onCancel = () => {

    setVisible(false);

    setProgressLine(1);

    setImgColor(false);

    setFileName('');

    setPercent(0);

    sessionStorage.removeItem('batchNumber2');

  };

  const onloadExcelData = () => {

    let name = '';

    name = `批量导入${taskEntityNameFunc(value)}新增模板.xlsx`;

    let url = '';

    url = env.VITE_APP_ROOT + '/authorization/api/template/download?inFileName=' + name;

    onloadExcel({ url, method: 'get', name, params: '', callbacks: () => {} });

  };

  const onChange = (e: any) => {

    setValue(e.target.value);

    setImgColor(false);

    setFileName('');

    setFile('');

    setProgressLine(1);

  };

  function handleImport(e: any) {

    setPercent(0);

    e.stopPropagation();

    // e.nativeEvent.stopImmediatePropagation();

    let str = 0;

    let ds_percent = setInterval(() => {

      if (str < 99) {

        str = str + 1;

        setPercent(str + 1);

      } else {

        setPercent(100);

        clearInterval(ds_percent);

      }

    }, 1500);

    setProgressLine(2);

    const fd = new FormData();

    fd.append('file', file);

    fd.append('type', value);

    fd.append('optType', '1');

    fd.append('flag', true);

    fd.append('sceneType', payloadRef.current.sceneType);

    if (sessionStorage.getItem('batchNumber2')) {

      fd.append('processId', sessionStorage.getItem('batchNumber2') || '');

    } else {

      if (payloadRef.current.processId) {

        fd.append('processId', payloadRef.current.processId);

        fd.append('relationFlag', true);

      }

    }

    fd.append('taskId', payloadRef.current.taskId);

    fd.append('projectName', payloadRef.current.projectName);

    fd.append('projectCode', payloadRef.current.projectCode);

    let configs = {

      headers: { 'Content-Type': 'multipart/form-data', token: localStorage.getItem('token') || '' },

      withCredentials: true,

      onUploadProgress: (progress: any) => {

        console.log(progress);

        console.log(Math.round((progress.loaded / progress.total) * 100));

      },

    };

    axios

      .post(env.VITE_APP_ROOT + '/authorization/api/data/manage/dataManageBatchImportExcel', fd, configs)

      .then((res: any) => {

        clearInterval(ds_percent);

        setPercent(100);

        if (res.data.code === 200) {

          if (res.data.message) {

            let concatarr: any[] = [];

            concatarr = [...new Set(fastImportTypes.concat([value]))].sort();

            setFastImportTypes(concatarr);

            sessionStorage.setItem('batchNumber2', res.data.message.split('-')[0]);

            setImportNumber(res.data.message.split('-')[1] || res.data.message.split('--')[1]);

          }

          setTimeout(() => {

            setProgressLine(3);

          }, 1000);

        } else {

          const arr: any[] = [];

          if (res.data.message.indexOf(';') !== -1) {

            const A = res.data.message.split(';');

            let B = '';

            let E = '';

            A.forEach((item: any, index: any) => {

              if (item !== '') {

                if (item.indexOf('行') !== -1 && A[index - 1] && A[index - 1].indexOf('行') !== -1) {

                  const I = item.indexOf('行') + 1;

                  const T = item.slice(0, I); // 截取当前行数

                  const Q = A[index - 1].slice(0, I); // 截取上一行数

                  if (T === Q) {

                    B = B + item.replace(`${T}`, ',');

                  } else {

                    B = B + ';' + item;

                  }

                } else {

                  B = B + ';' + item;

                }

              }

            });

            B.split(';').forEach((item) => {

              if (item !== '') {

                if (item.indexOf(',请上传页面项目相同的项目名称') !== -1) {

                  const I = item.indexOf('行') + 1;

                  const T = item.slice(0, I); // 截取当前行数

                  const C = item.replace(',请上传页面项目相同的项目名称', '');

                  const D = T + '请上传页面项目相同的项目名称,' + C.replace(`${T}`, '');

                  E = E + ';' + D;

                } else {

                  E = E + ';' + item;

                }

              }

            });

            E.split(';').forEach((item, index) => {

              if (item !== '') {

                arr.push({ number: index, reason: item });

              }

            });

          } else {

            arr.push({ number: 1, reason: res.data.message });

          }

          setErrorData(arr);

          setTimeout(() => {

            setProgressLine(4);

          }, 1000);

        }

      });

  }

  function cancelExcel(e: any) {

    e.stopPropagation();

    e.nativeEvent.stopImmediatePropagation();

    setImgColor(false);

    setFileName('');

    setProgressLine(1);

    setPercent(0);

  }

  function deleteExcel() {

    Modal.confirm({

      title: '提示',

      content: `确定删除excel导入的${taskEntityNameFunc(value)}数据吗?`,

      onOk() {

        let params = {

          type: value,

          processId: sessionStorage.getItem('batchNumber2'),

        };

        BatchImportApi.delTempDate(params).then((res: any) => {

          if (res && res.code === 200) {

            setImgColor(false);

            setFileName('');

            setProgressLine(1);

            setPercent(0);

            let concatArr = fastImportTypes.filter((item: any) => {

              return item !== value;

            });

            setFastImportTypes([...new Set(concatArr)].sort());

            message.success('删除成功');

          } else {

            message.error(res.message);

          }

        });

      },

    });

  }

  const uploadProps = {

    beforeUpload: (res: any) => {

      if (res.size > 10485760 * 2) {

        setImgColor(false);

        message.error('上传文件不能大于20兆!');

        return;

      }

      if (

        ((value === '2' && res.name.includes('导入楼栋')) ||

          (value === '3' && res.name.includes('导入房屋')) ||

          (value === '4' && res.name.includes('导入车位')) ||

          (value === '5' && res.name.includes('导入虚拟楼栋')) ||

          (value === '6' && res.name.includes('导入虚拟房屋'))) &&

        res.name.includes('新增')

      ) {

        if (res) {

          setImgColor(true);

          setFile(res);

          setFileName(res.name);

        } else {

          message.error(`上传excel表格失败,请重新上传`);

          setImgColor(false);

          setFileName('');

        }

      } else {

        message.error(`上传excel表格名称与所选导入数据类型不符,请检查导入数据类型`);

      }

      return false;

    },

  };

  function showError() {

    const heard = {

      number: '序号',

      reason: '导入失败原因',

    };

    exportExcel(heard, errorData, `${taskEntityNameFunc(value)}新增导入失败原因表`);

  }

  function publishData() {

    setPercent(0);

    if (fastImportTypes) {

      publics.openNewTabs(

        `modification/index/${value}/${payloadRef.current.isAlone}?processId=${sessionStorage.getItem(

          'batchNumber2',

        )}&taskId=${payloadRef.current.taskId}&operateType=1&sceneType=${

          payloadRef.current.sceneType

        }&fastTypeNumber=${fastImportTypes?.toString()}`,

      );

    }

  }

  return (

    <Modal

      title={payloadRef.current.title}

      width={750}

      zIndex={100}

      visible={visible}

      onOk={wrapWithClose(payloadRef.current.onOk)}

      onCancel={onCancel}

      forceRender={true}

      destroyOnClose={true}

      maskClosable={false}

      footer=""

    >

      <div className="overflow-y-auto max-h-140">

        {progressLine === 3 && (

          <div className="absolute top-0 left-0 bg-white h-13 px-5 z-index-101 w-full">

            <div className="text-16px leading-13 float-left">批量导入{taskEntityNameFunc(value)}数据</div>

            <div onClick={cancelExcel} className="text-right cursor-pointer float-right pt-4 px-2">

              X

            </div>

          </div>

        )}

        {progressLine !== 3 && (

          <div>

            <div className="flex items-center mb-4 change_radio">

              <Radio.Group

                onChange={onChange}

                options={radioOptions}

                value={value}

                optionType="button"

                buttonStyle="solid"

              />

            </div>

            <div className="flex items-center justify-between h-16 px-4 mb-4 border-blue-300 border-solid rounded bg-blue-50 border-1 template-style">

              <span>下载{taskEntityNameFunc(value)}新增数据导入模板</span>

              <Button onClick={onloadExcelData}>下载模板</Button>

            </div>

            <div className="mb-4 text-xs leading-5 tracking-widest text-red-500">

              温馨提示:请严格按照导入模板要求导入数据。若导入报错,请IT报事,谢谢。

            </div>

          </div>

        )}

        <Dragger {...uploadProps} className="relative z-index-1" showUploadList={false} accept=".xls, .xlsx">

          <div className="overflow-hidden h-60" />

          <div className="absolute top-0 bottom-0 left-0 right-0 pt-0 auto z-index-900 cursor-text">

            {progressLine === 1 ? (

              <div>

                <div className="relative overflow-hidden">

                  {imgColor ? (

                    <div

                      className="pt-8 overflow-hidden h-68"

                      onClick={(e: any) => {

                        e.stopPropagation();

                        e.nativeEvent.stopImmediatePropagation();

                      }}

                    >

                      <Icons className="mx-auto mb-2 mt-7" type="dragGreen" size="70px" />

                      <div className="absolute text-xs cursor-pointer top-12 right-77" onClick={cancelExcel}>

                        X

                      </div>

                      <div className="mb-4 text-xs leading-4 text-gray-300">{fileName}</div>

                      <Button type="primary" onClick={handleImport}>

                        导入数据

                      </Button>

                    </div>

                  ) : (

                    <div className="pt-8 overflow-hidden h-68">

                      <div

                        className="absolute top-0 w-full h-45 z-index-999"

                        onClick={(e: any) => {

                          e.stopPropagation();

                          e.nativeEvent.stopImmediatePropagation();

                        }}

                      />

                      <div

                        className="absolute w-full top-53 h-15 z-index-999"

                        onClick={(e: any) => {

                          e.stopPropagation();

                          e.nativeEvent.stopImmediatePropagation();

                        }}

                      />

                      <div

                        className="absolute left-0 h-8 top-45 w-76 z-index-999"

                        onClick={(e: any) => {

                          e.stopPropagation();

                          e.nativeEvent.stopImmediatePropagation();

                        }}

                      />

                      <div

                        className="absolute right-0 h-8 top-45 w-76 z-index-999"

                        onClick={(e: any) => {

                          e.stopPropagation();

                          e.nativeEvent.stopImmediatePropagation();

                        }}

                      />

                      <Icons className="mx-auto mb-2 mt-7" type="drag" size="60px" />

                      <div className="mx-auto mb-4 text-center">

                        <div className="h-4 text-xs leading-4 text-gray-300">将文件拖拽至此区域</div>

                        <div className="h-4 mb-5 text-xs leading-4 text-gray-300">支持xls、xlsx格式</div>

                        <Button className="mb-3">上传文件</Button>

                      </div>

                    </div>

                  )}

                </div>

              </div>

            ) : progressLine === 2 ? (

              <div

                className="overflow-hidden h-68"

                onClick={(e: any) => {

                  e.stopPropagation();

                  e.nativeEvent.stopImmediatePropagation();

                }}

              >

                <Progress percent={percent} className="!px-10 !pt-26" />

                <div className="flex justify-center my-4 text-gray-400">

                  导入{taskEntityNameFunc(value)}新增的数据中,请稍后...

                </div>

              </div>

            ) : progressLine === 3 ? (

              <div

                className="overflow-hidden h-68"

                onClick={(e: any) => {

                  e.stopPropagation();

                  e.nativeEvent.stopImmediatePropagation();

                }}

              >

                <div className="h-30">

                  <Icons className="mx-auto mb-2 mt-7" type="dragGreen" size="70px" />

                  {importNumber && (

                    <div className="absolute text-xs cursor-pointer top-12 right-77" onClick={deleteExcel}>

                      X

                    </div>

                  )}

                  <div className="mb-5 text-xs leading-4 text-gray-300">{fileName}</div>

                </div>

                <div className="mt-4 mb-2 text-2xl">导入成功</div>

                <div className="mb-4 text-gray-400">

                  成功导入{importNumber}条{taskEntityNameFunc(value)}新增数据,请尽快发布数据

                </div>

                <div>

                  <Button onClick={cancelExcel} className="mr-2">

                    重新导入

                  </Button>

                  <Button type="primary" onClick={publishData}>

                    发布数据

                  </Button>

                </div>

              </div>

            ) : (

              <div

                className="overflow-hidden h-68"

                onClick={(e: any) => {

                  e.stopPropagation();

                  e.nativeEvent.stopImmediatePropagation();

                }}

              >

                <Icons className="mx-auto mb-2 mt-7" type="importFail" size="80px" />

                <div className="mt-5 mb-2 text-2xl">导入失败</div>

                <div className="mb-4 text-gray-400">你可以下载查看失败数据,修改后重新导入</div>

                <div>

                  <Button type="primary" onClick={showError} className="mr-2">

                    点击查看导入失败原因

                  </Button>

                  <Button onClick={cancelExcel}>重新导入</Button>

                </div>

              </div>

            )}

          </div>

        </Dragger>

      </div>

    </Modal>

  );

}) as any;

FastBatchImport.show = (payload: Payload) => console.log('BatchImport is not mounted.');

export default FastBatchImport;

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值