<template>
|
<view class="cl-updata">
|
<view class="file-list" :style="[listRowStyle]">
|
|
<view v-for="(item, index) in previewList" @tap="clickSelectedFile(item, index)" class="file-list-row"
|
:style="[rowStyle]" :key="index">
|
|
<image
|
class="_image"
|
v-if="fileUrlType(item) === 'image'"
|
:src="item.path"
|
:style="[imgStyle]"
|
mode="aspectFill">
|
</image>
|
|
<view v-else class="_video" :style="[imgStyle]">
|
|
<!-- #ifdef MP-WEIXIN || MP-ALIPAY -->
|
<video
|
v-if="!autoUpload || cloudType === 'other'"
|
class="_video"
|
:style="[imgStyle]"
|
:src="item.path"
|
:show-center-play-btn="false"
|
:show-fullscreen-btn="false"
|
:show-play-btn="false"
|
:show-loading="false"
|
:enable-progress-gesture="false"
|
:controls="false">
|
<view @tap="previewVideo(item, index)" class="play">
|
<image style="width: 100%;" :src="playImg" mode="widthFix"></image>
|
</view>
|
</video>
|
|
<!-- #endif -->
|
|
<!-- #ifdef APP-PLUS -->
|
<video
|
v-if="cloudType === 'other'"
|
class="_video"
|
:style="[imgStyle]"
|
:src="item.path"
|
:poster="item.path"
|
:controls="false"
|
:show-center-play-btn="false"
|
:show-fullscreen-btn="false"
|
:show-play-btn="false"
|
:show-loading="false"
|
:enable-progress-gesture="false">
|
<cover-image class="app_play" :src="playImg" @tap="previewVideo(item, index)"></cover-image>
|
<cover-view class="remove" v-if="remove" @tap="deleteSelectedFile(item, index)">
|
<cover-image class="image" :src="deleteImg" mode="widthFix" @tap="deleteSelectedFile(item, index)"></cover-image>
|
</cover-view>
|
</video>
|
<!-- #endif -->
|
|
<!-- #ifndef MP-WEIXIN || MP-ALIPAY || APP-PLUS -->
|
<video
|
v-if="cloudType === 'other'"
|
class="_video"
|
:autoplay="false"
|
:style="[imgStyle]"
|
:src="item.path"
|
:controls="false"
|
:show-center-play-btn="false"
|
:show-fullscreen-btn="false"
|
:show-play-btn="false"
|
:show-loading="false"
|
:enable-progress-gesture="false" >
|
<cover-view @tap="previewVideo(item, index)" class="play">
|
<cover-image style="width: 100%;" :src="playImg" mode="widthFix"></cover-image>
|
</cover-view>
|
</video>
|
|
<!-- #endif -->
|
|
<template v-else>
|
<cl-image class="pay" :style="[imgStyle]" :cloudType="cloudType"
|
:src="(item.poster || item.path)"></cl-image>
|
|
<view class="play" @tap="previewVideo(item, index)">
|
<image class="play-img" :src="playImg" mode="widthFix"></image>
|
</view>
|
</template>
|
|
</view>
|
|
<view class="remove" v-if="remove" @tap.stop="deleteSelectedFile(item, index)">
|
<image class="image" :src="deleteImg" mode="widthFix"></image>
|
</view>
|
</view>
|
|
<view v-if="add && FileList.length < max" @tap="selectFileTypeOnAdd" :style="[rowStyle]" class="file-list-row">
|
<slot name="addImg">
|
<div class="add-image">
|
<image class="_image" :src="addImg" mode="widthFix"></image>
|
</div>
|
</slot>
|
</view>
|
</view>
|
|
|
<view v-if="tempVideoUrl" class="mask">
|
<image @tap="tempVideoUrl = ''" class="_root" :src="closeImg" mode="widthFix"></image>
|
|
<view class="block" @tap.stop>
|
<video class="block_video" autoplay :src="tempVideoUrl"></video>
|
</view>
|
</view>
|
</view>
|
</template>
|
|
<script>
|
import ClImage from '../cl-image/cl-image.vue'
|
export default {
|
name: "cl-upload",
|
components: { ClImage },
|
props: {
|
//受控图片列表
|
// #ifdef VUE2
|
value: {
|
type: Array,
|
default: () => [],
|
},
|
// #endif
|
|
// #ifdef VUE3
|
modelValue: {
|
type: Array,
|
default: () => [],
|
},
|
// #endif
|
|
// 存储云类型 oss阿里云 vframe七牛云 process腾讯云 other其他
|
cloudType: {
|
type: String,
|
default: 'oss'
|
},
|
// 标识符,即后端接口参数名
|
fileName: {
|
type: String,
|
default: 'file'
|
},
|
// 文件类型 'image', 'video', 'all'
|
fileType: {
|
type: String,
|
default: 'all'
|
},
|
// 上传图片参数
|
imageFormData: {
|
type: Object | null,
|
default: () => { }
|
},
|
// 上传视频参数
|
videoFromData: {
|
type: Object,
|
default: () => { }
|
},
|
|
// 必选参数,上传的地址
|
action: {
|
type: String,
|
default: ''
|
},
|
|
// 启用目录, 仅unicloud阿里云支持
|
// https://uniapp.dcloud.net.cn/uniCloud/storage.html#storage-dir
|
cloudPathAsRealPath: {
|
type: Boolean,
|
default: false
|
},
|
|
// 设置上传的请求头部
|
headers: {
|
type: Object,
|
default: () => { }
|
},
|
|
// 上传时附带的额外参数
|
data: {
|
type: Object,
|
default: () => { }
|
},
|
|
// 是否开启预览图片
|
isPreviewImage: {
|
type: Boolean,
|
default: true
|
},
|
|
// 图片指示器样式,可取值:"default" - 底部圆点指示器; "number" - 顶部数字指示器; "none" - 不显示指示器。
|
indicator: {
|
type: String,
|
default: 'none'
|
},
|
// 是否在选取文件后立即进行上传
|
autoUpload: {
|
type: Boolean,
|
default: true
|
},
|
// 是否显示删除按钮
|
remove: {
|
type: Boolean,
|
default: true
|
},
|
// 是否添加按钮
|
add: {
|
type: Boolean,
|
default: true
|
},
|
// 最多显示数量
|
max: {
|
type: Number,
|
default: 9
|
},
|
// 视频最大上传数量
|
maxVideo: {
|
type: Number,
|
default: 0
|
},
|
// 列表样式
|
listStyle: {
|
type: Object,
|
default: () => { }
|
},
|
// 删除提示弹窗标题
|
deleteTitle: {
|
type: String,
|
default: '提示'
|
},
|
// 删除提示弹窗文案
|
deleteText: {
|
type: String,
|
default: '您确认要删除吗?'
|
},
|
// 加载文案
|
loadingText: {
|
type: String,
|
default: '正在上传中...'
|
},
|
// 是否开启删除前钩子
|
useBeforeDelete: {
|
type: Boolean,
|
default: false
|
},
|
// 是否开启上传前钩子
|
useBeforeUpload: {
|
type: Boolean,
|
default: false
|
},
|
// 添加按钮图片
|
addImg: {
|
type: String,
|
default: 'https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/bb1550b3-e0a8-4a90-a86f-00f8c6afa9fb.png'
|
},
|
// 播放按钮图片
|
playImg: {
|
type: String,
|
default: 'https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/ae40402f-aa53-4344-b553-2322799bebd6.png'
|
},
|
// 删除按钮图片
|
deleteImg: {
|
type: String,
|
default: 'https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/d20177a5-417e-4c5d-a266-1988361c543d.png'
|
},
|
// 关闭视频按钮图片
|
closeImg: {
|
type: String,
|
default: 'https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/cde4362d-7ec7-4cac-a692-12e1f576be1e.png'
|
},
|
},
|
data() {
|
return {
|
// 渲染列表
|
FileList: [],
|
|
// 预览视频地址
|
tempVideoUrl: '',
|
|
// 临时文件列表
|
tempFile_paths: [],
|
|
};
|
},
|
watch: {
|
// #ifdef VUE2
|
'value': {
|
handler: function (newVal, oldVal) {
|
this.FileList = newVal;
|
},
|
deep: true,
|
immediate: true
|
},
|
// #endif
|
|
// #ifdef VUE3
|
'modelValue': {
|
handler: function (newVal, oldVal) {
|
this.FileList = newVal;
|
},
|
deep: true,
|
immediate: true
|
},
|
// #endif
|
},
|
computed: {
|
previewList() {
|
return this.FileList.map(item => {
|
return {
|
path: item.path || item,
|
poster: item.poster || ''
|
}
|
})
|
},
|
listRowStyle() {
|
const style = {
|
'grid-template-columns': `repeat(${this.listStyle?.columns || 4}, 1fr)`, // 每行数量
|
'grid-column-gap': this.listStyle?.columnGap || '40rpx', // 行间距
|
'grid-row-gap': this.listStyle?.rowGap || '40rpx', // 列间距
|
'padding': this.listStyle?.padding || '0rpx' // 列表内边距
|
}
|
|
return style;
|
},
|
rowStyle() {
|
const { height = '140rpx', ratio } = this.listStyle || {};
|
const style = {
|
'aspect-ratio': height ? '' : ratio || '1/1', // 图片比例
|
'height': height,
|
};
|
|
return style;
|
},
|
|
imgStyle() {
|
const style = {
|
'border-radius': this.listStyle?.radius || '6rpx', // 图片圆角
|
}
|
return style;
|
}
|
},
|
methods: {
|
/**
|
* 删除已选择文件
|
* @param {object} item 文件信息
|
* @param {number} selectedFileIndex 文件索引
|
* */
|
deleteSelectedFile(item, selectedFileIndex) {
|
|
const fileToDelete = this.FileList[selectedFileIndex];
|
|
// 删除前钩子
|
if (this.useBeforeDelete) {
|
this.$emit('beforeDelete', fileToDelete, selectedFileIndex, () => {
|
return deleteFileFromList()
|
})
|
}
|
|
if (!this.useBeforeDelete) {
|
uni.showModal({
|
title: this.deleteTitle,
|
content: this.deleteText,
|
success: (res) => {
|
if (res.confirm) {
|
deleteFileFromList()
|
}
|
}
|
});
|
}
|
|
const deleteFileFromList = () => {
|
const tempFileIndex = this.tempFile_paths.indexOf(item || item.path);
|
|
if (tempFileIndex > -1) {
|
this.tempFile_paths.splice(tempFileIndex, 1)
|
}
|
|
this.FileList.splice(selectedFileIndex, 1)
|
|
// #ifdef VUE2
|
this.$emit('input', this.FileList)
|
// #endif
|
|
// #ifdef VUE3
|
this.$emit("update:modelValue", this.FileList);
|
// #endif
|
}
|
|
},
|
|
/**
|
* 点击已选择文件
|
* @param {object} item 文件信息
|
* @param {number} index 文件索引
|
* */
|
clickSelectedFile(item, index) {
|
this.previewImage(item?.path ?? item, index);
|
this.$emit('onImage', {
|
item,
|
index
|
})
|
},
|
|
/**
|
* 点击选择图片按钮
|
* */
|
selectFileTypeOnAdd() {
|
|
switch (this.fileType) {
|
case 'image':
|
this.handleFileSelection(1);
|
break;
|
case 'video':
|
this.handleFileSelection(2);
|
break;
|
case 'all':
|
uni.showActionSheet({
|
itemList: ['相册', '视频'],
|
success: (res) => {
|
const tapIndex = res.tapIndex;
|
if (tapIndex === 0) {
|
this.handleFileSelection(1);
|
} else {
|
this.handleFileSelection(2);
|
}
|
},
|
fail: (res) => {
|
console.error(res.errMsg);
|
}
|
});
|
break;
|
default:
|
this.handleFileSelection(1);
|
break;
|
}
|
},
|
|
|
/**
|
* 从本地选择文件。
|
* @param { number } updataType 选择类型 1:图片 2视频
|
* */
|
async handleFileSelection(updataType) {
|
const that = this;
|
if (updataType === 1) {
|
|
const data = Object.assign({}, {
|
// 最多可以选择的图片张数,默认9
|
count: 9,
|
// 仅对 mediaType 为 image 时有效,是否压缩所选文件
|
// #ifndef MP-TOUTIAO
|
sizeType: ['original', 'compressed'],
|
// #endif
|
// album 从相册选图,camera 使用相机,默认二者都有。
|
sourceType: ['camera', 'album'],
|
|
compress: false
|
}, this.imageFormData)
|
|
data['count'] = this.max - this.FileList.length
|
|
uni.chooseImage({
|
...data,
|
success: async (res) => {
|
let tempFiles = res.tempFiles
|
const compress = that.imageFormData?.compress || false;
|
|
// 限制图片上传尺寸
|
if (that.imageFormData?.size ?? false) {
|
const maxSize = that.imageFormData.size * 1024 * 1024
|
|
tempFiles.map((imgInfo, index) => {
|
if (imgInfo.size > maxSize) {
|
tempFiles.splice(index, 1)
|
that.$emit('onImageSize', imgInfo)
|
return uni.showToast({
|
title: `图片最大上传${that.imageFormData.size}MB`,
|
duration: 2000,
|
icon: 'none'
|
});
|
}
|
})
|
}
|
|
// 开启压缩图片
|
if (compress) {
|
const compressedImagePathList = tempFiles.map(imageItem => {
|
return that.compressImage(imageItem.path)
|
})
|
|
Promise.all(compressedImagePathList).then(result => {
|
upload(result);
|
})
|
|
} else {
|
upload(tempFiles);
|
}
|
|
function upload(tempImages) {
|
if (that.autoUpload) {
|
tempImages.map(item => {
|
that.onBeforeUploadFile(item, 'image')
|
})
|
} else {
|
that.FileList = [...that.FileList, ...tempImages]
|
tempImages.map(item => {
|
that.tempFile_paths.push(item)
|
})
|
}
|
}
|
|
},
|
fail(err) {
|
console.error('选择图片失败', err)
|
that.$emit('onError', err)
|
}
|
|
})
|
}
|
|
if (updataType === 2) {
|
|
// 限制视频最大上传数量
|
const VIDEO_REGEXP = /\.(mp4|flv|avi)/i
|
const videoList = await that.FileList.filter(item => {
|
const fileUrl = item?.url ?? item
|
return VIDEO_REGEXP.test(fileUrl)
|
})
|
|
if (that.maxVideo > 0 && videoList.length >= that.maxVideo) {
|
that.$emit('onVideoMax', that.maxVideo, videoList.length)
|
return uni.showToast({
|
title: '视频数量已超出',
|
duration: 2000,
|
icon: 'none'
|
});
|
}
|
|
const data = Object.assign({}, {
|
// 拍摄视频最长拍摄时间,单位秒。最长支持 60 秒。
|
maxDuration: 60,
|
// #ifndef MP-TOUTIAO
|
// 'front'、'back',默认'back'
|
camera: "back",
|
// #endif
|
|
// album 从相册选视频,camera 使用相机拍摄,默认二者都有。
|
sourceType: ['camera', 'album'],
|
// 是否压缩所选的视频源文件,默认值为 true,需要压缩。
|
compressed: true,
|
// 'front'、'back',默认'back'
|
}, this.videoFromData)
|
|
uni.chooseVideo({
|
...data,
|
success: (res) => {
|
let tempFilePath = { ...res }
|
tempFilePath['path'] = res.tempFilePath
|
|
// 限制视频上传尺寸
|
if (that.videoFromData?.size ?? false) {
|
const maxSize = that.videoFromData.size * 1024 * 1024
|
|
if (tempFilePath.size > maxSize) {
|
uni.showToast({
|
title: `视频最大上传${that.videoFromData.size}MB`,
|
duration: 2000,
|
icon: 'none'
|
});
|
return false;
|
}
|
|
}
|
if (that.autoUpload) {
|
that.onBeforeUploadFile(tempFilePath, 'video')
|
} else {
|
that.FileList.push(tempFilePath)
|
that.tempFile_paths.push(tempFilePath)
|
}
|
},
|
fail(err) {
|
console.error('选择视频失败', err)
|
}
|
|
})
|
}
|
},
|
|
/**
|
* 上传前钩子
|
* @param { tempFile } 临时文件
|
* @return { Promise }
|
* */
|
onBeforeUploadFile(tempFile) {
|
if (this.useBeforeUpload) {
|
return this.$emit('beforeUpload', tempFile, () => {
|
return this.updataFile(tempFile);
|
})
|
}
|
return this.updataFile(tempFile);
|
},
|
|
/**
|
* 上传文件到服务器
|
* @param { tempFile } 临时文件
|
* @return { Promise }
|
* */
|
updataFile(tempFile) {
|
const that = this;
|
const filePath = tempFile.path || tempFile;
|
const fileType = this.fileUrlType(filePath) == 'image' ? '.png' : '.mp4';
|
const fileName = tempFile.name || Date.now() + fileType;
|
|
uni.showLoading({
|
title: this.loadingText,
|
icon: 'loading'
|
})
|
|
return new Promise((resolve, reject) => {
|
// uniCloud上传
|
if (that.action === 'uniCloud') {
|
|
uniCloud.uploadFile({
|
cloudPath: String(fileName),
|
filePath: filePath,
|
// #ifdef MP-ALIPAY
|
fileType: fileType,
|
// #endif
|
cloudPathAsRealPath: this.cloudPathAsRealPath,
|
|
onUploadProgress: (progressEvent) => {
|
const percentCompleted = Math.round(
|
(progressEvent.loaded * 100) / progressEvent.total
|
);
|
that.$emit('onProgress', percentCompleted)
|
},
|
success(result) {
|
if (that.autoUpload) {
|
that.FileList.push(result.fileID)
|
} else {
|
that.FileList.map((item, index) => {
|
if (item === filePath || item.path === filePath) {
|
that.FileList.splice(index, 1, result.fileID)
|
}
|
})
|
}
|
|
// #ifdef VUE2
|
that.$emit('input', that.FileList)
|
// #endif
|
// #ifdef VUE3
|
that.$emit("update:modelValue", that.FileList);
|
// #endif
|
|
resolve(result.fileID)
|
uni.hideLoading();
|
that.$emit('onProgress', {
|
...result
|
})
|
},
|
fail: (error) => {
|
uni.hideLoading();
|
console.error('error', error);
|
that.$emit('onError', error)
|
reject(error)
|
}
|
})
|
return false;
|
}
|
|
// 接口服务上传
|
const uploadTask = uni.uploadFile({
|
url: that.action,
|
filePath: filePath,
|
name: that.fileName,
|
formData: that.data,
|
header: that.headers,
|
// #ifdef MP-ALIPAY
|
fileType: filetype,
|
// #endif
|
success: (uploadFileRes) => {
|
const data = JSON.parse(uploadFileRes.data)
|
uni.hideLoading();
|
that.success(data)
|
|
if (!this.autoUpload) {
|
that.FileList.map((item, index) => {
|
if (item === filePath || item.path === filePath) {
|
that.FileList.splice(index, 1)
|
}
|
})
|
}
|
|
resolve(data)
|
},
|
fail: (error) => {
|
uni.hideLoading();
|
console.error('error', error);
|
that.$emit('onError', error)
|
reject(error)
|
}
|
});
|
|
uploadTask.onProgressUpdate((res) => {
|
that.$emit('onProgress', {
|
...res,
|
...tempFile
|
})
|
});
|
})
|
},
|
|
/**
|
* 手动上传
|
* */
|
submit() {
|
|
return new Promise((resolve, reject) => {
|
if (this.tempFile_paths.length <= 0) {
|
resolve([])
|
}
|
|
const uploadedFilePaths = this.tempFile_paths.map(item => {
|
return this.onBeforeUploadFile(item || item.path)
|
})
|
|
Promise.all(uploadedFilePaths).then(res => {
|
this.tempFile_paths = []
|
resolve(res)
|
}).catch(err => {
|
reject(err)
|
})
|
})
|
|
},
|
|
/**
|
* 返回数据
|
* @param {array} data 上传成功后的数据
|
* @return {array} 返回数据
|
* */
|
success(data) {
|
this.$emit('onSuccess', data);
|
|
// 自定义数据结构-选择性开启
|
// const list = data.map(item=> {
|
// return JSON.parse(item).data.link;
|
// })
|
// this.$emit('input', [...this.FileList, ...list]);
|
},
|
/**
|
* 压缩图片
|
* @param {array} tempFilePaths 临时路径数组
|
* @return {array} 被压缩过的路径数组
|
* */
|
async compressImage(tempFilePaths) {
|
const that = this;
|
|
return new Promise((resolve, reject) => {
|
|
if (typeof tempFilePaths !== 'string') {
|
console.error('压缩路径错误')
|
reject([])
|
}
|
|
uni.showLoading({
|
title: '压缩中...',
|
icon: 'loading',
|
})
|
|
// #ifdef H5
|
this.canvasDataURL(tempFilePaths, {
|
quality: that.imageFormData.quality / 100
|
}, (base64Codes) => {
|
resolve(base64Codes);
|
uni.hideLoading();
|
})
|
// #endif
|
|
// #ifndef H5
|
uni.compressImage({
|
src: tempFilePaths,
|
quality: that.imageFormData.quality || 80,
|
success: res => {
|
resolve(res.tempFilePath);
|
uni.hideLoading();
|
},
|
fail(err) {
|
reject(err);
|
uni.hideLoading();
|
}
|
})
|
// #endif
|
|
})
|
},
|
|
/**
|
* H5压缩图片质量
|
* @param {string} path 图片路径
|
* @param {object} obj 压缩配置
|
* @param {function} callback 回调函数
|
* @return {string} base64
|
* */
|
canvasDataURL(path, obj, callback) {
|
var img = new Image();
|
img.src = path;
|
img.onload = function () {
|
var that = this;
|
// 默认按比例压缩
|
var w = that.width,
|
h = that.height,
|
scale = w / h;
|
w = obj.width || w;
|
h = obj.height || (w / scale);
|
var quality = 0.8; // 默认图片质量为0.8
|
//生成canvas
|
var canvas = document.createElement('canvas');
|
var ctx = canvas.getContext('2d');
|
// 创建属性节点
|
var anw = document.createAttribute("width");
|
anw.nodeValue = w;
|
var anh = document.createAttribute("height");
|
anh.nodeValue = h;
|
canvas.setAttributeNode(anw);
|
canvas.setAttributeNode(anh);
|
ctx.drawImage(that, 0, 0, w, h);
|
// 图像质量
|
if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
|
quality = obj.quality;
|
}
|
// quality值越小,所绘制出的图像越模糊
|
var base64 = canvas.toDataURL('image/jpeg', quality);
|
// 回调函数返回base64的值
|
callback(base64);
|
}
|
},
|
|
/**
|
* 预览图片
|
* @param {string, object} item 文件信息
|
* */
|
previewImage(item) {
|
if (this.fileUrlType(item) === 'video') return false;
|
if (!this.isPreviewImage) return false;
|
|
const imgs = this.FileList.filter(item => {
|
return this.fileUrlType(item) !== 'video'
|
}).map(item => item?.path ?? item)
|
const current = imgs.indexOf(item || item.path);
|
|
uni.previewImage({
|
current: current,
|
urls: imgs,
|
success() {
|
},
|
fail(err) {
|
console.log(err);
|
}
|
})
|
},
|
|
/**
|
* 预览视频
|
* @param {string, object} item 文件信息
|
* @param {number} index 索引
|
* */
|
previewVideo(item, index) {
|
this.$emit('onVideo', {
|
item,
|
index
|
})
|
this.tempVideoUrl = item.path;
|
},
|
|
/**
|
* 是否img类型
|
* @param {string, object} item 文件信息
|
* @return {boolean} 是否img类型
|
* */
|
fileUrlType(file) {
|
const filePath = file.path || file;
|
|
if (this.isBase64(filePath)) return 'image'
|
|
const fileType = filePath.split('.').pop();
|
|
const IMAGE_REGEXP = /(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg|image)/i
|
if (IMAGE_REGEXP.test(fileType)) {
|
return 'image';
|
} else {
|
return 'video';
|
}
|
},
|
// 判断是否是base64
|
isBase64(str) {
|
if (str === '' || typeof str !== 'string') return console.error('文件路径错误, base64', str);
|
return str.includes('blob:') || str.includes('data:image');
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.cl-updata {
|
|
.file-list {
|
display: grid;
|
|
&-row {
|
display: inline-flex;
|
align-items: center;
|
position: relative;
|
|
.play-img {
|
width: 100%;
|
}
|
|
._image {
|
height: 100%;
|
width: 100%;
|
}
|
|
._video {
|
position: relative;
|
width: 100%;
|
height: 100%;
|
overflow: hidden;
|
}
|
|
.video-fixed {
|
position: absolute;
|
top: 0;
|
left: 0;
|
bottom: 0;
|
width: 100%;
|
height: 100%;
|
border-radius: 10rpx;
|
z-index: 96;
|
}
|
|
.play {
|
position: absolute;
|
top: 50%;
|
left: 50%;
|
transform: translate(-50%, -50%);
|
width: 30%;
|
z-index: 95;
|
}
|
|
.app_play {
|
position: absolute;
|
top: 50%;
|
left: 50%;
|
transform: translate(-50%, -50%);
|
width: 50rpx;
|
height: 50rpx;
|
}
|
|
.remove {
|
position: absolute;
|
top: 0;
|
right: 0;
|
background-color: #373737;
|
height: 50rpx;
|
width: 50rpx;
|
border-bottom-left-radius: 200rpx;
|
z-index: 97;
|
|
.image {
|
width: 20rpx;
|
height: 20rpx;
|
position: absolute;
|
right: 12rpx;
|
top: 12rpx;
|
}
|
}
|
}
|
|
.add-image {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
border: 2rpx dashed #ccc;
|
width: 100%;
|
height: 100%;
|
border-radius: 5rpx;
|
|
&:active {
|
opacity: 0.8;
|
}
|
|
._image {
|
width: 40%;
|
}
|
}
|
}
|
|
.mask {
|
background-color: #000;
|
position: fixed;
|
top: 0;
|
right: 0;
|
bottom: 0;
|
left: 0;
|
z-index: 99;
|
|
.block {
|
padding: 0 30rpx;
|
position: absolute;
|
top: 50%;
|
left: 50%;
|
transform: translate(-50%, -50%);
|
width: 100%;
|
|
.block_video {
|
width: 100%;
|
height: 78vh;
|
}
|
}
|
|
._root {
|
width: 60rpx;
|
height: 60rpx;
|
position: absolute;
|
left: 40rpx;
|
top: 5vh
|
}
|
}
|
}
|
</style>
|