<!--
  * @File 基于Antd的上传组件
  * @FileDescription 上传
  * value: 默认值 列表 'object_name, path, url 需要传值其中的一个' 'fileName, file_name, name, object_name 需要传值其中的一个 [{},{},{}]
  * String(required) urlShowFiles: 文件显示的url
  * String(required) urlUpload: 文件上传的的url
  * String type: 使用类型 图片或者文件 可选值 'img', 'file', 'video', 'other' 默认值img
  * Number maxFiles: 最大上传数量 默认值 5
  * Number maxSizes 最大单个文件上传大小 单位:MB 默认值 10
  * Array verifyType 验证类型 用于限制上传文件类型 传值文件类型或者后缀 ['all']不验证
  * String protected: 权限 PUBLIC(默认) 公开  所有用户均可访问 PROTECTED 受保护的  上传文件的用户可直接访问，运营人员可通过权限申请进行访问'
  * String tokenUser: 用户token 权限为保护的情况下必传
  * Boolean picture: 是否以图片类型展示 使用类型为'file'有效
  * Boolean multiple: 是否批量上传
  * Boolean directory: 是否文件夹上传
  * Boolean cropper: 是否可截图 当上传类型为图片时 并且非上传文件和批量时有效
  * Object cropperOptions: 截图配置选项 当可截图时
  *                   ratio  默认比例 可选值  1 (1:1) 4 (4 : 3) 5 (5:4) 16 (16:9) 0 (自定义) 默认值: 4:3
  *                   isRatio 是否可更改比例 默认值: true
  * Array resultFormat: 返回值格式 可选值: 'uid', 'fileName', 'file_name', 'icon', 'name', 'object_name', 'path', 'status', 'thumbUrl', 'type' 其中若需要type类型 默认赋值时需要传值
  * @desc 后续拓展升级方向： 1：上传方式增加 formData上传 2: 插槽显示已经上传数据
  * @Author 佟春晓
  * @Date 2021-10-29
  * @Update 佟春晓(2021-10-29)
-->
<template>
  <div>
    <!-- 自定义剪切组件 -->
    <CropperModal ref="cropper" @ok="handleCropperSuccess" />
    <!-- Antd上传组件 -->
    <a-upload
      name="upload"
      :listType="['img','video'].includes(type) || (type == 'file' && picture) ? 'picture-card' : 'text'"
      :file-list="listFiles"
      :beforeUpload="beforeImgUpload"
      :customRequest="this.customImgRequest"
      @change="changeFiles"
      @preview="handlePreview"
      :showUploadList="{ showPreviewIcon: ['img','video'].includes(type) }"
      :multiple='multiple'
      :directory='directory'
    >
      <!-- 自定义点击上传图片、视频 -->
      <div v-if="listFiles.length < maxFiles && (['img','video'].includes(type) || (type == 'file' && picture))" class="up_img_d">
        <a-icon style="font-size: 30px;" type="plus" />
        <div class="ant-upload-text" style="margin-top: 10px;">
          {{  type == 'img' ? '上传图片' : type == 'video' ? '上传视频' : '上传文件'}}
        </div>
      </div>
      <!-- 自定义点击上传文件 -->
      <div v-if=" listFiles.length < maxFiles && ( (type == 'file' && !picture) || type == 'other' )" class="up_img_d">
        <a-button style='background-color: #FFFFFF; color: #999999; font-size: 12px; border: 1px solid #d9d9d9;; box-shadow: 0 2px 0 rgba(0,0,0,.015); border-radius: 4px; height: 32px;'>
          <a-icon type="upload" /> 选择文件
        </a-button>
      </div>
    </a-upload>
    <!-- 图片和视频预览 -->
    <a-modal
      :visible="isPreviewVisible"
      :footer="null"
      @cancel="handlePreviewCancel"
    >
      <!-- 自定义显示组件 -->
      <ShowFile :type='type' :src="urlPreviewFiles" :tokenUser='tokenUser'/>
    </a-modal>
  </div>
</template>

<script>
import SparkMD5 from 'spark-md5'
import getSvgIcon from './static/iconsvg'
import ShowFile from './ShowFile'
import CropperModal from './CropperModal'
export default {
  name: 'Upload',
  components: {
    ShowFile,
    CropperModal
  },
  props: {
    // 默认值
    value: {
      type: Array,
      default: () => []
    },
    /* 文件显示的url */
    urlShowFiles: {
      type: String,
      default: '',
      required: true
    },
    /* 文件上传的的url */
    urlUpload: {
      type: String,
      default: '',
      required: true
    },
    /* 使用类型 图片或者文件 'img', 'file', 'video', 'other' */
    type: {
      type: String,
      default: 'img',
      validator: (value) => ['img', 'file', 'video', 'other'].includes(value)
    },
    /* 用户token 权限为保护的情况下必传 */
    tokenUser: {
      type: String,
      default: ''
    },
    /* 最大上传数量 */
    maxFiles: {
      type: Number,
      default: 5
    },
    /* 最大单个文件上传大小 单位:MB */
    maxSizes: {
      type: Number,
      default: 10
    },
    /* 验证类型  用于限制上传文件类型 传值文件类型或者后缀 */
    verifyType: {
      type: Array,
      default: null
    },
    /* 权限 PUBLIC 公开  所有用户均可访问 PROTECTED 受保护的  上传文件的用户可直接访问，运营人员可通过权限申请进行访问 */
    protected: {
      type: String,
      default: 'PUBLIC',
      validator: (value) => ['PUBLIC', 'PROTECTED'].includes(value)
    },
    /* 是否批量上传 */
    multiple: {
      type: Boolean,
      default: false
    },
    /* 是否文件夹上传 */
    directory: {
      type: Boolean,
      default: false
    },
    /* 是否可截图 当上传类型为图片时 并且非上传文件和批量时有效 */
    cropper: {
      type: Boolean,
      default: false
    },
    /* 截图配置选项 当可截图时
     * ratio  默认比例 可选值  1 (1:1) 4 (4 : 3) 5 (5:4) 16 (16:9) 0 (自定义) 默认值: 4:3
     * isRatio 是否可更改比例 默认值: true
     */
    cropperOptions: {
      type: Object,
      default: () => null
    },
    /* 是否以图片类型展示 使用类型为'file'有效 */
    picture: {
      type: Boolean,
      default: false
    },
    /* 返回值格式 可选值: 'uid', 'fileName', 'file_name', 'icon', 'name', 'object_name', 'path', 'status', 'thumbUrl', 'type' 其中若需要type类型 默认赋值时需要传值 */
    resultFormat: {
      type: Array,
      default: () => []
    }
  },
  data () {
    return {
      isBeforeSure: false,
      isPreviewVisible: false,
      urlPreviewFiles: '',
      listFiles: [],
      strFileName: '',
      objFileFormat: {
        uid: '',
        fileName: '',
        file_name: '',
        icon: '',
        name: '',
        object_name: '',
        path: '',
        status: '',
        thumbUrl: ''
      }
    }
  },
  created () {
  },
  mounted () {
    // 默认有数据 进行默认处理并赋值
    if (this.value.length > 0) {
      this.setFileDefult(this.value).then(list => {
        this.listFiles = list
      })
    }
  },
  methods: {
    // 剪切完成
    handleCropperSuccess (data) {
      const file = this.base64ToFile(data, this.strFileName || 'def.png')
      this.sendMainFiles(file)
    },
    // 图片上传
    sendMainFiles (file) {
      /* 表单方式提交 const formData = new FormData() formData.append('upload', file); 留存 后期增加 */
      const _this = this
      // 获取文件和MD5文件加密
      this.setFilesMD5(file, (objFile) => {
        // 上传请求接口
        this.getSendFilesMessage(objFile).then(item => {
          // 判断文件是否已经存在
          if (item.upload_url) {
            // 文件未上传 则上传文件
            this.sendFiles(item, objFile).then(result => {
              _this.finshSendFile(item, file)
            }).catch(e => {
              console.error(e)
              _this.changeFiles({ file: {}, fileList: {} })
            })
          } else {
            // 文件存在 则复用当前文件
            _this.finshSendFile(item, file)
          }
        }).catch(e => {
          console.error(e)
          _this.changeFiles({ file: {}, fileList: {} })
        })
      })
    },
    // 触发上传事件
    customImgRequest (options) {
      if (this.isBeforeSure === false) return
      const file = options.file
      if (this.cropper && this.type === 'img' && !this.multiple && !this.directory) {
        const _URL = window.URL || window.webkitURL
        const src = _URL.createObjectURL(options.file)
        var { option } = this
        var target = Object.assign({}, option, { img: src })
        this.$refs['cropper'].edit(target, this.cropperOptions, function () { _URL.revokeObjectURL(src) })
        this.strFileName = file.name
      } else {
        this.sendMainFiles(file)
      }
    },
    // 上传状态改变
    changeFiles (info) {
      // 将当前文件列表数据 赋值到控件状态
      const fileList = info.fileList = this.listFiles
      // 当前操作文件的d状态为 加载中
      if (info.file.status === 'uploading') {
        this.listFiles = fileList
        return
      }
      // 当前操作文件的状态为 已完成
      if (info.file.status === 'done') {
        this.listFiles = info.fileList = this.setFileList(fileList)
        if (this.type === 'img' && info.file.thumbUrl) {
          this.$nextTick(() => {
            setTimeout(() => {
              const _URL = window.URL || window.webkitURL
              _URL.revokeObjectURL(info.file.thumbUrl)
            }, 500)
          })
        }
      }
      // 当前操作文件的状态为 删除时 移除文件列表
      if (info.file.status === 'removed') {
        this.listFiles = info.fileList = this.deleteFileList(this.listFiles, info.file)
      }
      this.$emit('setImgList', this.listFiles)
    },
    // 图片 文件上传之前验证
    beforeImgUpload (file) {
      // 自定义的后缀或者类型验证
      if (this.verifyType !== null) {
        if (this.verifyType[0] !== "all") {
          const arrTypeSuffix = file.name.split('.')
          const typeSuffix = arrTypeSuffix[arrTypeSuffix.length - 1]
          if (!this.verifyType.includes(file.type) && !this.verifyType.includes(typeSuffix)) {
            this.$notification.warn({ message: '系统提示', description: '只能上传' + this.verifyType.join(',') + '格式的文件!', duration: 3 })
            this.isBeforeSure = false
            return
          }
        }
      // 如果没有自定义 则根据组件类型进行验证
      } else {
        // 图片类型验证
        if (this.type === 'img') {
          if (file.type !== 'image/png' && file.type !== 'image/jpg' && file.type !== 'image/jpeg') {
            this.$notification.warn({ message: '系统提示', description: '只能上传jpeg,png,jpg格式的图片!', duration: 3 })
            this.isBeforeSure = false
            return
          }
        // 文件类型验证
        } else if (this.type === 'file') {
          if (file.type !==
            'text/plain' && file.type !== 'application/pdf' && file.type !== 'application/vnd.ms-excel' && file.type !==
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' && file.type !== 'application/msword' &&
            file.type !== 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
            this.$notification.warn({
              message: '系统提示',
              description: '只能上传txt,doc,xls,pdf格式的文档!',
              duration: 3
            })
            this.isBeforeSure = false
            return
          }
        // 视频类型验证
        } else if (this.type === 'video') {
          if (file.type !==
            'audio/x-ms-wma' && file.type !== 'audio/x-ms-wmv' && file.type !== 'video/mp4' && file.type !==
            'video/x-msvideo' && file.type !== 'video/x-flv' && file.type !== 'application/vnd.rn-realmedia-vbr' &&
            file.type !== 'application/vnd.rn-realmedia' && file.type !== 'video/mpeg') {
            this.$notification.warn({
              message: '系统提示',
              description: '只能上传wma,wmv,mp4,avi,flv,rmvb,rm,mpeg格式的视频!',
              duration: 3
            })
            this.isBeforeSure = false
            return
          }
        }
      }
      // 文件大小验证
      const isLt2M = file.size / 1024 / 1024
      if (isLt2M > this.maxSizes) {
        this.$notification.warn({ message: '系统提示', description: '文件大小不能超过' + this.maxSizes + 'M!', duration: 3 })
        this.isBeforeSure = false
        return
      }
      this.isBeforeSure = true
    },
    // 删除文件
    deleteFileList (fileList, file) {
      const index = fileList.indexOf(file)
      const newFileList = fileList.slice()
      newFileList.splice(index, 1)
      return newFileList
    },
    // 关闭预览
    handlePreviewCancel () {
      this.isPreviewVisible = false
    },
    // 预览
    handlePreview (file) {
      if (['img', 'video'].includes(this.type)) {
        this.urlPreviewFiles = file.url || file.path
        this.isPreviewVisible = true
      }
    },
    /* 转换文件格式
     * 将文件转格式转换为原始文件格式、MD5格式、buffer格式。
     * @param {file} 文件
     * @param {function} 转换完成后的回调函数
     * @param {number=} p3 参数3的说明（可选）
     * @callback {Object} {md5File: MD5文件格式,bufferFile: buffer文件格式,file: 文件格式}
     */
    setFilesMD5 (file, callbackFunction) {
      var fileReader = new FileReader()
      var spark = new SparkMD5.ArrayBuffer()
      fileReader.readAsArrayBuffer(file)
      fileReader.onload = function (e) {
        const bufferFile = e.target.result
        spark.append(bufferFile)
        callbackFunction({
          md5File: spark.end(),
          bufferFile: bufferFile,
          file: file
        })
      }
    },
    // 获取上传文件信息请求接口
    getSendFilesMessage (objFile) {
      return new Promise((resolve, reject) => {
        // 如果为私密文件 必须带token
        const headers = {
          'credentials': 'same-origin',
          'content-type': 'application/json'
        }
        if (this.protected !== 'PUBLIC' && !this.tokenUser) {
          this.$message.warning('上传私密文件需要登录后上传')
          reject(new Error('上传私密文件需要登录后上传'))
          return
        }
        if (this.tokenUser) {
          headers['authorization'] = 'Bearer ' + this.tokenUser
        }
        // 请求上传信息
        fetch(this.urlUpload, {
          method: 'POST',
          headers: headers,
          body: JSON.stringify({
            md5: objFile.md5File,
            file_name: objFile.file.name,
            file_size: objFile.file.size,
            protected_level: this.protected
          })
        }).then(response => {
          response.text().then((data) => {
            try {
              if (data && JSON.parse(data) && JSON.parse(data).data) {
                // 返回请求值
                resolve(JSON.parse(data).data)
              } else {
                reject(new Error('获取上传信息失败'))
              }
            } catch (e) {
              reject(e)
            }
          })
        }).catch(e => {
          console.error(e)
          reject(new Error('获取上传信息失败'))
        })
      })
    },
    // 上传文件
    sendFiles (item, objFile) {
      return new Promise((resolve, reject) => {
        // 如果为私密文件 必须带token
        fetch(item.upload_url, {
          method: 'PUT',
          headers: item.headers,
          body: objFile.bufferFile
        }).then(response => {
          // 我这里加回调，如果回调失败了，OSS会给你报203
          if (response.status === 200 || response.status === 203) {
            response.text().then((data) => {
              resolve(JSON.parse(data))
            }).catch(e => {
              console.error(e)
              reject(e)
            })
          } else {
            reject(new Error('上传文件信息失败'))
          }
        }).catch(e => {
          console.error(e)
          reject(e)
        })
      })
    },
    // 文件上传成功
    async finshSendFile (item, file) {
      file.file_name = item.file_name
      file.object_name = item.object_name
      file.status = 'done'
      // 获取唯一Id
      file.uid = this.generateUUID()
      // 如果是图片或者是视频 生成缓存缩略图
      if (['img', 'video'].includes(this.type)) {
        const _URL = window.URL || window.webkitURL
        const src = _URL.createObjectURL(file)
        file.thumbUrl = this.type === 'video' ? await this.getVideoThumbUrl(src) : src
      }
      this.listFiles = [...this.listFiles, file]
      const info = { file: file, fileList: this.listFiles }
      this.changeFiles(info)
    },
    // 获取视频文件缩略图
    getVideoThumbUrl (src) {
      return new Promise((resolve, reject) => {
        const size = 160
        // 获取video节点
        const video = document.createElement('video')
        video.src = src
        video.width = size
        video.height = size
        video.currentTime = 1 // 第一帧
        const _this = this
        video.addEventListener('canplaythrough', function () {
          // 创建canvas对象
          const canvas = document.createElement('canvas')
          canvas.width = size
          canvas.height = size
          let img = ''
            // 利用canvas对象方法绘图
            _this.$nextTick(() => {
              canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height)
              _this.$nextTick(() => {
                // 转换成base64形式
                img = canvas.toDataURL('image/jpeg') // 这个就是图片的base64
                resolve(img)
                const _URL = window.URL || window.webkitURL
                _URL.revokeObjectURL(src)
              })
            })
        })
      })
    },
    // 将base64图片转为File文件类型
    base64ToFile (urlData, fileName) {
      var arr = urlData.split(',')
      var mime = arr[0].match(/:(.*?);/)[1]
      var bytes = atob(arr[1]) // 解码base64
      var n = bytes.length
      var ia = new Uint8Array(n)
      while (n--) {
        ia[n] = bytes.charCodeAt(n)
      }
      return new File([ia], fileName, { type: mime })
    },
    // 创建UUID
    generateUUID () {
      var d = new Date().getTime()
      var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = (d + Math.random() * 16) % 16 | 0
        d = Math.floor(d / 16)
        return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
      })
      return uuid
    },
    // 设置文件信息
    setFileList (fileList) {
      for (var i in fileList) {
        if (fileList[i].status === 'done') {
          if (!fileList[i].type) { continue }
          var url = this.urlShowFiles + fileList[i].object_name
          if (['img', 'video'].includes(this.type)) {
            fileList[i].url = url
          } else {
            // 文件默认显示图 暂未完成
            switch (fileList[i].type) {
              case 'text/plain':
                fileList[i].icon = 'TET'
                break
              case 'application/pdf':
                fileList[i].icon = 'PDF'
                break
              case 'application/vnd.ms-excel':
              case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
                fileList[i].icon = 'ECEL'
                break
              case 'application/msword':
                fileList[i].icon = 'WORD'
                break
              default:
                fileList[i].icon = 'zonghewendang'
            }
            fileList[i].thumbUrl = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(getSvgIcon(fileList[i].icon))))
          }
          fileList[i].path = url
          fileList[i].fileName = fileList[i].file_name
        }
      }
      return fileList
    },
    // 更换文件列表的icon
    setFileListIcon (list) {
      if (['img', 'video'].includes(this.type) || (this.type === 'file' && !this.picture)) return
      this.$nextTick(() => {
        if (list.length > 0) {
          const arrIcon = document.getElementsByClassName('ant-upload-list ant-upload-list-text')
          if (arrIcon.length > 0) {
            for (let i = 0; i < list.length; i++) {
              const svg = document.createElement('span')
              svg.style = 'position: absolute; left: 3px; top: 2px;'
              const icon = list[i].icon || 'icon-zonghewendang'
              svg.innerHTML = getSvgIcon(icon, '14', '14')
              const dom = arrIcon[0].children[i].getElementsByClassName('ant-upload-list-item-info')[0].children[0]
              dom.children[0].remove()
              dom.insertBefore(svg, dom.children[0])
            }
          }
        }
      })
    },
    // 根据后缀获取文件类型
    getTypeBySuffix (suffix) {
      switch (suffix) {
        case 'txt':
          return 'TET'
        case 'doc':
        case 'docx':
          return 'WORD'
        case 'xls':
        case 'xlsx':
          return 'ECEL'
        case 'pdf':
          return 'PDF'
        default:
          return 'zonghewendang'
      }
    },
    // 根据名称获取文件类型
    getTypeByFileName (strFileName) {
      if (!strFileName) return false
      const arrStrFileName = strFileName.split('.')
      return this.getTypeBySuffix(arrStrFileName[1])
    },
    // 获取文件缩略图
    getThubmUrlByIcon (icon) {
      return 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(getSvgIcon(icon))))
    },
    // 设置文件默认值
    async setFileDefult (list) {
        const listDefult = []
        for (var value of list) {
          const objItem = value
          if (!objItem['fileName'] && !objItem['file_name'] && !objItem['name'] && !objItem['object_name']) {
            console.error('fileName, file_name, name, object_name 需要传值其中的一个')
            return
          }
          if (!objItem['object_name'] && !objItem['path'] && !objItem['url']) {
            console.error('object_name, path, url 需要传值其中的一个')
            return
          }
          const item = await this.getFileUrl(this.urlShowFiles + objItem['object_name'] || objItem['path'] || objItem['url'])
          for (var index in this.objFileFormat) {
            if (!objItem[index]) {
              switch (index) {
                case 'fileName':
                  objItem[index] = objItem['file_name'] || objItem['name'] || item.fileName
                  break
                case 'file_name':
                  objItem[index] = objItem['fileName'] || objItem['name'] || item.fileName
                  break
                case 'name':
                  objItem[index] = objItem['fileName'] || objItem['file_name'] || item.fileName
                  break
                case 'status':
                  objItem[index] = 'done'
                  break
                case 'uid':
                  objItem[index] = this.generateUUID()
                  break
                case 'object_name':
                  objItem[index] = ''
                  break
                case 'path':
                  objItem[index] = objItem['url'] || this.urlShowFiles + objItem['object_name']
                  break
                case 'url':
                  objItem[index] = objItem['path'] || this.urlShowFiles + objItem['object_name']
                  break
                case 'icon':
                  // 在这获取icon 或者是在后续更改的时候 通过类型获取icon
                  objItem[index] = this.getTypeByFileName(objItem['fileName'] || objItem['file_name'] || item.fileName)
                  break
                case 'thumbUrl':
                  if (this.type === 'img') {
                    objItem[index] = item.src
                  }
                  if (this.type === 'file' && this.picture) {
                    objItem[index] = this.getThubmUrlByIcon(objItem['icon'])
                  }
                  if (this.type === 'video') {
                    objItem[index] = await this.getVideoThumbUrl(item.src)
                  }
                  break
              }
            }
          }
          listDefult.push(objItem)
        }
        return listDefult
    },
    // 下载文件 获取当前文件信息
    getFileUrl (srcFile) {
      return new Promise((resolve, reject) => {
        if (!srcFile) {
          resolve('没有文件路径')
          return
        }
        const headers = {}
        const item = {}
        let strFileName = ''
        if (this.tokenUser) headers['authorization'] = 'Bearer ' + this.tokenUser
        fetch(srcFile, {
          method: 'GET',
          headers: headers,
          responseType: 'blob'
        }).then(res => {
          const name = res.headers.get('Content-Disposition')
          strFileName = name ? name.split('filename=')[1] : this.generateUUID() + '.txt'
          strFileName = strFileName.replace(/"/g, '')
          const arrStrFileName = strFileName.split('.')
          item.fileName = `${decodeURI(arrStrFileName[0])}.${arrStrFileName[1]}`
          return res.blob()
        }).then(blob => {
          const _URL = window.URL || window.webkitURL
          item.src = _URL.createObjectURL(blob)
          resolve(item)
        })
      })
    }
  },
  watch: {
    // 监听组件默认值
    value (list) {
      if (this.listFiles.length !== list.length) {
        this.setFileDefult(list).then(r => {
          this.listFiles = r
        })
      }
    },
    // 当前值改变时给组件赋值
    listFiles (list) {
      // 值改变时 如果为文档 修改icon
      if (this.type === 'other' || (this.type === 'file' && !this.picture)) this.setFileListIcon(this.listFiles)
      // 是否为初始化值
      let listNew = []
      // 按照需求格式 格式化当前返回值
      if (this.resultFormat.length > 0) {
        list.forEach((item) => {
          var objItemNew = {}
          for (var i in item) {
            if (this.resultFormat.includes(i)) {
              objItemNew[i] = item[i]
            }
          }
          listNew.push(objItemNew)
        })
      } else {
        listNew = list
      }
      this.$emit('input', listNew)
      this.$emit('change', listNew)
    }
  }
}
</script>
<style lang="scss" scoped>
  ::v-deep .has-error .ant-upload{
    border: 1px solid #f522d0;
  }
  ::v-deep .ant-upload-list-picture-card .ant-upload-list-item-info::before{
    box-sizing: content-box;
    position: absolute;
    left: 0px !important;
    top: 0px !important;
  }
</style>
