| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- <template>
- <view class="video-uploader">
- <up-upload
- :file-list="fileList"
- :max-count="maxCount"
- accept="video"
- :preview-full-image="false"
- :max-size="maxSize * 1024 * 1024"
- @after-read="handleAfterRead"
- @delete="handleDelete"
- >
- <view class="upload-btn">
- <u-icon name="plus" size="32" color="#999"></u-icon>
- <text class="upload-text">{{
- fileList.length ? t("重新选择") : t("选择视频")
- }}</text>
- </view>
- </up-upload>
- <!-- 预览 -->
- <view v-if="fileList.length" class="preview">
- <video class="preview-video" :src="fileList[0].url" controls></video>
- </view>
- <!-- 上传进度 -->
- <u-line-progress
- v-if="uploading"
- :percentage="progress"
- stroke-width="6"
- active-color="#3c9cff"
- :show-text="true"
- class="preview"
- />
- </view>
- </template>
- <script setup>
- import { ref, watch } from "vue";
- import { $uploadFile, Toast } from "@/utils";
- import { t } from "@/locale";
- const props = defineProps({
- // 初始图片列表
- modelValue: {
- type: Array,
- default: () => [],
- },
- // 最大上传数量
- maxCount: {
- type: Number,
- default: 1,
- },
- maxSize: {
- type: Number,
- default: 50,
- },
- // 是否多选
- multiple: {
- type: Boolean,
- default: false,
- },
- disabled: {
- type: Boolean,
- default: false,
- },
- // 上传按钮文字
- uploadText: {
- type: String,
- default: "上传图片",
- },
- });
- const fileList = ref([]);
- const uploading = ref(false);
- const progress = ref(0);
- const emit = defineEmits(["update:modelValue", "success", "delete", "error"]);
- watch(
- () => props.modelValue,
- (newVal) => {
- fileList.value = newVal.map((item) => {
- return typeof item === "string" ? { url: item } : item;
- });
- },
- { immediate: true }
- );
- /**
- * 文件选择后处理
- */
- const handleAfterRead = async (event) => {
- const file = Array.isArray(event.file) ? event.file[0] : event.file;
- uploading.value = true;
- progress.value = 0;
- try {
- const uploadFiles = Array.isArray(file) ? file : [file];
- const results = await Promise.all(
- uploadFiles.map((file) => {
- return $uploadFile({
- filePath: file.url,
- name: "file",
- onProgress(e) {
- progress.value = e.progress;
- },
- });
- })
- );
- const newFiles = results.map((res) => ({
- url: res.data.url,
- name: res.data.name,
- status: "success",
- }));
- fileList.value = [...fileList.value, ...newFiles];
- emit("update:modelValue", fileList.value);
- emit("success", newFiles);
- Toast(t("成功"));
- } catch (error) {
- emit("error", error);
- Toast(t("失败"));
- } finally {
- uploading.value = false;
- }
- };
- const handleDelete = (event) => {
- const { index } = event;
- const deletedFile = fileList.value[index];
- fileList.value.splice(index, 1);
- progress.value = 0;
- emit("update:modelValue", fileList.value);
- emit("delete", deletedFile);
- };
- defineExpose({
- clearFiles: () => {
- fileList.value = [];
- progress.value = 0;
- emit("update:modelValue", []);
- },
- });
- </script>
- <style lang="less" scoped>
- .video-uploader {
- padding: 10rpx;
- .upload-btn {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- width: 150rpx;
- height: 150rpx;
- border: 1px dashed #c0c4cc;
- border-radius: 8rpx;
- background-color: #f5f7fa;
- .upload-text {
- margin-top: 10rpx;
- font-size: 24rpx;
- color: #909399;
- }
- }
- .preview {
- margin-top: 20rpx;
- .preview-video {
- width: 100%;
- max-height: 200rpx;
- border-radius: 12rpx;
- background-color: #000;
- }
- }
- }
- </style>
|