<!--
  OSS 直传上传组件 Demo
  
  最小可运行示例，展示如何使用 file.ts 和 env.ts 实现文件直传阿里云 OSS。
  
  使用方式：
  1. 将 file.ts 和 env.ts 复制到你的项目中
  2. 安装 axios：npm install axios
  3. 在页面中引入此组件即可使用
-->
<template>
  <div class="upload-demo">
    <h2>阿里云 OSS 直传上传 Demo</h2>

    <!-- 文件选择 -->
    <div class="upload-area">
      <input
        type="file"
        ref="fileInput"
        @change="handleFileChange"
        accept="image/*,.pdf,.doc,.docx,.mp4,.mp3"
      />
      <button @click="handleUpload" :disabled="!selectedFile || uploading">
        {{ uploading ? "上传中..." : "上传文件" }}
      </button>
      <button
        v-if="uploading"
        @click="handleCancel"
        style="margin-left: 8px; color: red"
      >
        取消上传
      </button>
    </div>

    <!-- 进度条 -->
    <div v-if="uploading" class="progress-area">
      <div class="progress-bar">
        <div class="progress-fill" :style="{ width: progress + '%' }"></div>
      </div>
      <span>{{ progress }}%</span>
    </div>

    <!-- 上传结果 -->
    <div v-if="result" class="result-area">
      <p>上传成功！</p>
      <p>文件路径：{{ result.filePath }}</p>
      <p>文件大小：{{ (result.fileSize / 1024).toFixed(1) }} KB</p>
      <img
        v-if="result.filePath && isImage(result.fileName)"
        :src="result.filePath"
        alt="预览"
        style="max-width: 300px; margin-top: 8px"
      />
    </div>

    <!-- 错误信息 -->
    <div v-if="error" class="error-area">
      <p style="color: red">上传失败：{{ error }}</p>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
import { uploadFile } from "./file";

const fileInput = ref<HTMLInputElement>();
const selectedFile = ref<File | null>(null);
const uploading = ref(false);
const progress = ref(0);
const result = ref<{
  filePath: string;
  fileName: string;
  fileSize: number;
} | null>(null);
const error = ref<string>("");

// 取消控制器
let abortController: AbortController | null = null;

/** 判断是否为图片 */
function isImage(fileName: string): boolean {
  return /\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(fileName);
}

/** 文件选择事件 */
function handleFileChange(event: Event) {
  const target = event.target as HTMLInputElement;
  if (target.files && target.files.length > 0) {
    selectedFile.value = target.files[0];
    error.value = "";
    result.value = null;
  }
}

/** 开始上传 */
async function handleUpload() {
  if (!selectedFile.value) return;

  uploading.value = true;
  progress.value = 0;
  error.value = "";
  result.value = null;

  // 创建取消控制器
  abortController = new AbortController();

  try {
    const uploadResult = await uploadFile(selectedFile.value, "demo", {
      onProgress: (percent) => {
        progress.value = percent;
      },
      signal: abortController.signal,
    });

    result.value = {
      filePath: uploadResult.filePath,
      fileName: uploadResult.fileName,
      fileSize: uploadResult.fileSize,
    };
  } catch (err: any) {
    if (err.name === "CanceledError" || err.name === "AbortError") {
      error.value = "上传已取消";
    } else {
      error.value = err.message || "未知错误";
    }
  } finally {
    uploading.value = false;
    abortController = null;
  }
}

/** 取消上传 */
function handleCancel() {
  if (abortController) {
    abortController.abort();
    abortController = null;
  }
}
</script>

<style scoped>
.upload-demo {
  max-width: 500px;
  margin: 20px auto;
  padding: 20px;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
}

.upload-area {
  margin: 16px 0;
}

.progress-area {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 8px 0;
}

.progress-bar {
  flex: 1;
  height: 8px;
  background: #e0e0e0;
  border-radius: 4px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: #1890ff;
  transition: width 0.3s;
}

.result-area,
.error-area {
  margin-top: 16px;
  padding: 12px;
  border-radius: 4px;
}

.result-area {
  background: #f6ffed;
  border: 1px solid #b7eb8f;
}

.error-area {
  background: #fff2f0;
  border: 1px solid #ffccc7;
}

button {
  padding: 6px 16px;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  cursor: pointer;
  background: #fff;
}

button:hover:not(:disabled) {
  border-color: #1890ff;
  color: #1890ff;
}

button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
</style>
