<template>
  <div class="upload-container">
    <div class="fileUpload">
      <div class="item-upload">
        <span v-if="required" class="required">*</span>
        <n-button type="success" onclick="document.getElementById('fpfileName').click()">
          文件选择
        </n-button>
        <!-- <el-button type="primary" οnclick="document.getElementById('fpfileName').click()">文件选择</el-button> -->
        <input
          type="file"
          id="fpfileName"
          class="file2"
          style="display: none"
          @change="selectFile"
        />
      </div>
      <div v-if="showFileName" class="item-info">
        {{ fileName }}
      </div>
      <div v-else class="item-info">支持{{ getAcceptType() }}文件格式</div>
      <div v-if="progress > 0" class="item-cancel">
        <n-button type="success" style="margin-top: 5px" @click="cancelUploadInfo">
          X
        </n-button>
      </div>
    </div>
    <div class="item-process" v-if="progress > 0">
      <n-progress
        type="line"
        :percentage="progress"
        indicator-placement="inside"
        processing
      />
      <!-- <el-progress :text-inside="true" :stroke-width="20" :percentage="progress"/> -->
    </div>
    <div v-if="requiredValid" class="item-valid">请上传文件</div>
  </div>
</template>
<script>
// import { message } from 'element-plus';
// import { request } from "http";
import { defineComponent, onMounted, reactive, toRefs } from "vue";
export default defineComponent({
  name: "file-upload",
  props: {
    //文件接受类型
    accept: {
      type: Array,
      default: ["doc", "docx", "pdf", "safetensors", "ckpt"],
    },
    //是否必填
    required: {
      type: Boolean,
      default: false,
    },
    //文件限制大小
    fileSize: {
      type: Number,
      default: 2000,
    },
  },
  setup(props) {
    const data = reactive({
      file: null,
      fileName: "",
      fileSize: 0,
      progress: 0,
      objectKey: "",
      chunkSize: 5 * 1024 * 1024,
      totalChunks: 0,
      currentChunk: 1,
      uploadId: "",
      partArr: [],
      showFileName: false,
      bucketName: "",
      objectKeyName: "",
      required: props.required,
      requiredValid: false,
    });
    const message = useMessage();

    // 选择文件
    const selectFile = async (event) => {
      data.file = event.target.files[0];
      event.target.value = "";
      if (data?.file?.size) {
        const fileSize = Math.round((data?.file?.size / 1024 / 1024) * 100) / 100;
        if (fileSize > props.fileSize) {
          message.warning("文件大小超过上限" + props.fileSize + "MB");
          return;
        }
        data.fileSize = fileSize;
        console.log(data.fileSize);
        const fileName = data.file.name;
        const index = fileName.lastIndexOf(".");
        const fileType = fileName.substring(index + 1, fileName.length);
        if (!props.accept.includes(fileType)) {
          message.warning("文件类型不支持");
          return;
        }
        data.progress = 0;
        data.fileName = data.file.name;
        data.showFileName = true;
        data.totalChunks = Math.ceil(data.file.size / data.chunkSize);
        data.objectKey = guid() + "." + fileType;
        const res = await request.get("/file/getUploadId/" + data.objectKey);
        data.uploadId = res.data;
        data.progress = 1;
        uploadFile();
        // getUploadId(data.objectKey).then((res)=>{
        //     data.uploadId = res.data
        //     data.progress = 1;
        //     uploadFile();
        // })
      }
    };

    // 文件上传
    const uploadFile = async () => {
      const index = data.currentChunk - 1;
      const start = index * data.chunkSize;
      const end = Math.min((index + 1) * data.chunkSize, data.file.size);
      const formData = new FormData();
      formData.append("file", data.file.slice(start, end));
      formData.append("chunk", data.currentChunk);
      formData.append("objectKey", data.objectKey);
      formData.append("uploadId", data.uploadId);
      // 调用后端接口上传切片数据
      try {
        const res = await request.post("/file/chunk", formData, {
          headers: {
            "Content-Type": "multipart/form-data",
          },
        });
        data.partArr.push(res.data);
        console.log(data.progress);
        data.currentChunk++;
        data.progress = Math.floor((data.currentChunk / data.totalChunks) * 100);
        if (data.currentChunk <= data.totalChunks) {
          uploadFile();
        } else {
          // 所有切片上传完成
          data.progress = 99;
          console.log(data.progress);
          complete();
        }
      } catch (err) {
        initParam();
        console.error("切片上传失败：", error);
        message.warning("文件上传异常或上传已取消");
      }
      // uploadFileInfo(formData).then((res) => {
      //     data.partArr.push(res.data)
      //     console.log(data.progress)
      //     data.currentChunk++;
      //     data.progress = Math.floor((data.currentChunk / data.totalChunks) * 100);
      //     if (data.currentChunk <= data.totalChunks) {
      //         uploadFile();
      //     } else {
      //         // 所有切片上传完成
      //         data.progress = 99;
      //         console.log(data.progress)
      //         complete();
      //     }
      // }).catch((error) => {
      //     initParam()
      //     console.error('切片上传失败：', error);
      //     message.warning("文件上传异常或上传已取消")
      // });
    };

    // 上传完成并合并分段上传
    const complete = async () => {
      try {
        const res = await request.post(
          `/file/completeUpload?objectKey=${data.objectKey}&uploadId=${data.uploadId}`,
          data.partArr
        );
        console.log("文件上传完成");
        console.log(res);
        data.bucketName = res.data.bucketName;
        data.objectKeyName = res.data.objectKey;
        data.progress = 100;
        initParam();
      } catch (err) {
        console.error("文件上传失败：", error);
        message.warning('"文件上传失败"');
      }
      // completeUpload(data.partArr,data.objectKey,data.uploadId).then((res) => {
      //     console.log('文件上传完成');
      //     console.log(res);
      //     data.bucketName = res.data.bucketName
      //     data.objectKeyName = res.data.objectKey
      //     data.progress = 100;
      //     initParam()
      // }).catch((error) => {
      //     console.error('文件上传失败：', error);
      //     message.error("文件上传失败")
      // });
    };

    // 取消上传
    const cancelUploadInfo = () => {
      if (data.progress !== 100) {
        cancelUpload(data.objectKey, data.uploadId).then(() => {
          data.progress = 0;
          data.showFileName = false;
          initParam();
        });
      } else {
        data.progress = 0;
        data.showFileName = false;
        initParam();
      }
    };

    const getAcceptType = () => {
      let str = "";
      if (props.accept) {
        for (let item of props.accept) {
          str += item + ",";
        }
      }
      return str.substr(0, str.length - 1);
    };

    // 构建uuid
    const guid = () => {
      return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
        var r = (Math.random() * 16) | 0,
          v = c == "x" ? r : (r & 0x3) | 0x8;
        return v.toString(16);
      });
    };

    // 初始化参数
    const initParam = () => {
      data.file = null;
      data.objectKey = "";
      data.totalChunks = 0;
      data.currentChunk = 1;
      data.uploadId = "";
      data.partArr = [];
      data.requiredValid = false;
    };

    // 必传校验
    const validRequired = () => {
      if (data.bucketName && data.objectKeyName) {
        data.requiredValid = false;
        return true;
      } else {
        data.requiredValid = true;
        return false;
      }
    };

    // 返回上传结果 桶名称、文件名、文件大小
    const getUploadInfo = () => {
      return {
        bucketName: data.bucketName,
        fileName: data.objectKeyName,
        fileSize: data.fileSize,
      };
    };

    // 初始化
    onMounted(() => {
      data.progress = 0;
    });

    return {
      ...toRefs(data),
      selectFile,
      uploadFile,
      getAcceptType,
      validRequired,
      getUploadInfo,
      cancelUploadInfo,
    };
  },
});
</script>
<style scoped>
.upload-container {
  .fileUpload {
    display: flex;
    flex-direction: row;
    padding: 0px 8px;
    .item-upload {
      width: 100px;
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
      .required {
        color: red;
        padding: 0px 5px;
      }
    }
    .item-info {
      flex: 1;
      padding-top: 12px;
      font-size: 13px;
    }
    .item-cancel {
      width: 30px;
      padding-right: 20px;
    }
  }
  .item-process {
    margin-top: 5px;
    padding: 0px 23px;
    box-sizing: border-box;
  }
  .item-valid {
    color: red;
    padding: 0px 10px;
    font-size: 13px;
  }
}
</style>
