<template>
  <div 
    class="component-upload-image" 
    @mouseenter="handleMouseEnter"
    @mouseleave="handleMouseLeave"
  >
    <el-upload
      multiple
      :action="uploadImgUrl"
      list-type="picture-card"
      :on-success="handleUploadSuccess"
      :before-upload="handleBeforeUpload"
      :limit="limit"
      :on-error="handleUploadError"
      :on-exceed="handleExceed"
      ref="imageUpload"
      :on-remove="handleDelete"
      :show-file-list="true"
      :headers="headers"
      :file-list="fileList"
      :on-preview="handlePictureCardPreview"
      :class="{hide: this.fileList.length >= this.limit}"
      class="image-upload"
      :style="cssVars"
      :data="uploadData"
      drag
    >
      <!-- 粘贴区域（隐藏） -->
      <textarea 
        ref="pasteArea"
        class="paste-area"
        @paste="handlePaste"
      ></textarea>
      <!-- 上传按钮 -->
      <i class="el-icon-plus"></i>
      <!-- 文件列表 -->
      <template #file="{ file }">
        <div :class="['el-upload-list__item', { 'is-file': !isImage(file.url) }]">
          <!-- 图片 -->
          <img v-if="isImage(file.url)"  class="el-upload-list__item-thumbnail " :src="file.url" alt=""/>
          <!-- 视频 -->
          <video v-else-if="isVideo(file.url)" class="el-upload-list__item-thumbnail" :src="file.url" alt=""/>
          <!-- 文件图标 -->
          <img v-else class="el-upload-list__item-thumbnail" :src="getFileIcon(file.url)" alt=""/>
          <!-- 操作按钮 -->
          <span class="el-upload-list__item-actions">
            <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
              <i class="el-icon-zoom-in"></i>
            </span>
            <span class="el-upload-list__item-delete" @click="handleDelete(file)">
              <i class="el-icon-delete"></i>
            </span>
          </span>
          <!-- 文件名 -->
          <div class="file-name-container">
            <el-tooltip :content="getDisplayFileName(file)" placement="bottom" :disabled="getDisplayFileName(file).length <= 10">
              <span class="file-name" :class="{'edit-name': editName}"  @click="editFileName(file)">
                <i v-if="editName" class="el-icon-edit"></i>
                {{ getDisplayFileName(file) }}
              </span>
            </el-tooltip>
          </div>
        </div>
      </template>
    </el-upload>

    <!-- 上传提示 -->
    <div class="el-upload__tip" slot="tip" v-if="showTip">
      请上传
      <template v-if="fileSize">大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b></template>
      <template v-if="fileType">格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b></template>
      的文件
      <br/>
      支持
      <b style="color: #f56c6c">拖动上传</b>
      和鼠标移入后
      <b style="color: #f56c6c">Ctrl+V</b>
      粘贴上传
    </div>

    <!-- 预览 -->
    <el-dialog :visible.sync="dialogVisible" title="预览" width="800" append-to-body>
      <video v-if="isVideo(dialogImageUrl)" :src="dialogImageUrl" controls style="display: block; max-width: 100%; margin: 0 auto"/>
      <img v-else :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto"/>
    </el-dialog>

  </div>
</template>

<script>
import { getToken } from '@/utils/auth'
import { getQiniuToken } from '@/api/common'
import axios from 'axios'
import { getRealUrl, getFileIcon, getExt, isImage, getFileNameWithTime, isVideo } from '@/utils'

export default {
  props: {
    value: [String, Object, Array],
    // 图片数量限制
    limit: {
      type: Number,
      default: 5,
    },
    // 大小限制(MB)
    fileSize: {
       type: Number,
      default: 200,
    },
    // 文件类型, 例如['png', 'jpg', 'jpeg']
    fileType: {
      type: Array,
      default: () => ["png", "jpg", "jpeg"],
    },
    // 是否显示提示
    isShowTip: {
      type: Boolean,
      default: true
    },
    width: {
      type: String,
      default: "148px"
    },
    height: {
      type: String,
      default: "148px"
    },
    // 上传地址，可选local、qiniu
    host: {
      type: String,
      default: "qiniu",
      validator: function (value) {
        return ['local', 'qiniu'].includes(value);
      }
    },
    // 是否可编辑文件名
    editName: {
      type: Boolean,
      default: false
    },
    // 值类型，可选string 字符串、array-string 字符串数组、array-object 对象数组
    valueType: {
      type: String,
      default: 'string',
      validator: function (value) {
        return ['string', 'array-string', 'array-object'].includes(value);
      }
    }
  },
  data() {
    return {
      number: 0,
      uploadList: [],
      dialogImageUrl: "",
      dialogVisible: false,
      hideUpload: false,
      baseUrl: process.env.VUE_APP_BASE_API,
      fileList: [],
      isListening: false,
      qiniuToken: null,
      uploadData: {},
    };
  },
  watch: {
    value: {
      handler(val) {
        if (val) {
          // 首先将值转为数组
          let list = [];
          if (Array.isArray(val)) {
            list = val;
          } else {
            list = val.split(',');
          }

          // 然后将数组转为对象数组
          this.fileList = list.map(item => {
            if (typeof item === "string") {
              return { 
                name: item,  // 保持原始名称，用于判断文件类型
                url: this.getRealUrl(item)
              };
            } else {
              return item;
            }
          });
        } else {
          this.fileList = [];
          return [];
        }
      },
      deep: true,
      immediate: true
    }
  },
  computed: {
    // 是否显示提示
    showTip() {
      return this.isShowTip && (this.fileType || this.fileSize);
    },
    // 计算样式
    cssVars() {
      return {
        '--width': this.width,
        '--height': this.height
      }
    },
    // 新增：获取文件图标的方法
    getFileIcon() {
      return (url) => {
        return getFileIcon(url);
      }
    },
    // 是否为图片
    isImage() {
      return (url) => {
        return isImage(url);
      }
    },
    // 是否为视频
    isVideo() {
      return (url) => {
        return isVideo(url);
      }
    },
    // 新增：获取显示的文件名
    getDisplayFileName() {
      return (file) => {
        let fileName = file.name;
        // 如果是URL格式，取最后一个斜杠后的值
        if (fileName.includes('/')) {
          fileName = fileName.split('/').pop();
        }
        return fileName;
      }
    },
    // 上传图片地址
    uploadImgUrl() {
      if (this.host === 'qiniu') {
        return 'https://up-z2.qiniup.com';
      }
      return process.env.VUE_APP_BASE_API + "/common/upload";
    },
    // 请求头
    headers() {
      if (this.host === 'local') {
        return {
          Authorization: "Bearer " + getToken(),
        };
      } 
      return {};
    },
  },
  methods: {
    editFileName(file) {
      if (!this.editName) {
        return;
      }
      this.$prompt('请输入文件名', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        inputPattern: /^[^<>]*$/,
        inputErrorMessage: '文件名不能包含<或>',
        inputValue: file.name,
      }).then(({ value }) => {
        file.name = value;
        this.emitInputValue();
      });
    },
    // 获取真实url
    getRealUrl,
    // 新增：鼠标进入处理
    handleMouseEnter() {
      if (!this.isListening) {
        if (this.$refs.pasteArea) {
          this.$refs.pasteArea.focus();
        }
        this.isListening = true;
      }
    },
    // 新增：鼠标离开处理
    handleMouseLeave() {
      if (this.isListening) {
        if (this.$refs.pasteArea) {
          this.$refs.pasteArea.blur();
        }
        this.isListening = false;
      }
    },
    // 粘贴图片上传
    handlePaste(event) {
      // 阻止默认行为
      event.preventDefault();
      
      const items = event.clipboardData?.items;
      
      if (!items) {
        this.$modal.msgError('当前浏览器不支持粘贴上传');
        return;
      }

      let file = null;
      for (let i = 0; i < items.length; i++) {
        if (items[i].type.indexOf('image') !== -1) {
          file = items[i].getAsFile();
          break;
        }
      }

      if (!file) {
        this.$modal.msgError('粘贴内容中不包含图片');
        return;
      }

      // 检查是否超出数量限制
      if (this.fileList.length >= this.limit) {
        this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);
        return;
      }

      this.uploadFile(file);
    },
    // 手动上传文件
    async uploadFile(file) {
        // 使用 handleBeforeUpload 进行文件验证
        const valid = await this.handleBeforeUpload(file);
        if (!valid) {
          return;
        }

        // 构建formData对象
        const formData = new FormData();
        formData.append('file', file);
        if (this.host === 'qiniu') {
          formData.append('key', this.uploadData.key);
          formData.append('token', this.uploadData.token);
        }

        // 发起上传请求
        try {
          const response = await axios.post(this.uploadImgUrl, formData, {
            headers: {
              ...this.headers,
              'Content-Type': 'multipart/form-data'
            }
          });
          
          this.handleUploadSuccess(response.data, file);
        } catch (error) {
          this.handleUploadError();
        } finally {
          this.$modal.closeLoading();
        }
    },
    // 上传前loading加载
    async handleBeforeUpload(file) {
      let isValid = false;
      let fileExtension = getExt(file.name);

      // 检查是否为允许的文件类型
      isValid = this.fileType.some(type => {
        if (file.type.indexOf(type) > -1) return true;
        if (fileExtension && fileExtension === type.toLowerCase()) return true;
        return false;
      });

      if (!isValid) {
        this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
        return false;
      }
      if (this.fileSize) {
        const isLt = file.size / 1024 / 1024 < this.fileSize;
        if (!isLt) {
          this.$modal.msgError(`上传文件大小不能超过 ${this.fileSize} MB!`);
          return false;
        }
      }
      this.number++;
      this.$modal.loading("正在上传文件，请稍候...");

      // 设置七牛云token
      if (this.host === 'qiniu') {
        let tokenRes = await getQiniuToken();
        if (tokenRes.code === 200) {
          this.uploadData.key = getFileNameWithTime(file.name);
          this.uploadData.token = tokenRes.data;
        }
      }

      return true;
    },
    // 文件个数超出
    handleExceed() {
      this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);
    },
    // 上传成功回调
    handleUploadSuccess(res, file) {
      if (this.host === 'qiniu') {
        // 七牛云返回的是文件信息
        this.uploadList.push({ 
          name: res.key,
          url: process.env.VUE_APP_QINIU_DOMAIN + '/' + res.key // 需要配置七牛云域名
        });
        this.uploadedSuccessfully();
      } else {
        if (res.code === 200) {
          this.uploadList.push({ 
            name: file.name,  // 保持原始文件名
            url: res.fileName  // 保持原始返回的URL
          });
          this.uploadedSuccessfully();
        } else {
          this.number--;
          this.$modal.closeLoading();
          this.$modal.msgError(res.msg);
          this.$refs.imageUpload.handleRemove(file);
          this.uploadedSuccessfully();
        }
      }
    },
    // 删除图片
    handleDelete(file) {
      const findex = this.fileList.map(f => f.name).indexOf(file.name);
      if (findex > -1) {
        this.fileList.splice(findex, 1);
        this.emitInputValue();
      }
    },
    // 发送input事件
    emitInputValue() {
        // 若value是字符串，则将fileList转为字符串
        if (this.valueType === 'string') {
          this.$emit("input", this.listToString(this.fileList));
        }
        // 若value是字符串数组，则将fileList转为字符串数组
        else if (this.valueType === 'array-string') {
          this.$emit("input", this.fileList.map(f => f.url));
        }
        // 若value是对象数组，则直接返回
        else if (this.valueType === 'array-object') {
          this.$emit("input", this.fileList);
        }
    },
    // 上传失败
    handleUploadError() {
      this.$modal.msgError("上传文件失败，请重试");
      this.$modal.closeLoading();
    },
    // 上传结束处理
    uploadedSuccessfully() {
      if (this.number > 0 && this.uploadList.length === this.number) {
        this.fileList = this.fileList.concat(this.uploadList);
        this.uploadList = [];
        this.number = 0;
        this.emitInputValue();
        this.$modal.closeLoading();
      }
    },
    // 预览
    handlePictureCardPreview(file) {
      const fileUrl = file.url;
      if (!this.isImage(file.name) && !this.isVideo(file.name)) {
          this.downloadFile(file);
      } else {
        // 图片文件使用原有的预览方式
        this.dialogImageUrl = fileUrl;
        this.dialogVisible = true;
      }
    },
    // 新增：下载文件方法
    downloadFile(file) {
      const link = document.createElement('a');
      link.href = file.url;
      link.download = this.getDisplayFileName(file);
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    },
    // 对象转成指定字符串分隔
    listToString(list, separator) {
      let strs = "";
      separator = separator || ",";
      for (let i in list) {
        if (list[i].url) {
          strs += list[i].url.replace(this.baseUrl, "") + separator;
        }
      }
      return strs != '' ? strs.substr(0, strs.length - 1) : '';
    }
  }
};
</script>
<style scoped lang="scss">
/* 上传区域基础样式 */
::v-deep .el-upload {
  display: flex;
  justify-content: center;
  align-items: center;
}

/* 上传按钮样式 */
::v-deep .el-upload--picture-card {
  width: var(--width);
  height: var(--height);
}

/* 隐藏上传按钮 */
::v-deep.hide .el-upload--picture-card {
  display: none;
}

/* 已上传图片项样式 */
::v-deep .el-upload-list__item {
  position: relative;
  overflow: hidden;
  width: var(--width);
  height: var(--height);
  .el-upload-list__item-thumbnail {
    object-fit: cover;
    object-position: center;
  }
  
  &.is-file {
    .el-upload-list__item-thumbnail {
      padding: 20px;
      background-color: #f5f7fa;
      object-fit: contain;
    }
  }

  &:hover {
    .el-upload-list__item-actions {
      opacity: 1;
    }
  }

  .el-upload-list__item-actions {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    color: #fff;
    opacity: 0;
    font-size: 20px;
    background-color: rgba(0, 0, 0, 0.5);
    cursor: default;
    text-align: center;
    transition: opacity .3s;
    
    .el-upload-list__item-delete {
      position: static;
      font-size: inherit;
      color: inherit;
      margin: 0 8px;
    }

    .el-icon-delete {
      cursor: pointer;
    }

    .el-icon-zoom-in {
      cursor: pointer;
    }
  }
}

/* 拖拽上传区域样式 */
::v-deep .el-upload-dragger {
  width: var(--width);
  height: var(--height);
  display: flex;
  justify-content: center;
  align-items: center;
}

/* 文件类型图标样式 */
.file-icon {
  width: 48px;
  height: 48px;
  margin: 0 auto;
}

/* 文件名容器样式 */
.file-name-container {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(0, 0, 0, 0.5);
  padding: 4px;
  text-align: center;
  z-index: 1;
}

/* 文件名样式 */
.file-name {
  color: #fff;
  font-size: 12px;
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: 0 4px;
}

.edit-name {
  cursor: pointer;
  &:hover {
    color: #409EFF;
  }
}

/* 调整列表动画时间 */
::v-deep .el-list-enter-active {
  transition: all 0.1s;
}

::v-deep .el-list-leave-active {
  transition: all 0.1s;
}

/* 确保列表项立即靠左显示 */
::v-deep .el-upload-list--picture-card {
  .el-upload-list__item {
    transition: none;
  }
}

/* 粘贴区域样式 */
.paste-area {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
  z-index: 1;
}
</style>

