UploadVideoPopup.vue 3.43 KB
<template>
  <van-popup
    v-model:show="show"
    position="bottom"
    :style="{ height: '100%' }"
  >
    <div class="upload-video-popup">
      <van-nav-bar
        title="上传视频"
        left-text="取消"
        right-text="提交"
        @click-left="onCancel"
        @click-right="onSubmit"
      />

      <div class="upload-content">
        <van-uploader
          :max-count="1"
          :max-size="maxSize"
          :before-read="beforeRead"
          :after-read="afterRead"
          accept="video/*"
          @oversize="onOversize"
        >
          <van-button type="default">请选择视频</van-button>
        </van-uploader>

        <div v-if="uploadProgress > 0 && uploadProgress < 100" class="progress">
          <van-progress :percentage="uploadProgress" :show-pivot="true" />
        </div>

        <div v-if="videoUrl" class="video-preview">
          <VideoPlayer :video-url="videoUrl" :autoplay="false" />
        </div>
      </div>
    </div>
  </van-popup>
</template>

<script setup>
import { ref, defineProps, defineEmits, watch } from 'vue';
import { showToast } from 'vant';
import VideoPlayer from '@/components/ui/VideoPlayer.vue';
import { v4 as uuidv4 } from 'uuid';

const props = defineProps({
  modelValue: {
    type: Boolean,
    required: true
  }
});

const emit = defineEmits(['update:modelValue', 'submit', 'cancel']);

const show = ref(false);

watch(() => props.modelValue, (newVal) => {
  show.value = newVal;
  if (newVal) {
    // 重置所有状态
    videoUrl.value = '';
    videoId.value = '';
    videoName.value = '';
    uploadProgress.value = 0;
  }
});

watch(show, (newVal) => {
  emit('update:modelValue', newVal);
});

const videoUrl = ref('');
const videoId = ref('');
const videoName = ref('');
const uploadProgress = ref(0);
const maxSize = 100 * 1024 * 1024; // 100MB

const beforeRead = (file) => {
  if (!file.type.includes('video/')) {
    showToast('请上传视频文件');
    return false;
  }
  return true;
};

const afterRead = async (file) => {
  const formData = new FormData();
  formData.append('file', file.file);

  try {
    // 模拟上传进度
    const timer = setInterval(() => {
      uploadProgress.value += 10;
      if (uploadProgress.value >= 100) {
        clearInterval(timer);
        // 模拟上传成功后的视频URL
        videoUrl.value = URL.createObjectURL(file.file);
        videoId.value = uuidv4();
        videoName.value = file.file.name;
      }
    }, 300);

    // TODO: 实际的上传逻辑
    // const response = await uploadVideo(formData);
    // videoUrl.value = response.data.url;
    // videoId.value = uuidv4();
    // videoName.value = file.file.name;
  } catch (error) {
    showToast('上传失败');
    console.error('Upload error:', error);
  }
};

const onOversize = () => {
  showToast('文件大小不能超过100MB');
};

const onSubmit = () => {
  if (!videoUrl.value || !videoId.value) {
    showToast('请先上传视频');
    return;
  }
  emit('submit', {
    url: videoUrl.value,
    id: videoId.value,
    name: videoName.value
  });
  emit('update:modelValue', false);
};

const onCancel = () => {
  emit('cancel');
  emit('update:modelValue', false);
};
</script>

<style scoped>
.upload-video-popup {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.upload-content {
  flex: 1;
  padding: 16px;
  overflow-y: auto;
}

.progress {
  margin: 16px 0;
}

.video-preview {
  margin-top: 16px;
  width: 100%;
  max-width: 600px;
}
</style>