import React, { Suspense } from 'react';
import { FormItem, FormControlProps, FormBaseControl } from '../../../Form/Item';
// import 'cropperjs/dist/cropper.css';
const Cropper = React.lazy(() => import('react-cropper'));
import DropZone from 'react-dropzone';
import { FileRejection } from 'react-dropzone';
import 'blueimp-canvastoblob';
import find from 'lodash/find';
import {
  guid,
  isEmpty,
  isMobile,
} from '../../../../utils/helper';
import { Icon } from '../../../../components/icons';
import Button from '../../../../components/Button';
import { Button as Buttons, message } from 'antd';
import accepts from 'attr-accept';
import { getNameFromUrl } from '../../../Form/InputFile';
import ImageComponent, { ImageThumbProps } from '../../../Image';
import { TranslateFn } from '../../../../locale';
import { dataMapping } from '../../../../utils/tpl-builtin';
import {
  SchemaApi,
  SchemaClassName,
  SchemaTokenizeableString,
  SchemaUrlPath
} from '../../../../Schema';
import { filter } from '../../../../utils/tpl';
import isPlainObject from 'lodash/isPlainObject';
import merge from 'lodash/merge';
import { isPdf, isImg, getMediaIcon, isCon, downloadFile, downFile, byteSize } from '../../utils/utils'
import SparkMD5 from 'spark-md5';
import Axios from 'axios';
import { compress } from 'image-conversion';
import { CloseCircleOutlined, CloudDownloadOutlined, DownloadOutlined, FolderTwoTone, InstagramOutlined } from '@ant-design/icons';
import Popover from 'antd/lib/popover';
import CellPopover from '../../Table/LionCellImg/CellPopover';
import { Modal } from 'antd';
import { getLodop } from '../../../../utils/print/LodopFuncs';
import { ModalPrint } from '../../LabelPrint';
import { ImgInfo, Shell } from '../../../../utils/shell';
import { Progress } from 'antd';
import PopUp from '../../../../components/PopUp';
import { MoveUpload, MoveUploadimg } from '../../../../components/Lion/MoveUpload';
import Input from 'antd/lib/input/Input';
import { Renderer } from '../../../../factory';
import { observer } from 'mobx-react';
import { EventEnum, EventSub } from '../../../../utils/sub';
/** 
 * Image 图片上传控件
 * 文档：https://baidu.gitee.io/amis/docs/components/form/image
 */

// 图片缓存
const ImgCache: any = {}

// 注册缓存清理事件
EventSub.on(EventEnum.ClearMappingAcahe, (InstanceName) => {
  if (!InstanceName) return
  delete ImgCache[InstanceName]
})
export interface ImageControlSchema extends FormBaseControl {
  /**
   * 指定为图片上传控件
   */
  type: 'input-image';

  /**
   * 默认展示图片的链接
   */
  src?: SchemaUrlPath;

  /**
   * 默认展示图片的类名
   */
  imageClassName?: string;

  /**
   * 配置接收的图片类型
   *
   * 建议直接填写文件后缀
   * 如：.txt,.csv
   *
   * 多个类型用逗号隔开。
   */
  accept?: string;

  /**
   * 默认都是通过用户选择图片后上传返回图片地址，如果开启此选项，则可以允许用户图片地址。
   */
  allowInput?: boolean;

  /**
   * 是否自动开始上传
   */
  autoUpload?: boolean;

  /**
   * 选择图片按钮的 CSS 类名
   */
  btnClassName?: SchemaClassName;

  /**
   * 上传按钮的 CSS 类名
   */
  btnUploadClassName?: SchemaClassName;

  /**
   * @deprecated
   */
  compress?: boolean;

  /**
   * @deprecated
   */
  compressOptions?: {
    maxHeight?: number;
    maxWidth?: number;
  };

  crop?:
  | boolean
  | {
    /**
     * 默认 `1` 即 `1:1`
     *
     * 留空将不限制
     */
    aspectRatio?: number;

    guides?: boolean;
    dragMode?: string;
    viewMode?: number;
    rotatable?: boolean;
    scalable?: boolean;
  };

  /**
   * 裁剪后的图片类型
   */
  cropFormat?: string;

  /**
   * 裁剪后的质量
   */
  cropQuality?: number;

  /**
   * 是否允许二次裁剪。
   */
  reCropable?: boolean;

  /**
   * 是否隐藏上传按钮
   */
  hideUploadButton?: boolean;

  /**
   * 限制图片大小，超出不让上传。
   */
  limit?: {
    /**
     * 比率不对时的提示文字
     */
    aspectRatioLabel?: string;
    /**
     * 限制比率
     */
    aspectRatio?: number;

    /**
     * 限制图片高度
     */
    height?: number;

    /**
     *  限制图片宽度
     */
    width?: number;

    /**
     * 限制图片最大高度
     */
    maxHeight?: number;

    /**
     * 限制图片最大宽度
     */
    maxWidth?: number;

    /**
     * 限制图片最小高度
     */
    minHeight?: number;

    /**
     *  限制图片最小宽度
     */
    minWidth?: number;
  };

  /**
   * 最多的个数
   */
  maxLength?: number;

  /**
   * 默认10MB，当设置后，文件大小大于此值将不允许上传。
   */
  maxSize?: number;

  /**
   * 默认 `/api/upload` 如果想自己存储，请设置此选项。
   */
  receiver?: SchemaApi;

  /**
   * 默认为 false, 开启后，允许用户输入压缩选项。
   *
   * @deprecated
   */
  showCompressOptions?: boolean;

  /**
   * 是否为多选
   */
  multiple?: boolean;

  /**
   * 单选模式：当用户选中某个选项时，选项中的 value 将被作为该表单项的值提交，否则，整个选项对象都会作为该表单项的值提交。
   * 多选模式：选中的多个选项的 `value` 会通过 `delimiter` 连接起来，否则直接将以数组的形式提交值。
   */
  joinValues?: boolean;

  /**
   * 分割符
   */
  delimiter?: string;

  /**
   * 开启后将选中的选项 value 的值封装为数组，作为当前表单项的值。
   */
  extractValue?: boolean;

  /**
   * 清除时设置的值
   */
  resetValue?: any;

  /**
   * 缩路图展示模式
   */
  thumbMode?: 'w-full' | 'h-full' | 'contain' | 'cover';

  /**
   * 缩路图展示比率。
   */
  thumbRatio?: '1:1' | '4:3' | '16:9';

  /**
   * 上传后把其他字段同步到表单内部。
   */
  autoFill?: {
    [propName: string]: SchemaTokenizeableString;
  };

  /**
   * 默认占位图图片地址
   */
  frameImage?: SchemaUrlPath;

  /**
   * 是否开启固定尺寸
   */
  fixedSize?: boolean;

  /**
   * 固定尺寸的 CSS类名
   */
  fixedSizeClassName?: SchemaClassName;

  /**
   * 只读模式，只提供展示功能，不能编辑、不能进行上传删除等操作
   */
  readonly?: boolean;

  /**
   * 是否在文件赋值地址前，对地址进行读取容错，针对地址不存在或返回了错误信息
   */
  preAjax?: boolean;

  /**
   * 上传的提示文字
   */
  uploadText?: string;

  /**
   * 图片压缩的宽度
   */
  pressWidth?: number;
  /**
   * 展示形式。默认false
   */
  beauty?: boolean;
  /**
  * 判断是否在表格,默认false
  */
  tabSample?: boolean;
  /** 自定义文件列表渲染器, 用于重新定义文件列表的渲染 */
  attachmentRender?: (configs: any) => React.ReactDOM;
  /** 定义文件预览的Popover的触发方式，默认‘hover’ */
  attachmentTrigger?: string[];
}

let preventEvent = (e: any) => e.stopPropagation();
const isUrlImg = (file: FileX) => {
  if (!file.name && !file.size && file.addr.startsWith('http')) return true;
  return false;
}

export interface ImageProps
  extends FormControlProps,
  Omit<
    ImageControlSchema,
    'type' | 'className' | 'descriptionClassName' | 'inputClassName'
  > {
  onImageEnlarge?: (
    info: Pick<ImageThumbProps, 'src' | 'originalSrc' | 'title' | 'caption'> & {
      index?: number;
      list?: Array<
        Pick<ImageThumbProps, 'src' | 'originalSrc' | 'title' | 'caption'>
      >;
    }
  ) => void;
  _print_visible?: boolean;
  ctx?: {
    items: Array<any>;
    rows: Array<any>;
    selectedItems: Array<any>;
    unSelectedItems: Array<any>;
    ids: string;
    primaryField?: string;
    [key: string]: any;
  }
}

export interface LionUploadState {
  uploading: boolean;
  locked: boolean;
  lockedReason?: string;
  files: Array<FileValue | FileX>;
  crop?: any;
  error?: string;
  cropFile?: FileValue;
  cropFileName?: string; // 主要是用于后续上传的时候获得用户名
  submitOnChange?: boolean;
  frameImageWidth?: number;
  [propName: string]: any;
  isOpened: boolean;
  maxTagCount: number;
  minTagCount: number;
  pictureUrl: string;
}

export interface FileValue {
  value?: any;
  state: 'init' | 'error' | 'pending' | 'uploading' | 'uploaded' | 'invalid';
  url?: string;
  error?: string;
  info?: {
    width: number;
    height: number;
    len?: number;
  };
  [propName: string]: any;
}

export interface FileX extends File {
  id?: string | number;
  preview?: string;
  state?: 'init' | 'error' | 'pending' | 'uploading' | 'uploaded' | 'invalid';
  progress?: number;
  [propName: string]: any;
}
export default class LionUpload extends React.Component<
  ImageProps,
  any
> {
  static defaultProps = {
    limit: undefined,
    accept: '',
    receiver: '/api/upload',
    hideUploadButton: false,
    placeholder: 'Image.placeholder',
    joinValues: true,
    extractValue: false,
    delimiter: ',',
    autoUpload: true,
    multiple: false,
    maxSize: 10 * 1024 * 1024,
    beauty: false,
    tabSample: false,
    _print_visible: false,
    ctx: {
      items: [],
      rows: [],
      selectedItems: [],
      unSelectedItems: [],
      ids: ''
    }
  };

  static formatFileSize(
    size: number | string,
    units = [' B', ' KB', ' M', ' G']
  ) {
    size = parseInt(size as string, 10) || 0;

    while (size > 1024 && units.length > 1) {
      size /= 1024;
      units.shift();
    }

    return size.toFixed(2) + units[0];
  }

  static sizeInfo(
    width: number | undefined,
    height: number | undefined,
    __: TranslateFn
  ): string {
    if (!width) {
      return __('Image.height', { height: height });
    } else if (!height) {
      return __('Image.width', { width: width });
    }

    return __('Image.size', { width, height });
  }

  state: LionUploadState = {
    uploading: false,
    locked: false,
    files: [],

    // visible: false,
    // uploading: false,
    // params: '',
    // init: false,
    // formItemName: '',
    // removeIcon: true,
    // loading: false,
    // preUploading: false,   //预处理
    chunksSize: 0,   // 上传文件分块的总个数
    // currentChunks: 0,  // 当前上传的队列个数 当前还剩下多少个分片没上传
    // uploadPercent: -1,  // 上传率
    // preUploadPercent: -1, // 预处理率
    // uploadRequest: false, // 上传请求，即进行第一个过程中
    // uploaded: false, // 表示文件是否上传成功
    uploadParams: {} as any,
    arrayBufferData: [] as any,
    upload_cmd: 'check_exist',
    upload_name: '',
    // upload_field: '',
    file_type: '',
    // fileSize: 0,
    isOpened: false,
    maxTagCount: 0,
    minTagCount: 0,
    pictureUrl: ''
  };

  baseURL: string = '';
  fillCell: boolean

  files: Array<FileValue | FileX> = [];
  fileUploadCancelExecutors: Array<{
    file: any;
    executor: () => void;
  }> = [];
  cropper: Cropper;
  dropzone = React.createRef<any>();
  dropzoneimg = React.createRef<any>();
  frameImageRef = React.createRef<any>();
  current: FileValue | FileX | null = null;
  resolve?: (value?: any) => void;
  emitValue: any;
  unmounted = false;
  errImg: string;
  constructor(props: ImageProps) {
    super(props);
    this.baseURL = props.env?.axiosInstance?.defaults?.baseURL || props.env?.ajaxApi || ''
    // this.baseURL = 'https://sasdev.sanfu.com/saas_dev'
    // this.baseURL = 'https://bwt.sanfu.com/saas'

    this.state = {
      ...this.state,
      crop: this.buildCrop(props),
      frameImageWidth: 0,
      selectList: [],
      setvideo: false,
      structure: {},
      content: {},
    };
    this.fillCell = !!props.formItem && !!props.fillCell && !!props.readonly
    this.errImg = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg==';

    this.sendFile = this.sendFile.bind(this);
    this.removeFile = this.removeFile.bind(this);
    this.handleDrop = this.handleDrop.bind(this);
    this.handleClick = this.handleClick.bind(this);
    this.handleClick = this.handleClick.bind(this);
    this.handleCrop = this.handleCrop.bind(this);
    this.handleDropRejected = this.handleDropRejected.bind(this);
    this.cancelCrop = this.cancelCrop.bind(this);
    this.rotatableCrop = this.rotatableCrop.bind(this);
    this.handleFrameImageLoaded = this.handleFrameImageLoaded.bind(this);
    this.startUpload = this.startUpload.bind(this);
    this.stopUpload = this.stopUpload.bind(this);
    this.toggleUpload = this.toggleUpload.bind(this);
    this.tick = this.tick.bind(this);
    this.onChange = this.onChange.bind(this);
    this.addFiles = this.addFiles.bind(this);
    this.handleSelect = this.handleSelect.bind(this);
    this.handlePaste = this.handlePaste.bind(this);
    this.syncAutoFill = this.syncAutoFill.bind(this);
    this.initFiles = this.initFiles.bind(this)
    this.formatfileAddr = this.formatfileAddr.bind(this)
    this.updateFiles = this.updateFiles.bind(this)
    this.previewImage = this.previewImage.bind(this)
    this.handprogress.bind = this.handprogress.bind(this)
    this.chunks.bind = this.chunks.bind(this)
  }



  componentDidMount() {
    // this.syncAutoFill();
    // 初始化
    ImgCache[this.props.crudName] = ImgCache[this.props.crudName] || {}
    this.updateFiles()
    this.calcuate()

  }
  calcuate() {
    const { classnames: cx, } = this.props;
    const { files } = this.state
    this.setState({ maxTagCount: undefined }, async () => {

      const maxWidth = this.dropzoneimg.current!.clientWidth - (files && files.length > 1 ? 25 : 0)
      let tagWidth = 0
      let showCount = 0
      const children = await this.dropzoneimg.current?.getElementsByClassName(cx('ImageControl-img-wrapper'))

      const minTagCount = Math.floor(maxWidth / (children?.[0]?.offsetWidth + 12))

      if (children && children.length > 0) {
        for (let i = 0; i < children.length; i++) {
          const e = children[i] as HTMLDivElement
          if (tagWidth > maxWidth) {
            e.style.display = "none"
          }
          //如果是最后一个不需要使用这个length

          tagWidth += e.offsetWidth + ((i < children.length - 1) ? 12 : 0)
          if (tagWidth > maxWidth) {
            e.style.display = "none"
          }
          if (e.style.display != 'none') {
            showCount++
          }
        }

        this.setState({ maxTagCount: showCount, minTagCount })
      }
    })
  }

  updateFiles() {
    this.initFiles().then((files: Array<FileValue>) => {
      this.setState({
        files: (this.files = files)
      }, this.syncAutoFill)
    })
  }

  componentDidUpdate(prevProps: ImageProps) {
    const props = this.props;
    if (prevProps.value !== props.value && this.emitValue !== props.value) {
      if ((props.isFieldTable || props.tableType == 'input-table') && props?.value?.value && prevProps?.value?.value && props.value.value === prevProps.value.value) {
      } else {
        this.updateFiles()
      }
      this.calcuate()
    }
    if (prevProps?.value?.info?.length !== props?.value?.info?.length) {
      this.calcuate()
    }
    if (prevProps.crop !== props.crop) {
      this.setState({
        crop: this.buildCrop(props)
      });
    }
  }

  componentWillUnmount() {
    this.unmounted = true;
  }

  // 增加缓存
  getBatchAddrInfo(files: Array<FileValue>) {
    const requests = files.map(async (item) => {
      // 表格模式下才走
      if (this.props.crudName) {
        if (ImgCache[this.props.crudName][item.thumbnailAddr]) return ImgCache[this.props.crudName][item.thumbnailAddr]
        const getThumbnailAddr = () => new Promise((res) => {
          Axios(item.thumbnailAddr).then(res).catch(res)
        })
        const res = await getThumbnailAddr()
        ImgCache[this.props.crudName][item.thumbnailAddr] = res
        return res
      } else {
        return Axios(item.thumbnailAddr)
      }
    })
    return Promise.allSettled(requests)
  }

  analyzingAddrInfo(files: Array<FileValue>, allResponse: any[]) {
    const { name, value, store } = this.props
    const info = [...value.info]
    let list = files.concat()
    let hasErrorFile = false
    allResponse.forEach((item: any, index: number) => {
      if (item.status === 'fulfilled') {
        const result = item?.value
        if (result.status === 200) {
          list[index].notNull = true
          if (result.data.status) {
            list[index].errorMsg = result.data.msg
            list[index].state = 'error'
          } else {
            // list[index].thumbnailAddr = result.data
          }
        }

      }
      if (item.status === 'rejected') {
        if (item.reason?.response?.data?.status == 404) {
          info.splice(index, 1)
          hasErrorFile = true
        }
        // list[index].errorMsg = 'rejected'
        // list[index].state = 'error'
        // list[index].notNull = true
      }
    })
    if (name && hasErrorFile) store?.changeValue(name, { ...value, info })
    return list.filter((item: any) => item.notNull)
  }

  initFiles() {
    const { value, preAjax, data } = this.props
    let files: Array<FileValue> = []

    if (value) {
      const { value: fileValue, info: fileInfo } = value
      if (fileValue && Array.isArray(fileInfo) && fileInfo.length) {
        const fileValueArr = fileValue.split(',')
        files = fileInfo.map((item, index) => {
          return this.formatfileAddr(Object.assign({
            state: 'init',
            value: fileValueArr[index],
            taskId: data.TASK_ID
          }, item))
        })
      }
    }
    this.setState({ selectList: files.map((_, index) => index) })
    // files = testdata
    return new Promise(resolve => {
      if (preAjax && files.length) {
        this.getBatchAddrInfo(files).then(allResponse => {
          let list = this.analyzingAddrInfo(files, allResponse)
          resolve(list)
        })
      } else {
        resolve(files)
      }
    })

  }

  buildCrop(props: ImageProps) {
    let crop = props.crop;
    const __ = this.props.translate;

    if (crop && props.multiple) {
      props.env && props.env.alert && props.env.alert(__('Image.configError'));
      return null;
    }

    if (crop === true) {
      crop = {};
    }

    if (crop) {
      crop = {
        aspectRatio: undefined, // 默认不限制
        guides: true,
        dragMode: 'move',
        viewMode: 1,
        rotatable: true,
        scalable: true,
        ...crop
      };
    }

    return crop;
  }

  handleDropRejected(
    rejectedFiles: FileRejection[],
    evt: React.DragEvent<any>
  ) {
    if (evt.type !== 'change' && evt.type !== 'drop') {
      return;
    }
    const { multiple, env, accept, translate: __ } = this.props;

    const files = rejectedFiles.map(fileRejection => ({
      ...fileRejection.file,
      state: 'invalid',
      id: guid(),
      name: fileRejection.file.name
    }));

    env.alert(
      __('File.invalidType', {
        files: files.map((file: any) => `「${file.name}」`).join(' '),
        accept
      })
    );
  }

  // 开始上传
  startUpload(retry: boolean = false) {
    if (this.state.uploading) {
      return;
    }

    this.setState(
      {
        uploading: true,
        locked: true,
        files: (this.files = this.files.map(file => {
          if (retry && file.state === 'error') {
            file.state = 'pending';
            file.progress = 0;
          }

          return file;
        }))
      },
      this.tick
    );
  }

  toggleUpload() {
    return this.state.uploading ? this.stopUpload() : this.startUpload();
  }

  stopUpload() {
    if (!this.state.uploading) {
      return;
    }

    this.setState({
      uploading: false
    });
  }

  // 统一处理下，省的后续的组件重复去拼地址
  formatfileAddr(fileData: Omit<FileValue, 'state'>) {
    if (!fileData) return
    let obj = JSON.parse(JSON.stringify(fileData))
    if (obj.preview) {
      obj.preview = (obj.preview?.startsWith('http') ? '' : this.baseURL) + obj.preview
    }

    // 非图片格式去本地拿图标
    if (isImg(obj.name)) {
      obj.thumbnailAddr = (obj.thumbnailAddr?.startsWith('http') ? '' : this.baseURL) + (obj.thumbnailAddr || obj?.url || obj?.addr)
      // 给个标识，留给样式调整空间，以及调用不同的预览组件
      obj.isNotImg = false
    } else {
      obj.thumbnailAddr = getMediaIcon(obj.name)
      obj.isNotImg = true
    }
    const taskId: string | undefined = obj.taskId
    const url: string = (obj?.url || obj?.addr) ?? ''
    const dealUrl = taskId ? url.includes('?') ? `${url}&taskId=${taskId}` : `${url}?taskId=${taskId}` : url
    obj.downloadSrc = (obj.addr?.startsWith('http') ? '' : this.baseURL) + dealUrl
    return obj
  }

  tick() {
    if (this.current || !this.state.uploading) {
      return;
    }

    const env = this.props.env;
    const __ = this.props.translate;
    const file = find(this.files, item => item.state === 'pending') as FileX;
    if (file) {
      this.current = file;

      file.state = 'uploading';
      this.setState(
        {
          files: (this.files = this.files.concat())
        },
        () =>
          this.sendFile(
            file as FileX,
            (error, file, obj) => {
              const files = this.files.concat();
              const idx = files.indexOf(file);

              if (!~idx) {
                return;
              }

              let newFile: FileX | FileValue = file;

              if (error) {
                newFile.state =
                  file.state !== 'uploading' ? file.state : 'error';
                newFile.error = error;

                if (!this.props.multiple && newFile.state === 'invalid') {
                  files.splice(idx, 1);
                  this.current = null;

                  return this.setState(
                    {
                      files: (this.files = files),
                      error: error
                    },
                    this.tick
                  );
                }

                env.notify('error', error || __('File.errorRetry'));
              } else {
                newFile = this.formatfileAddr({
                  name: file.name || this.state.cropFileName,
                  size: file.size,
                  ...obj
                })
              }
              files.splice(idx, 1, newFile);
              this.current = null;
              this.setState(
                {
                  files: (this.files = files)
                },
                this.tick
              );
            },
            progress => {
              const files = this.files.concat();
              const idx = files.indexOf(file);

              if (!~idx) {
                return;
              }

              // file 是个非 File 对象，先不copy了直接改。
              file.progress = progress;
              this.setState({
                files: (this.files = files)
              });
            }
          )
      );
    } else {
      this.setState(
        {
          uploading: false,
          locked: false
        },
        () => {
          this.onChange(!!this.resolve);

          if (this.resolve) {
            this.resolve(
              this.files.some(file => file.state === 'error')
                ? __('File.errorRetry')
                : null
            );
            this.resolve = undefined;
          }
        }
      );
    }
  }

  removeFile(file: FileValue, index: number) {
    const files = this.files.concat();
    const fileIndex = files.indexOf(file as any)
    this.removeFileCanelExecutor(file, true);
    files.splice(fileIndex, 1);
    const isUploading = this.current === file;
    if (isUploading) {
      this.current = null;
    }

    this.setState(
      {
        files: (this.files = files)
      },
      isUploading ? this.tick : this.onChange
    );
  }

  previewImage(file: FileX, index: number, e: React.MouseEvent<any>) {
    const { isImage } = this.props;
    e.preventDefault();
    if (isCon(file.name) && !isImage) {
      Shell.hasShell() ?
        Shell.handleExternalUrl({
          "externalUrl": file.downloadSrc,
          "fileName": file.name,
          "handleType": "open"
        })
        :
        this.setState({
          setvideo: true,
          structure: {
            "type": "video",
            "src": file.downloadSrc,
            "poster": file.thumbnailAddr,
            "aspectRatio": "16:9"
          }
        })
    } else {
      const { onImageEnlarge } = this.props;
      if (onImageEnlarge) {
        const files = this.files;
        if (!isImage && file.isNotImg && file.size > 10 * 1024 * 1024) {
          message.info('大于10M的文件请下载后查看')
        } else {
          onImageEnlarge({
            // 预览地址
            src: (file.thumbnailAddr || file) as string,
            originalSrc: (file.preview || file) as string || this.errImg,
            index,
            list: files.map(file => ({
              src: (file.thumbnailAddr || file) as string,
              originalSrc: (file.preview || file) as string || this.errImg,
              downloadSrc: file.downloadSrc || file,
              title: file.name || (isImage && typeof file === 'string' ? file : getNameFromUrl(file.value || file.url)),
              isNotImg: file.isNotImg as boolean,
            }))

          });
        }
      }

    }
  }

  editImage(index: number) {
    const files = this.files;

    this.setState({
      cropFile: {
        preview: files[index].preview || (files[index].url as string),
        name: files[index].name,
        state: 'init'
      },
      cropFileName: files[index].name
    });
  }

  onChange(changeImmediately?: boolean) {
    const { onChange } = this.props;
    let newValue: any;
    newValue = this.files.reduce((t: any, c) => {
      if (c.state == 'uploaded' || c.state == 'init') {
        t.value += ((t.value ? ',' : '') + c.value)
        t.info.push({
          size: c.size,
          name: c.name
        })
      }
      return t
    }, {
      value: "",
      info: []
    })
    onChange((this.emitValue = newValue), undefined, changeImmediately);
    this.syncAutoFill();
  }

  syncAutoFill() {
    const { autoFill, multiple, onBulkChange, data } = this.props;
    if (!isEmpty(autoFill) && onBulkChange) {
      const files = this.state.files.filter(
        file => ~['uploaded', 'init', 'ready'].indexOf(file.state as string)
      );
      const toSync = dataMapping(
        autoFill,
        multiple
          ? {
            items: files
          }
          : files[0]
      );

      Object.keys(toSync).forEach(key => {
        if (isPlainObject(toSync[key]) && isPlainObject(data[key])) {
          toSync[key] = merge({}, data[key], toSync[key]);
        }
      });
      onBulkChange(toSync);
    }
  }

  handleSelect() {
    this.dropzone.current && this.dropzone.current.open();
  }

  handleRetry(index: number) {
    const files = this.files.concat();
    const file = files[index];

    if (file.state !== 'invalid' && file.state !== 'error') {
      return;
    }

    file.state = 'pending';
    file.progress = 0;

    this.setState(
      {
        files: files
      },
      this.startUpload
    );
  }

  handleDrop(files: Array<FileX>) {
    const { multiple, crop } = this.props;

    if (crop && !multiple) {
      const file: any = files[0] as FileValue;
      if (!file.preview || !file.url) {
        file.preview = window.URL.createObjectURL(file);
      }

      return this.setState({
        cropFile: file,
        cropFileName: file.name
      });
    }
    this.addFiles(files);
  }

  handlePaste(e: React.ClipboardEvent<any>) {
    const event = e.nativeEvent as any;
    const files: Array<FileX> = [];
    const items = event.clipboardData.items;
    const accept = this.props.accept || '*';

    [].slice.call(items).forEach((item: DataTransferItem) => {
      let blob: FileX;

      if (
        item.kind !== 'file' ||
        !(blob = item.getAsFile() as File) ||
        !accepts(blob, accept)
      ) {
        return;
      }

      blob.id = guid();
      files.push(blob);
    });

    this.handleDrop(files);
  }

  // 裁剪
  handleCrop() {
    const { cropFormat, cropQuality } = this.props;
    this.cropper.getCroppedCanvas().toBlob(
      (file: File) => {
        this.addFiles([file]);
        this.setState({
          cropFile: undefined,
          locked: false,
          lockedReason: ''
        });
      },
      cropFormat || 'image/png',
      cropQuality || 1
    );
  }

  cancelCrop() {
    this.setState(
      {
        cropFile: undefined,
        cropFileName: undefined,
        locked: false,
        lockedReason: ''
      },
      this.onChange
    );
  }

  rotatableCrop() {
    this.cropper.rotate(45);
  }

  handleOpenClick() {
    this.setState({
      isOpened: true
    });
  }

  close() {
    this.setState({
      isOpened: false
    });
  }

  async addFiles(files: Array<FileX>) {
    const { pressWidth = 640 } = this.props
    if (!files.length) {
      return;
    }
    const { multiple, maxLength, maxSize, accept, translate: __ } = this.props;
    let currentFiles = this.files;

    // 明确指定非多选的情况, 才进行清空操作
    if (multiple === false && currentFiles.length) {
      currentFiles = [];
    }

    const allowed =
      (multiple
        ? maxLength
          ? maxLength
          : files.length + currentFiles.length
        : 1) - currentFiles.length;
    let inputFiles: Array<FileX> = [];

    let list = [].slice.call(files, 0, allowed)


    for (const file of list) {
      if (maxSize && file.size > maxSize) {
        this.props.env.alert(
          __('File.maxSize', {
            filename: file.name,
            actualSize: LionUpload.formatFileSize(file.size),
            maxSize: LionUpload.formatFileSize(maxSize)
          })
        );
        return;
      }
      if (pressWidth && this.props.isImage && file.size > 1024 * 1024) {
        let img = new Image();
        img.src = URL.createObjectURL(file);

        img.onload = async () => {

          const { width } = img;
          let upFilez = file;
          if (width > pressWidth) {
            const res = await compress(file, { width: pressWidth, quality: 1 })
            upFilez = new window.File([res], file.name, { type: file.type })
            upFilez.state = 'pending';
            Object.defineProperties(upFilez, {
              path: {
                value: file.path,
                writable: false,
                enumerable: true,
                configurable: false
              }
            })
            // upFilez.path = file.path;
            upFilez.id = guid();
            if (!upFilez.preview || !upFilez.url) {
              upFilez.preview = URL.createObjectURL(upFilez);
            }
            inputFiles.push(upFilez);

          } else {
            file.state = 'pending';
            file.id = guid();
            if (!file.preview || !file.url) {
              file.preview = URL.createObjectURL(file);
            }
            inputFiles.push(file);
          }
          this.setState(
            {
              error: undefined,
              files: (this.files = currentFiles.concat(inputFiles)),
              locked: true
            },
            () => {
              const { autoUpload } = this.props;


              if (autoUpload) {
                this.startUpload();
              }
            }
          );
        }
      } else {
        file.state = 'pending';
        file.id = guid();
        if (!file.preview || !file.url) {
          file.preview = URL.createObjectURL(file);
        }
        inputFiles.push(file);


        this.setState(
          {
            error: undefined,
            files: (this.files = currentFiles.concat(inputFiles)),
            locked: true
          },
          () => {
            const { autoUpload } = this.props;

            if (autoUpload) {
              this.startUpload();
            }
          }
        );
      }
    }

  }

  sendFile(
    file: FileX,
    cb: (error: null | string, file: FileX, obj?: FileValue) => void,
    onProgress: (progress: number) => void
  ) {

    const { limit, translate: __ } = this.props;

    if (!limit) {
      return this._upload(file, cb, onProgress);
    }

    const image = new Image();
    image.onload = () => {
      const width = image.width;
      const height = image.height;
      let error = '';

      if (
        (limit.width && limit.width != width) ||
        (limit.height && limit.height != height)
      ) {
        error = __('Image.sizeNotEqual', {
          info: LionUpload.sizeInfo(limit.width, limit.height, __)
        });
      } else if (
        (limit.maxWidth && limit.maxWidth < width) ||
        (limit.maxHeight && limit.maxHeight < height)
      ) {
        error = __('Image.limitMax', {
          info: LionUpload.sizeInfo(limit.maxWidth, limit.maxHeight, __)
        });
      } else if (
        (limit.minWidth && limit.minWidth > width) ||
        (limit.minHeight && limit.minHeight > height)
      ) {
        error = __('Image.limitMin', {
          info: LionUpload.sizeInfo(limit.minWidth, limit.minHeight, __)
        });
      } else if (
        limit.aspectRatio &&
        Math.abs(width / height - limit.aspectRatio) > 0.01
      ) {
        error = __(limit.aspectRatioLabel || 'Image.limitRatio', {
          ratio: (+limit.aspectRatio).toFixed(2)
        });
      }

      if (error) {
        file.state = 'invalid';
        cb(error, file);
      } else {
        this._upload(file, cb, onProgress);
      }
    };
    image.src = (file.preview || file.url) as string;
  }

  // 自lion-input-file迁徙而来的上传方法1
  _upload(
    file: FileX,
    cb: (error: null | string, file: Blob, obj?: any) => void,
    onProgress: (progress: number) => void
  ) {
    const { url, receiver, env, name, translate: __ } = this.props;

    const formData = new FormData();
    this.handleFile(file).then(() => {
      const { uploadParams } = this.state;
      formData.append('upload_cmd', 'check_exist');
      formData.append('upload_field', String(name));
      formData.append('file_name', uploadParams?.file.fileName);
      formData.append('file_md5', uploadParams?.file.fileMd5);
      // 搞不懂为什么，这样在壳上可以解密
      Shell.hasShell() && Shell.uploadFile({ path: url || receiver, url: url || receiver, formData: formData, }, () => { }, () => { })

      env.fetcher({
        url: url || receiver,
        data: formData,
        method: 'post',
        dataType: 'form-data'
      }).then((res: any) => {
        if (res?.status === 0 && res?.data) {
          const { exist } = res?.data;
          switch (exist) {
            case true:
              onProgress(1)
              const obj: FileValue = {
                ...res.data,
                state: 'uploaded'
              };
              obj.value = obj.value || obj.url;
              cb(null, file, obj);
              break;
            case false:
              this.setState({
                upload_cmd: 'chunk_upload'
              }, () => {
                // 上传分片文件
                this.handlePartUpload(file, cb, onProgress)
              });
              break;
            default:
              break;
          }
        } else {
          throw new Error(res.msg || __('File.errorRetry'));
        }
      }).catch(error => cb(error.message || __('File.errorRetry'), file))
    })

  }

  async getFileMd5(file: any) {
    return new Promise<string>(resolve => {
      let spark = new SparkMD5.ArrayBuffer();
      let totalFileReader = new FileReader();

      totalFileReader.readAsArrayBuffer(file);
      totalFileReader.onload = function (e: any) {
        // 对整个totalFile生成md5
        spark.append(e.target.result)
        resolve(spark.end()) // 计算整个文件的fileMd5
      }
    })
  }

  // 自lion-input-file迁徙而来的上传方法2
  handleFile = (config: any) => {
    return new Promise(async (resolve: any, reject: any) => {
      let fileSize = config?.size;
      let file = config;

      let blobSlice = File.prototype.slice; // 切片使用

      let _this = this;

      let chunkSize = 1024 * 1024 * 1;   // 切片每次1M
      let chunks = Math.ceil(file.size / chunkSize); // 切片数
      let currentChunk = 0; // 当前上传的chunk索引

      let file_type = config?.type;
      let file_name = config?.name;

      let spark = new SparkMD5.ArrayBuffer(); // 对arrayBuffer数据进行md5加密，产生一个md5字符串
      let chunkFileReader = new FileReader(); // 用于计算出每个chunkMd5

      let params: any = { chunks: [], file: {} };  // 用于上传所有分片的md5信息

      let arrayBufferData: any = [];  // 用于存储每个chunk的arrayBuffer对象,用于分片上传使用

      params.file.fileName = file.name || this.state.cropFileName;
      params.file.fileSize = file.size;
      const md5 = await this.getFileMd5(file)
      params.file.fileMd5 = md5
      params.file.id = config.id

      chunkFileReader.onload = function (e: any) {
        // 对每一片分片进行md5加密
        spark.append(e.target.result)
        // 每一个分片需要包含的信息
        let obj = {
          chunk: currentChunk + 1,
          start: currentChunk * chunkSize, // 计算分片的起始位置
          end: ((currentChunk * chunkSize + chunkSize) >= file.size) ? file.size : currentChunk * chunkSize + chunkSize, // 计算分片的结束位置
          chunkMd5: spark.end(),
          chunks
        }
        // 每一次分片onload,currentChunk都需要增加，以便来计算分片的次数
        currentChunk++;
        params.chunks.push(obj)

        // 将每一块分片的arrayBuffer存储起来，用来partUpload
        let tmp = {
          chunk: obj.chunk,
          currentBuffer: e.target.result
        }
        arrayBufferData.push(tmp)

        if (currentChunk < chunks) {
          // 当前切片总数没有达到总数时
          loadNext()
        } else {
          //记录所有chunks的长度
          params.file.fileChunks = params.chunks.length
          // 表示预处理结束，将上传的参数，arrayBuffer的数据存储起来
          _this.setState({
            // preUploading: false,
            uploadParams: params,
            arrayBufferData,
            chunksSize: chunks,
            // preUploadPercent: 100,
            file_type: file_type,
            upload_name: params.file.fileName,
            fileSize: fileSize
          }, () => {
            resolve()
          })
        }
      }

      chunkFileReader.onerror = function () {
        console.warn('oops, something went wrong.');
      };

      function loadNext() {
        var start = currentChunk * chunkSize,
          end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
        chunkFileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
      }

      loadNext();
    })
  }

  // 自lion-input-file迁徙而来的上传方法3
  handlePartUpload = (originalFile: FileX, cb: Function, onProgress: (progress: number) => void) => {
    const { upload_cmd, upload_name, chunksSize, file_type, uploadParams } = this.state;
    const { chunks: uploadList, file } = uploadParams
    const { fileMd5 } = file;
    const { url, receiver, env, name } = this.props;
    let count = 0
    // 遍历uploadList
    try {
      // @ts-ignore
      Promise.allSettled(uploadList.map((_uploadItem: any) => {
        return new Promise((resolve: any, reject: any) => {
          const { chunkMd5, chunk, start, end } = _uploadItem;
          let formData = new FormData(),
            //新建一个Blob对象，将对应分片的arrayBuffer加入Blob中
            blob = new Blob([this.state.arrayBufferData[chunk - 1].currentBuffer], { type: 'application/octet-stream' });
          // 上传的参数
          let params = `fileMd5=${fileMd5}&chunkMd5=${chunkMd5}&chunk=${chunk}&start=${start}&end=${end}&chunks=${this.state.arrayBufferData.length}`

          // 通过formData将上传参数传入
          formData.append('upload_cmd', upload_cmd);
          formData.append('upload_field', String(name));
          formData.append('file_name', upload_name);
          formData.append('file_md5', fileMd5);
          formData.append('chunk_index', chunk);
          formData.append('chunk_total', String(chunksSize));
          formData.append('chunk_size', String(end - start));
          formData.append('type', file_type);
          formData.append('chunk_file', blob);
          // 搞不懂为什么，这样在壳上可以解密
          Shell.hasShell() && Shell.uploadFile({ path: url || receiver, url: url || receiver, formData: formData, }, () => { }, () => { })

          env.fetcher({
            url: url || receiver,
            data: formData,
            method: 'post'
          }).then((res: any) => {
            if (res.status === 0) {
              count++
              onProgress(count / chunksSize)
              resolve(res?.data)
            } else {
              reject({ _err: res?.msg, _data: formData })
            }
          }).catch(e => reject(e))
        })
      })).then((_res: any) => {

        let _chunk_success_count: number = 0;
        let _chunk_error_arr: any = [];

        _res.map((_upload_res: any) => {
          if (_upload_res?.status === 'fulfilled') {
            _chunk_success_count++
          } else {
            _chunk_error_arr.push(_upload_res.reason._data)
          }
        })

        if (_chunk_success_count === chunksSize) {
          let formData = new FormData();
          // 通过formData将上传参数传入，发起文件分片合并通知
          formData.append('upload_cmd', 'chunk_merge');
          formData.append('upload_field', String(name));
          formData.append('file_name', upload_name);
          formData.append('file_md5', fileMd5);
          // 搞不懂为什么，这样在壳上可以解密
          Shell.hasShell() && Shell.uploadFile({ path: url || receiver, url: url || receiver, formData: formData, }, () => { }, () => { })

          env.fetcher({
            url: url || receiver,
            data: formData,
            method: 'post'
          }).then((_merge_res: any) => {
            if (_merge_res?.status === 0) {
              const obj: FileValue = {
                ..._merge_res?.data,
                state: 'uploaded'
              };
              obj.value = obj.value || obj.url;
              cb(null, originalFile, obj);
            } else {
              cb(_merge_res?.msg, originalFile)
            }
          }).catch((_file_merge_res: any) => {
            cb('上传失败', originalFile)
            return;
          })
        } else {
          _chunk_error_arr.map((_chunk_error_item: any) => {
            env.fetcher({
              url: url,
              data: _chunk_error_item,
              method: 'post'
            }).then((_error_res: any) => {
            })
          })
          throw new Error('chunk file upload error!')
        }
      }).catch((_err: any) => {
        cb(_err, originalFile)
        return;
      })
    } catch (error) {
      cb(error, originalFile)
      return;
    }
  }

  removeFileCanelExecutor(file: any, execute = false) {
    this.fileUploadCancelExecutors = this.fileUploadCancelExecutors.filter(
      item => {
        if (execute && item.file === file) {
          item.executor();
        }

        return item.file !== file;
      }
    );
  }

  handleClick() {
    (this.refs.dropzone as any).open();
  }

  handleFrameImageLoaded(e: React.UIEvent<any>) {
    const imgDom = e.currentTarget;
    const img = new Image();
    const { clientHeight } = this.frameImageRef.current;

    const _this = this;
    img.onload = function () {
      const ratio = (this as any).width / (this as any).height;
      const finalWidth = (ratio * (clientHeight - 2)).toFixed(2);
      _this.setState({
        frameImageWidth: +finalWidth
      });
    };
    img.src = imgDom.src;
  }

  validate(): any {
    const __ = this.props.translate;

    if (this.state.locked && this.state.lockedReason) {
      return this.state.lockedReason;
    } else if (this.state.cropFile) {
      return new Promise(resolve => {
        this.resolve = resolve;
        this.handleCrop();
      });
    } else if (
      this.state.uploading ||
      this.files.some(item => item.state === 'pending')
    ) {
      return new Promise(resolve => {
        this.resolve = resolve;
        this.startUpload();
      });
    } else if (this.files.some(item => item.state === 'error')) {
      return __('File.errorRetry');
    }
  }
  //图片无法显示默认图片
  handleImageError(el: string, index: number) {
    const files = this.state.files.concat()
    const file = files[index]
    file.src = el ? el : this.errImg
    file.err = true
    files.splice(index, 1, file)
    this.setState({ files })
  }
  // 打印
  handleLabelPrint = (item: FileX) => {
    let list = item
    this.setState({
      ctx: {
        ...this.state.ctx,
        items: [list],
        rows: [list],
        selectedItems: [list],
        unSelectedItems: []
      }
    }, () => {
      const LODOP = getLodop()
      if (LODOP) {
        this.setState({
          _print_visible: true
        })
      }
    });
  }
  // 判断是否是pdf，图片，视频
  handlementCategory = (item: FileX) => {
    if (isImg(item.name) || isPdf(item.name)) {
      return true
    } else {
      return false
    }
  }
  // 进度条

  handprogress = (name: any) => {
    let { percent, size } = this.state.content[name]
    let speed: any = this.state.content
    const value = Number(((percent / size) * 100).toFixed(0))
    speed[name] = { ...this.state.content[name], percent: ++percent, pent: value !== Infinity ? value : 0 }
    this.setState({ content: speed }, () => {
      if (Number(((percent / size) * 100).toFixed(0)) == 100) {
        speed[name] = { ...this.state.content[name], percent: 0, pent: 0 }
        this.setState({ content: speed })
      }
    })
  }

  // 获取文件大小判断是否分流还有分流多大
  chunks = async (url: any, chunkSize = 524288, name: string) => {
    // "https://amis.bj.bcebos.com/amis/2019-12/1577157317579/trailer_hd.mp4"
    let staging = url.split("?").pop()
    let chunk = staging.split("=").pop()
    if (chunk === "1") {
      const datacontent = (await fetch(url, { method: "HEAD" })).headers.get("Content-Length") as string
      const contentSize = parseInt(datacontent);
      let previewvalue: any = this.state.content
      let speed: any = this.state.content
      previewvalue[name] = { "size": 0, "percent": 0, "pent": 0 }
      this.setState({ content: previewvalue }, () => {
        speed[name] = { ...this.state.content[name], size: Number((contentSize / chunkSize).toFixed(0)) }
        this.setState({ content: speed })
      })
      return contentSize;
    }
    return false
  }

  //0相册 1 拍照
  getImages = (type: number) => {
    const { maxLength = 0, multiple, } = this.props
    const { files } = this.state

    const count = maxLength - files.length;
    // maxLength大于0证明有配置,此时才需要验证
    if (count <= 0 && maxLength) {
      message.warning({ content: `上传个数已达上限${maxLength}个` })
      return
    }
    let list: any[] = [];
    let fail = (res: ShellFailResult) => {
      message.error(res.msg)
    }
    let info = (res: ShellDoneResult<ImgInfo>) => {
      if (res?.code === -200) {
        message.warning(res?.msg || '拍照失败')
      } else {
        list.push(res.data);
      }
    }
    let success = (res: ShellDoneResult<ImgInfo>) => {
      list.push(res.data);
      this.onUpload(list)
    }
    Shell.getAttachment({ type }, info, success, fail)
  }

  onUpload = (md5s: ImgInfo[]) => {
    const info = md5s.map(item => {
      const blob = this.base64ToBlob(item.dataurl)
      const file = new File([blob], item.filename, { type: 'image/png' })
      return file
    })
    this.handleDrop(info)
  }

  base64ToBlob = (base64Data: string) => {
    const byteString = atob(base64Data.split(',')[1]);
    const ab = new ArrayBuffer(byteString.length);
    const ia = new Uint8Array(ab);

    for (let i = 0; i < byteString.length; i++) {
      ia[i] = byteString.charCodeAt(i);
    }

    const blob = new Blob([ab], { type: 'image/png' });
    return blob;
  }

  filetext = (fileName: string) => {
    if (/(.pdf)/i.test(fileName)) {
      return <Icon icon={'file-pdf'} className="icon"></Icon>
    } else if (/(.ppt)/i.test(fileName)) {
      return <Icon icon={'file-ppt'} className="icon"></Icon>
    } else if (/(.jpe?)g|(.png)|(.svg)|(.gif)/i.test(fileName)) {
      return <Icon icon={'file-img'} className="icon"></Icon>
    } else if (/(.xlsx)|(.xls)/i.test(fileName)) {
      return <Icon icon={'file-xls'} className="icon"></Icon>
    } else if (/(.docx)|(.doc)/i.test(fileName)) {
      return <Icon icon={'file-doc'} className="icon"></Icon>
    } else {
      return <Icon icon={'file-file'} className="icon"></Icon>
    }
  }

  addContent = () => (
    <div className='add-content-container'>
      <div className='add-content-body'>
        <div className='add-content-body-show'>将图片拖拽或复制至此即可添加</div>
        <div className='add-content-divider' />
        <div className='add-content-body-input'>
          <div className='add-content-url'><Input value={this.state.pictureUrl} onChange={(e) => {
            this.setState({ pictureUrl: e.target.value })
          }} placeholder='输入图片地址' /></div>
          <div className='add-content-commit'><Button onClick={async () => {
            const newFiles: any[] = this.state.files.concat();
            newFiles.push({
              value: this.state.pictureUrl,
              state: "init",
              chunkDownload: false,
              preview: this.state.pictureUrl,
              size: null,
              addr: this.state.pictureUrl,
              thumbnailAddr: this.state.pictureUrl,
              isNotImg: false,
              downloadSrc: this.state.pictureUrl
            });
            this.setState({ files: newFiles }, () => {
              this.files = newFiles;
              this.onChange()
              this.setState({ pictureUrl: '' })
            });
          }} disabled={!this.state.pictureUrl}>确认</Button></div>
          <div className='add-content-add'><Button onClick={() => isMobile() ? this.setState({ isOpened: true }) : this.handleSelect()}>添加本地图片</Button></div>
        </div>
      </div>
    </div>
  )
  getIcon({name, color}) {
    return (<Icon icon={name} color={color} />)
  }
  render() {
    const {
      className,
      classnames: cx,
      placeholder,
      disabled,
      multiple,
      accept,
      maxLength,
      autoUpload,
      hideUploadButton,
      thumbMode,
      thumbRatio,
      reCropable,
      frameImage,
      fixedSize,
      fixedSizeClassName,
      readonly,
      uploadText,
      translate: __,
      beauty,
      data,
      isImage,
      tabSample,
      domicile,
      name,
      popOverContainer,
      label,
      isShowHide,
      attachmentRender,
      attachmentTrigger = ['hover']
    } = this.props;
    const isMobileUI = isMobile();
    const { files, error, crop, uploading, cropFile, frameImageWidth, selectList, structure, setvideo, content, maxTagCount, isOpened, minTagCount } = this.state;
    const acceptable = isMobileUI ? accept?.split(',').some(item => ['jpeg', 'jpg', 'png', 'gif'].some(format => item.includes(format))) ? accept.replace(/.jpeg/g, 'image/jpeg')
      .replace(/.jpg/g, 'image/jpg')
      .replace(/.png/g, 'image/png')
      .replace(/.gif/g, 'image/gif') : accept : accept

    // 是否可以添加图片的判断
    // 是否不是只读
    // 是否mobileui 是 是否多选，并且是否达到选择上限  否 是否有文件
    const canAddImage = !readonly && (
      ((multiple && (!maxLength || files.length < maxLength)) ||
        (!multiple && !files.length)))

    let frameImageStyle: any = {};
    if (fixedSizeClassName && frameImageWidth && fixedSize) {
      frameImageStyle.width = frameImageWidth;
    }
    const filterFrameImage = filter(frameImage, this.props.data, '| raw');
    const hasPending = files.some(file => file.state == 'pending');

    return (
      <div className={cx(`ImageControl`, className, {
        'isMobile': isMobileUI
      })} style={{ height: this.fillCell ? '100%' : undefined }}>
        {cropFile ? (
          <div className={cx('ImageControl-cropperWrapper')}>
            <Suspense fallback={<div>...</div>}>
              <Cropper
                {...crop}
                onInitialized={instance => {
                  this.cropper = instance;
                }}
                src={cropFile.preview}
              />
            </Suspense>
            <div className={cx('ImageControl-croperToolbar')}>
              {crop.rotatable && (
                <a
                  className={cx('ImageControl-cropRotatable')}
                  onClick={this.rotatableCrop}
                  data-tooltip={__('rotate')}
                  data-position="left"
                >
                  <Icon icon="retry" className="icon" />
                </a>
              )}
              <a
                className={cx('ImageControl-cropCancel')}
                onClick={this.cancelCrop}
                data-tooltip={__('cancel')}
                data-position="left"
              >
                <Icon icon="close" className="icon" />
              </a>
              <a
                className={cx('ImageControl-cropConfirm')}
                onClick={this.handleCrop}
                data-tooltip={__('confirm')}
                data-position="left"
              >
                <Icon icon="check" className="icon" />
              </a>
            </div>
          </div>
        ) : (
          <DropZone
            key="drop-zone"
            ref={this.dropzone}
            onDrop={this.handleDrop}
            onDropRejected={this.handleDropRejected}
            accept={accept === '*' ? '' : Shell.hasShell() ? acceptable : accept}
            multiple={multiple}
            disabled={disabled}
          >
            {({
              getRootProps,
              getInputProps,
              isDragActive,
              isDragAccept,
              isDragReject,
              isFocused
            }) => {
              let addCon = <label
                className={cx(
                  'ImageControl-addBtn',
                  {
                    'is-disabled': disabled
                  },
                  fixedSize ? 'ImageControl-fixed-size' : '',
                  fixedSize ? fixedSizeClassName : ''
                )}
                style={frameImageStyle}
                onClick={(e) => {
                  isImage ? null : isMobileUI ? this.setState({ isOpened: true }) : this.handleSelect()
                }}
                data-tooltip={isMobile() ? null : __(placeholder)}
                data-position="right"
                ref={this.frameImageRef}
              >
                {filterFrameImage ? (
                  <ImageComponent
                    key="upload-default-image"
                    src={filterFrameImage}
                    className={cx(
                      fixedSize ? 'Image-thumb--fixed-size' : ''
                    )}
                    onLoad={this.handleFrameImageLoaded.bind(this)}
                    thumbMode={thumbMode}
                    thumbRatio={thumbRatio}
                  />
                ) : (
                  isMobileUI ? <>
                    {files && !files.length && !readonly ? <span className='icon-isMobileUI'>
                      <Icon icon="right-arrow-bold" className="icon" style={{ color: "#0003" }} />
                    </span> : null}
                    <PopUp
                      isShow={isOpened}
                      className={'popOverClassName Upload'}
                      onHide={() => this.setState({ isOpened: false })}
                      isShowHide={!canAddImage && isShowHide}
                      header={<div className={cx('TransferDropDown-header')}>{label ?? domicile?.label ?? ''}</div>}
                      multiple={multiple}
                      showClose
                      container={popOverContainer ?? this.props?.env?.getModalContainer ?? document.getElementById('amis-modal-container')!}
                      popOverHeatClassName={'PopUp-popOverHeat'}
                    >
                      <div className={cx('ImageControl-upload')}>
                        <div className={cx('ImageControl-upload-body')}>
                          <div className={cx('ImageControl-upload-content')} id="containerss">
                            <ul className={cx('ImageControl-upload-ul')}>
                              {
                                files && files.length ? files.map((file, index) => {
                                  return <MoveUploadimg
                                    props={this.props}
                                    files={files}
                                    file={file}
                                    isImage={isImage}
                                    errImg={this.errImg}
                                    index={index}
                                    key={index}
                                    formatFileSize={LionUpload.formatFileSize}
                                    readonly={readonly}
                                    disabled={disabled}
                                    downloadFile={downloadFile}
                                    removeFile={() => {
                                      this.removeFile(file as FileValue, index)
                                    }}
                                  />
                                }) : null
                              }
                            </ul>
                          </div>
                          {isImage && <div className={cx('ImageControl-upload-url-input')}>
                            <div className='add-url'><Input value={this.state.pictureUrl} onChange={(e) => {
                              this.setState({ pictureUrl: e.target.value })
                            }} placeholder='输入图片地址' /></div>
                            <div className='add-url-commit'><Button onClick={async () => {
                              const newFiles: any[] = this.state.files.concat();
                              newFiles.push({
                                value: this.state.pictureUrl,
                                state: "init",
                                chunkDownload: false,
                                preview: this.state.pictureUrl,
                                size: null,
                                addr: this.state.pictureUrl,
                                thumbnailAddr: this.state.pictureUrl,
                                isNotImg: false,
                                downloadSrc: this.state.pictureUrl
                              });
                              this.setState({ files: newFiles }, () => {
                                this.files = newFiles;
                                this.onChange()
                                this.setState({ pictureUrl: '' })
                              });
                            }} disabled={!this.state.pictureUrl}>确认</Button></div>
                          </div>}
                        </div>
                        <div className={cx('ImageControl-upload-button')}>
                          {isImage && canAddImage && <div className={cx('ImageControl-button-icon')}>
                            <Buttons icon={<Icon icon="export-picture-icon" className={`icon ${canAddImage ? 'image' : ''}`} />} type="text" onClick={() => canAddImage &&
                              this.handleSelect()
                            } />
                            <span>
                              {__('Flow.image')}
                            </span>
                          </div>}
                          {!isImage && canAddImage && <div className={cx('ImageControl-button-icon')}>
                            <Buttons icon={
                              <FolderTwoTone className={canAddImage ? "" : "file"} />
                            } type="text" onClick={() => canAddImage && this.handleSelect()} />
                            <span>
                              {__('Flow.file')}
                            </span>
                          </div>}
                          {isImage && <div className={cx('ImageControl-button-icon')}>
                            <Buttons icon={
                              <InstagramOutlined style={{ color: canAddImage ? '#8dc8ff' : '' }} />
                            } type="text" onClick={() => canAddImage && this.getImages(1)} />
                            <span>
                              {__('Flow.photograph')}
                            </span>
                          </div>}
                        </div>
                      </div>
                    </PopUp>
                  </>
                    : <>
                      <Icon icon="plus" className="icon" />
                      {!tabSample &&
                        <span>
                          {uploadText || __('File.upload')}
                        </span>
                      }
                    </>
                )}

                {
                  isFocused && !isMobile ? (
                    <span className={cx('ImageControl-pasteTip')}>
                      {__('Image.pasteTip')}
                    </span>
                  ) : null}
              </label>
              return (
                <div
                  {...getRootProps({
                    onClick: preventEvent,
                    onPaste: this.handlePaste,
                    className: cx('ImageControl-dropzone', {
                      'is-disabled': disabled,
                      'is-empty': !files.length,
                      'is-active': isDragActive,
                      'is-pcImage': !isMobile(),
                      'addble': canAddImage,
                      "ImageControl-formfile-noImage": !isImage && files?.length == 1
                    },

                      tabSample ? "ImageControl-formfile" : '')
                  })}
                  onClick={() => { isMobileUI ? this.setState({ isOpened: true }) : null }}
                  ref={this.dropzoneimg}
                  style={{ display: this.fillCell ? 'flex !important' : 'flex', height: this.fillCell ? '100%' : undefined }}
                >
                  <input {...getInputProps()} />

                  {isDragActive || isDragAccept || isDragReject ? (
                    <div
                      className={cx('ImageControl-acceptTip', {
                        'is-accept': isDragAccept,
                        'is-reject': isDragReject
                      })}
                    >
                      {__('Image.dragDrop')}
                    </div>
                  ) : (
                    <>
                      <>
                        {
                          files && files.length
                            ? files.map((file, key) => {
                              return isMobileUI ? (
                                <MoveUpload
                                  readonly={readonly}
                                  dropzone={this.dropzoneimg}
                                  isImage={isImage}
                                  props={this.props}
                                  maxTagCount={maxTagCount}
                                  minTagCount={minTagCount}
                                  files={files}
                                  key={key}
                                  index={key}
                                  errImg={this.errImg}
                                  file={file}
                                  onClick={() => { this.setState({ isOpened: true }) }}
                                />
                              ) : (tabSample ?
                                <Popover
                                 content={
                                  <div className='amis-scope' style={{ background: 'none' }}>
                                    <CellPopover
                                      canDelete={this.props.canDelete}
                                      canUpload={this.props.canUpload}
                                      isSingleFile={false}
                                      tabSample={tabSample}
                                      mediaList={files}
                                      singlePhoto={file}
                                      selectList={selectList}
                                      readonly={readonly}
                                      maxLength={maxLength}
                                      isImage={isImage}
                                      formatFileSize={LionUpload.formatFileSize}
                                      Print={() => {
                                        selectList.map((_: string | number) => files[_]).map((file: any) => {
                                          this.handlementCategory(file as any)
                                        })
                                      }}
                                      // 打印
                                      printMedia={() => {
                                        selectList.map((_: string | number) => files[_]).map((file: any) => {
                                          this.handleLabelPrint(file as any)
                                        })
                                      }}
                                      //删除
                                      remove={() => {
                                        selectList.map((_: string | number) => files[_]).map((file: any, index: number) => { this.removeFile(file as any, index) })
                                      }}
                                      upload={
                                        this.handleSelect
                                      }
                                      // 下载
                                      downloadMedia={() => {
                                        selectList.map((_: string | number) => files[_]).map((file: any) => {
                                          downFile(
                                            // 获取文件大小判断是否分流还有分流多大
                                            this.chunks,
                                            // url
                                            file.downloadSrc,
                                            //名字00
                                            file.name,
                                            // 进度条
                                            this.handprogress
                                          )
                                        })
                                      }}
                                      // -1说明是单个文件用自己 否则根据点中的下标决定
                                      previewMedia={(mediaIndex: any, e: React.MouseEvent<any, MouseEvent>) => {
                                        this.previewImage?.(mediaIndex === -1 ? file : files[mediaIndex] as any, mediaIndex === -1 ? key : mediaIndex, e)
                                      }}
                                      // 反选全选
                                      selectMedia={(type: 'all' | 'invert') => {
                                        let _selectList = [...selectList]
                                        switch (type) {
                                          // 全选
                                          case 'all':
                                            _selectList = []
                                            _selectList = files.map((_, index) => index)
                                            break
                                          case 'invert':
                                            // 全选了就清空
                                            if (_selectList.length === files.length) {
                                              _selectList = []
                                            } else {
                                              _selectList = []
                                              // 否则全部选中
                                              _selectList = files.map((_, index) => index)
                                            }
                                            break
                                        }
                                        this.setState({ selectList: _selectList })
                                      }}
                                      // 选中
                                      checkMedia={(mediaIndex: any) => {

                                        // 添加选中效果
                                        const _selectList = [...selectList]
                                        const selectIndex = _selectList.findIndex(_ => _ === mediaIndex)
                                        if (selectIndex < 0) {
                                          _selectList.push(mediaIndex)
                                        } else {
                                          _selectList.splice(selectIndex, 1)
                                        }
                                        this.setState({ selectList: _selectList })
                                      }}
                                    />
                                  </div>
                                }
                                  trigger={isMobile() ? [] : attachmentTrigger}
                                  // trigger="click"
                                  placement='top'
                                  autoAdjustOverflow={true}
                                  destroyTooltipOnHide={true}
                                  // getPopupContainer={popOverContainer}
                                  overlayClassName='table-media-format-popover'
                                >
                                 {attachmentRender ? (<>{attachmentRender({downloadFile, previewImage:this.previewImage, fileText:this.filetext, handleImageError: this.handleImageError, fileInfo: {file, key}, getIcon: this.getIcon})}</>) : (<>
                                 {
                                    !isImage && files.length == 1 && < div className={cx('Cell-img-wrapper-isImage')} >
                                      <span onClick={(e) => { this.previewImage?.(file as any, key, e) }}
                                        className={cx('Cell-img-wrapper-content')}>
                                        <span className='textfile_icon'>
                                          {this.filetext(file.name)}
                                        </span>
                                        <span className='text'>
                                          {file.name}
                                        </span>
                                      </span>
                                      <span className='item-select-tag-btn' title={__('download')} onClick={() => {
                                        downloadFile(file.downloadSrc, file.name)
                                      }}>
                                        <DownloadOutlined style={{ fontSize: 14, color: '#ccc' }} />
                                      </span>
                                    </div>
                                  }
                                  {!(!isImage && files.length == 1) && <div className={cx('Cell-img-wrapper')} style={{ display: 'inline-block' }}>

                                    <img
                                      key={file.value || key}
                                      src={file.thumbnailAddr || file.url}
                                      className={cx('Cell-img')}
                                      onClick={(e) => {
                                        this.previewImage?.(file as any, key, e)
                                      }}
                                      onError={(e) => this.handleImageError(file.src, key)}
                                    />

                                    {
                                      content[file.name]?.pent !== "Infinity" && content[file.name]?.pent > 0 &&
                                      <div style={{ display: "inline-block", width: 30, height: 30 }}>
                                        < Progress type="circle" style={{ margin: "auto" }} key={key} percent={content[file.name]?.pent} width={25} />
                                      </div>
                                    }
                                  </div>}
                                 </>
                                 )}
                                </Popover>
                                :
                                <div
                                  key={file.id || key}
                                  className={cx(
                                    'ImageControl-item',
                                    {
                                      'is-uploaded': file.state !== 'uploading',
                                      'is-invalid':
                                        file.state === 'error' ||
                                        file.state === 'invalid',
                                      'readonly-mode': readonly || (!multiple && files.length),

                                    },
                                    fixedSize ? 'ImageControl-fixed-size' : '',
                                    fixedSize ? fixedSizeClassName : ''
                                  )}
                                  style={{ ...frameImageStyle, width: this.fillCell ? `calc(${1 / files.length * 100}% - 0.75rem)` : undefined, height: this.fillCell ? '100%' : undefined }}
                                >
                                  {file.state === 'invalid' || file.state === 'error' ? (
                                    <div className={cx('ImageControl-image')}>
                                      {
                                        !readonly
                                          ? <a
                                            className={cx('ImageControl-itemClear')}
                                            data-tooltip={__('Select.clear')}
                                            data-position="bottom"
                                            onClick={this.removeFile.bind(
                                              this,
                                              file,
                                              key
                                            )}
                                          >
                                            <Icon icon="close" className="icon" />
                                          </a>
                                          : null
                                      }

                                      {
                                        !file.errorMsg
                                          ? <a
                                            className={cx(
                                              'ImageControl-retryBtn',
                                              {
                                                'is-disabled': disabled
                                              },
                                              fixedSize ? 'ImageControl-fixed-size' : '',
                                              fixedSize ? fixedSizeClassName : ''
                                            )}
                                            onClick={this.handleRetry.bind(this, key)}
                                          >
                                            <Icon icon="retry" className="icon" />
                                            <p className="ImageControl-itemInfoError">
                                              {__('File.repick')}
                                            </p>
                                          </a>
                                          : <a className={cx('ImageControl-retryBtn')}>
                                            <div>
                                              <img style={{ width: '100%', height: '100%' }} src={file.thumbnailAddr || file.url} onError={(e) => this.handleImageError(file.src, key)} alt="" />
                                            </div>
                                            <p className="errorMsg">
                                              {file.errorMsg}
                                            </p>
                                          </a>
                                      }

                                    </div>
                                  ) : file.state === 'uploading' ? (
                                    <div className={cx('ImageControl-image')}>
                                      <a
                                        onClick={this.removeFile.bind(
                                          this,
                                          file,
                                          key
                                        )}
                                        key="clear"
                                        className={cx('ImageControl-itemClear')}
                                        data-tooltip={__('Select.clear')}
                                      >
                                        <Icon icon="close" className="icon" />
                                      </a>
                                      <div
                                        key="info"
                                        className={cx(
                                          'ImageControl-itemInfo',
                                          fixedSize ? 'ImageControl-fixed-size' : '',
                                          fixedSize ? fixedSizeClassName : ''
                                        )}
                                      >
                                        <Progress type="circle" width={50} percent={Math.round(file.progress * 100)} />
                                      </div>
                                    </div>
                                  ) : (
                                    <>
                                      {isMobileUI ? <div className='show-img-container' onClick={(e) => { this.previewImage(file as FileX, key, e) }}>
                                        <div className='img-left'>
                                          <img style={{ width: '100%' }} src={file.thumbnailAddr || file.url} />
                                        </div>
                                        <div className='img-right'>
                                          <div className='img-name'>{file.fileName || file.name}</div>
                                          <div className='img-size'>{LionUpload.formatFileSize(file.size)}</div>
                                        </div>
                                        {!readonly && !disabled ? <div className='img-del'>
                                          <CloseCircleOutlined onClick={(e) => {
                                            e.stopPropagation();
                                            this.removeFile(file as FileValue, key);
                                          }} />
                                        </div> : null}
                                      </div> : <ImageComponent
                                        key="image"
                                        className={cx(
                                          'ImageControl-image',
                                          fixedSize ? 'Image-thumb--fixed-size' : '',
                                          isImage ? "" : "ImageControl-file",
                                          this.fillCell ? 'ImageControl-fillCell' : ''
                                        )}
                                        src={this.fillCell ? ((file.addr?.startsWith('http') ? '' : this.baseURL) + file.addr) : file.thumbnailAddr || file.addr || file}
                                        originalSrc={file.preview || file}
                                        alt={file.fileName}
                                        thumbMode={thumbMode}
                                        thumbRatio={thumbRatio}
                                        // fileName={file.fileName}
                                        // 非图片格式缩略图使用图标填充
                                        imageClassName={file.isNotImg ? 'icon-fill' : ''}
                                        fillCell={this.fillCell}
                                        overlays={
                                          <>
                                            {/* 查看大图 */}
                                            <a
                                              data-tooltip={isCon(file.name) && !isImage ? "查看视频" : __('Image.zoomIn')}
                                              data-position="bottom"
                                              target="_blank"
                                              rel="noopener"
                                              href={file.url || file.preview || file}
                                              onClick={this.previewImage.bind(
                                                this,
                                                file,
                                                key
                                              )}
                                            >
                                              <Icon icon="view" className="icon" />
                                            </a>
                                            {/* 剪裁编辑 */}
                                            {!!crop &&
                                              reCropable !== false &&
                                              !disabled ? (
                                              <a
                                                data-tooltip={__('Image.crop')}
                                                data-position="bottom"
                                                onClick={this.editImage.bind(
                                                  this,
                                                  key
                                                )}
                                              >
                                                <Icon
                                                  icon="pencil"
                                                  className="icon"
                                                />
                                              </a>
                                            ) : null}
                                            {/* 下载 */}
                                            <a
                                              data-tooltip={__('download')}
                                              data-position="bottom"
                                              onClick={() => {
                                                (file.downloadSrc || file.addr).includes(this.baseURL) ? downloadFile(file.downloadSrc || file.addr, (typeof file == 'string' ? '' : file.name))
                                                  : downFile(this.chunks, file.downloadSrc || file.addr, file.name, this.handprogress)
                                              }}
                                            >
                                              <Icon icon="download" className="icon" />
                                            </a>
                                            {/* 移除 */}
                                            {!readonly && !disabled ? (
                                              <a
                                                data-tooltip={__('Select.clear')}
                                                data-position="bottom"
                                                onClick={this.removeFile.bind(
                                                  this,
                                                  file,
                                                  key
                                                )}
                                              >
                                                <Icon icon="remove" className="icon" />
                                              </a>
                                            ) : null}

                                          </>
                                        }
                                      />}
                                      {/* 判断是不是图片，图片无文字，文件有文字 */
                                        (!isMobile() && !this.fillCell) && (isImage ? null :
                                          (
                                            <>
                                              <p className='image-info'>{file.name}</p>
                                              <p className='image-info'>{file.size && LionUpload.formatFileSize(file.size)}</p>
                                            </>
                                          ))
                                      }
                                    </>
                                  )}
                                </div>)
                            })
                            : null
                        }
                        {
                          // 上传
                          (canAddImage || (isMobileUI)) && !(this.props.tableLayout === 'horizontal' && this.props.isFieldTable) ? (
                            isImage && !isMobile() ? <Popover autoAdjustOverflow placement='right' content={this.addContent()} trigger="click"
                              getPopupContainer={() => document.getElementById('amis-modal-container')! || document.body}>
                              {addCon}
                            </Popover> :
                              addCon
                          ) : null
                        }
                      </>
                      {canAddImage && !autoUpload && !hideUploadButton && files.length ? (
                        <Button
                          level="default"
                          className={cx('ImageControl-uploadBtn')}
                          disabled={!hasPending}
                          onClick={this.toggleUpload}
                        >
                          {__(uploading ? 'File.pause' : 'File.start')}
                        </Button>
                      ) : null}


                      {error ? (
                        <div className={cx('ImageControl-errorMsg')}>{error}</div>
                      ) : null}
                      {/*视频 */}


                      {/* 打印弹窗 */}
                      {this.state._print_visible && <ModalPrint printType='file' {...this.props as any} isSingleFilePrint={true} ctx={this.state.ctx as any} show={this.state._print_visible} onHide={() => { this.setState({ _print_visible: false }) }}></ModalPrint>}
                    </>
                  )
                  }
                </div>
              )
            }}
          </DropZone>
        )
        }
        {
          setvideo && <Modal title="视频" visible={setvideo} zIndex={1011}
            maskClosable={false}
            destroyOnClose={true}
            width={isMobile() ? "100%" : "55%"}
            keyboard={false}
            okText='关闭'
            cancelButtonProps={{ style: { display: 'none' } }}
            onOk={() => { this.setState({ setvideo: false }) }}
            onCancel={() => { this.setState({ setvideo: false }) }}
            getContainer={this.props.env.getModalContainer}
          >
            {
              this.props.render("Video", structure)
            }
          </Modal >
        }

      </div >
    );
  }
}

@Renderer({
  type: 'simple-upload-table-cell',
  name: 'simple-upload-table-cell'
})
export class SimpleUploadTableCellRenderer extends LionUpload { }

@FormItem({
  type: 'lion-upload',
  sizeMutable: false
})
export class LionUploadRenderer extends LionUpload { }
