<template>
  <div class="com-image-upload">
    <VueDraggable
      v-model="imageList"
      draggable=".image-item"
      class="flex items-start flex-wrap"
      @end="updateList"
    >
      <div
        v-for="(item, index) in imageList"
        :key="item.uid || index"
        class="image-item flex items-start"
        :style="{ width: width, height: height }"
      >
        <img
          :src="item.url"
          alt=""
          class=""
        />
        <div class="action-area flex items-center justify-center">
          <!-- 预览 -->
          <span
            v-if="!disablePreview"
            class="action-icon"
            @click="handlePictureCardPreview(item)"
          >
            <el-icon :size="32">
              <ZoomIn></ZoomIn>
            </el-icon>
          </span>
          <!-- 删除 -->
          <span
            class="action-icon"
            @click="handleRemove(index)"
          >
            <el-icon :size="32">
              <Delete></Delete>
            </el-icon>
          </span>
        </div>
      </div>
      <el-progress
        v-show="loading"
        type="circle"
        :percentage="uploadPercent"
        :width="Number(width.slice(0, width.length - 2))"
        style="margin: 8px"
      ></el-progress>
      <div
        class="upload-wrap"
        :class="{ hide: loading || imageList.length >= max }"
        :style="{ width: width, height: height }"
      >
        <el-upload
          ref="pictureUpload"
          :multiple="true"
          :limit="max"
          action=""
          drag
          accept=".jpg,.png,.jpeg"
          class="custom-upload-item"
          list-type="picture-card"
          :file-list="imageList"
          :show-file-list="false"
          :auto-upload="false"
          :on-preview="handlePictureCardPreview"
          :on-change="
            (file, fileList) => {
              handleUpload(file, fileList)
            }
          "
        >
          <el-icon :size="32">
            <Plus></Plus>
          </el-icon>
        </el-upload>
      </div>
    </VueDraggable>

    <el-dialog v-model="imageDialogVisible">
      <img
        width="100%"
        :src="imageUrl"
        alt=""
      />
    </el-dialog>
  </div>
</template>

<script lang="ts" setup>
import { defineComponent, ref, watch } from 'vue'
import { VueDraggable } from 'vue-draggable-plus'
import { ElMessage, ElUpload, ElIcon, ElProgress, ElDialog } from 'element-plus'
import { Plus, Delete, ZoomIn } from '@element-plus/icons-vue'
import { cloneDeep } from 'lodash'
import common from '@/api/common'
defineComponent({
  name: 'ImageUpload',
})
const {
  max = 16,
  list = [],
  disablePreview = false,
  width = '150px',
  height = '150px',
} = defineProps<{
  list: any[]
  max?: number
  disablePreview?: boolean
  width?: string
  height?: string
}>()
const $emit = defineEmits(['update:list'])

// 组件内部数据.
const imageList = ref([] as any[])
const loading = ref(false)
const uploadPercent = ref(0)
watch(
  () => list,
  () => (imageList.value = cloneDeep(list)),
)
const handleUpload = (file: any, fileList: any[]) => {
  if (file.status === 'ready') {
    loading.value = true
    const interval = setInterval(() => {
      if (uploadPercent.value >= 99) {
        clearInterval(interval)
        return
      }
      uploadPercent.value += 1 // 进度条进度
    }, 100)
  }

  const formData = new FormData() as any
  fileList.forEach((file) => {
    formData.append('file', file.raw)
  })
  formData.append('type', 1)
  common
    .imagesUpload(formData)
    .then((response: any) => {
      if (response.result.code === 200) {
        imageList.value.push({
          url: response.result.data,
          uid: file.uid,
        })

        updateList()
        return
      }
      ElMessage.warning(response.result.message)
    })
    .catch((error) => {
      console.log(error, 'component upload image error')
      ElMessage.error(error.response.data.msg)
    })
    .finally(() => {
      loading.value = false
      // 进度条恢复到初始状态
      uploadPercent.value = 0
    })
}
const handleRemove = (index: number) => {
  imageList.value.splice(index, 1)
  updateList()
}
const imageDialogVisible = ref(false)
// 预览大图的url, 每次点击都会更新
const imageUrl = ref('')
const handlePictureCardPreview = (file: any) => {
  imageUrl.value = file.url
  imageDialogVisible.value = true
}

// 每次更新imageList后手动更新父组件的数据, 不能用watch自动更新, 因为同时要watch prop值更新iamgeList, 同时watch会死循环.
// 直接把prop数据绑定到dragable 和 el-upload的话vue和eslint会报错, 也可能造成调试困难
const updateList = () => {
  $emit('update:list', cloneDeep(imageList.value))
}
</script>

<style lang="scss" scoped>
:deep(.el-upload) {
  border-style: solid;
  width: 100%;
  height: 100%;
}
:deep(.el-upload-dragger) {
  width: 100%;
  height: 100%;
  border: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.com-image-upload {
  vertical-align: top;
}
.image-item {
  overflow: hidden;
  position: relative;
  border: 1px solid #c0ccda;
  border-radius: 6px;
  margin-right: 8px;
  margin-bottom: 2px;
  img {
    width: 100%;
  }
  &:hover {
    .action-area {
      display: flex;
    }
  }
  .action-area {
    position: absolute;
    z-index: 1;
    left: 0;
    top: 0;
    display: none;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.7);
    color: #fff;
    font-size: 32px;
  }
  .action-icon {
    cursor: pointer;
    & + .action-icon {
      margin-left: 16px;
    }
  }
}
.upload-wrap {
  display: inline-block;
  position: relative;
  margin-bottom: 2px;
  &.hide {
    display: none;
  }
}
.custom-upload-item {
  width: 100%;
  height: 100%;
}
</style>
