index.tsx 7.77 KB
import React, { useEffect, useImperativeHandle, useState } from 'react';
import { message, Modal, notification, Radio, Select } from 'antd';
import './index.less';
import ExportTree from '@/pages/app-view/list/components/export/export-tree';
import { CheckCircleFilled, ExclamationCircleFilled } from '@ant-design/icons';
import {
  closeExport,
  exportDataNew,
  exportOption,
  exportProgress,
  exportRecordLast,
} from '@/pages/app-view/list/service';
import { handleDownload } from '@/libs/htmlHandle';

const { Option } = Select;

interface ExportDialogProps {
  dRef?: any;
  appCode: string;
  funCode: string;
  viewCode: string;
  exportQueryParams: any;
  parentExportProgressData: any;
}
const plainOptions = [
  { label: 'Excel文件', value: 'excel' },
  // { label: 'Word文件', value: 'word' },
  // { label: 'PDF文件', value: 'pdf' },
];

const ExportDialog: React.FC<ExportDialogProps> = (props) => {
  const {
    appCode,
    funCode,
    viewCode,
    exportQueryParams,
    parentExportProgressData,
  } = props;

  const [visible, setVisible] = useState(false);
  const [status, setStatus] = useState<string>('excel');
  const [exportData, setExportData] = useState<any>([]);
  const [exportLastData, setExportLastData] = useState<any>([]);
  const [selectKeys, setSelectKeys] = useState<any>([]);
  // const [exportProgressData, setProgressData] = useState<any>();
  const [loading, setLoading] = useState<boolean>(false);

  const getExportData = async () => {
    const option = await exportOption(appCode, funCode, viewCode);
    setExportData(option || []);
    const last = await exportRecordLast(appCode, funCode, viewCode);
    setExportLastData(last?.configJson?.fields || []);
  };

  useEffect(() => {
    if (visible) {
      getExportData();
    } else {
      setExportData([]);
      setExportLastData([]);
    }
  }, [visible]);

  useImperativeHandle(props.dRef, () => ({
    // 暴露给父组件
    open: () => {
      setVisible(true);
    },
    close: () => {
      setVisible(false);
    },
  }));
  const changeStatus = (value: string) => {
    setStatus(value);
  };
  const handleChange = () => {};
  const closeNotification = (_status: number, taskId: string) => {
    if (_status !== 2) {
      closeExport(appCode, funCode, viewCode, { taskId }).then(() => {
        // setProgressData(null);
      });
    }
  };
  const openNotification = (
    success: number,
    taskId: string,
    url: string,
    name: string,
  ) => {
    notification.warn({
      key: 'qx-export-notification',
      className: 'qx-export-notification',
      message:
        success === 1
          ? '导出文件准备完成'
          : success === 2
          ? '导出文件准备中'
          : '导出文件失败',
      description:
        success === 1 ? (
          <div>
            【{name || document.title}】导出文件准备完成,请
            <span
              onClick={() =>
                handleDownload(url, `${name || document.title}-数据导出.xlsx`)
              }
            >
              立即下载
            </span>
          </div>
        ) : success === 2 ? (
          <div>
            正在导出【{name || document.title}
            】文件,可能需要一段时间,您可以操作其他内容,导出后会立即通知您
          </div>
        ) : (
          <div>【{name || document.title}】文件导出失败,请重新导出</div>
        ),
      placement: 'bottomLeft',
      duration: null,
      icon:
        success === 1 ? (
          <CheckCircleFilled style={{ color: '#52C41A' }} />
        ) : success === 2 ? (
          <ExclamationCircleFilled style={{ color: '#FAAD14' }} />
        ) : (
          <ExclamationCircleFilled style={{ color: 'red' }} />
        ),
      onClose: () => closeNotification(success, taskId),
    });
  };
  const exportSelectData = (taskType: string) => {
    exportProgress(appCode, funCode, viewCode, taskType).then((res) => {
      // setProgressData(res || null);
      if (res?.status === 'SUCCESS') {
        openNotification(1, res?.taskId, res?.downloadUrl, res?.name);
      } else if (res?.status === 'PROCESSING') {
        setTimeout(() => {
          exportSelectData('EXPORT');
        }, 4000);
      } else if (res?.status === 'FAIL') {
        openNotification(3, res?.taskId, '', res?.name);
      }
    });
  };
  useEffect(() => {
    if (!(location.href.indexOf('/dataset?') > -1)) {
      exportSelectData('EXPORT');
    }
  }, []);
  useEffect(() => {
    if (!parentExportProgressData) {
      return;
    }
    if (!parentExportProgressData.downloadUrl) {
      openNotification(2, '', '', parentExportProgressData.name);
    } else {
      openNotification(
        1,
        parentExportProgressData.taskId,
        parentExportProgressData.downloadUrl,
        parentExportProgressData.name,
      );
    }
  }, [parentExportProgressData]);

  const onOk = () => {
    if (!selectKeys.length) {
      message.warn('导出字段不能为空');
      return;
    }
    setLoading(true);
    // setProgressData({
    //   percent: 0,
    //   status: 'PROCESSING',
    // });
    const data = {
      ...exportQueryParams,
      exportRecord: {
        templateId: 'default',
        exportType: status,
        configJson: {
          fields: selectKeys,
        },
      },
    };
    exportDataNew(appCode, funCode, viewCode, JSON.stringify(data)).then(
      (res: any) => {
        openNotification(2, '', '', res?.name || '');
        setVisible(false);
        setLoading(false);
        setTimeout(() => {
          exportSelectData('EXPORT');
        }, 4000);
      },
    );
  };

  // const [intervalName, setIntervalName] = useState<any>();
  // useEffect(() => {
  //   if (exportProgressData) {
  //     if (exportProgressData.status === 'PROCESSING' && !intervalName) {
  //       setIntervalName(setInterval(() => exportSelectData('EXPORT'), 1000 * 10));
  //       return;
  //     }
  //     if (exportProgressData.status !== 'PROCESSING' && intervalName) {
  //       clearInterval(intervalName);
  //       return;
  //     }
  //   }
  //
  //   return () => {
  //     if (intervalName) {
  //       setTimeout(() => {
  //         clearInterval(intervalName);
  //       }, 1000 * 60 * 10);
  //     }
  //   };
  // }, [exportProgressData]);
  const changeExportData = (val: any) => {
    setSelectKeys(val || []);
  };

  return (
    <Modal
      title="导出数据"
      width={'468px'}
      visible={visible}
      confirmLoading={loading}
      onCancel={() => {
        setVisible(false);
      }}
      destroyOnClose
      maskClosable={false}
      wrapClassName={'qx-export-modal'}
      onOk={onOk}
    >
      <div className={'qx-export-modal-title'}>1、请选择导出方式 </div>
      <div className={'qx-export-modal-status'}>
        导出方式:
        <Radio.Group
          options={plainOptions}
          onChange={(e) => changeStatus(e.target.value)}
          value={status}
        />
      </div>
      {status !== 'excel' && (
        <>
          <div className={'qx-export-modal-title'}>2、请选择导出模板</div>
          <div className={'qx-export-modal-status'}>
            <Select
              defaultValue="lucy"
              style={{ width: 224 }}
              onChange={handleChange}
            >
              <Option value="jack">Jack</Option>
              <Option value="lucy">Lucy</Option>
            </Select>
          </div>
        </>
      )}
      {status === 'excel' && (
        <>
          <div className={'qx-export-modal-title'}>2、请选择导出字段</div>
          <div className={'qx-export-modal-tree'}>
            <ExportTree
              exportData={exportData}
              exportLastData={exportLastData}
              changeExportData={changeExportData}
            />
          </div>
        </>
      )}
    </Modal>
  );
};

export default ExportDialog;