Files
dvcp_v2_wxcp_app/components/AiUploader/AiUploader.vue
2024-10-31 16:22:41 +08:00

284 lines
7.3 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="ai-uploader">
<div class="fileList">
<div class="item" v-for="(item, i) in fileList" :key="i">
<template v-if="type == 'image'">
<ai-image :src="item.url" :preview="preview"/>
<u-icon v-if="!disabled" class="delBtn" color="#f46" name="close-circle-fill" size="40" @click="remove(i)"/>
</template>
<template v-else-if="type == 'video'">
<video :src="item.url" :poster="item.thumb"/>
<u-icon v-if="!disabled" class="delBtn" color="#f46" name="close-circle-fill" size="40" @click="remove(i)"/>
</template>
<div class="file" v-else>
<ai-image :preview="preview" :file="item"/>
<div class="info">
<span>{{ item.name }} </span>
<i>{{ item.fileSizeStr }}</i>
</div>
<template v-if="!disabled">
<div btn @tap="handleReUpload(i)">
重新上传
</div>
<div btn @tap="remove(i)">
删除
</div>
</template>
</div>
</div>
<div v-if="!disabled&&(fileList.length == 0 || (multiple && fileList.length < limit))" class="default"
@click="upload">
<i class="iconfont iconfont-iconAdd"/>
<span>{{ placeholder }}</span>
</div>
</div>
</div>
</template>
<script>
import {mapState} from 'vuex'
import AiImage from './AiImage'
export default {
name: 'AiUploader',
components: {AiImage},
props: {
limit: {default: 1}, //数量
placeholder: {default: '添加图片'}, // 文字提示
type: {default: 'image'}, // 文件类型image还是file
multiple: {
type: Boolean,
default: false,
},
fileId: String,
mediaId: String,
def: {default: () => []},
action: String,
preview: Boolean,
size: {default: 10 * 1024 * 1024},
disabled: Boolean,
sourceType: {default: () => ['album', 'camera']},
withoutToken: {
type: Number,
default: 0,
},
},
computed: {
...mapState(['token']),
errorImage: v => v.$cdn + 'file.png',
api() {
if (this.action) return this.action
else return {
image: '/admin/file/add',
file: '/admin/file/add',
video: '/admin/file/addVideo',
}[this.type]
}
},
watch: {
def: {
handler(v) {
if (!!v?.toString()) {
if (this.multiple) {
this.fileList = v
} else if (v?.url) {
this.fileList = [v]
}
}
},
immediate: true,
deep: true
},
},
data() {
return {
fileList: [],
}
},
methods: {
remove(index) {
this.fileList.splice(index, 1)
this.$emit('list', this.fileList)
},
upload(wait) {
typeof wait == 'function' && wait()
let count = this.limit - (this.fileList?.length || 0)
if (count > 0) {
let params = {
count,
sizeType: ['compressed'],
sourceType: [this.sourceType].flat(),
success: (res) => {
let count = this.fileList?.length + (res.tempFiles?.length || res.tempFile ? 1 : 0)
if (count > this.limit && this.limit !== 1) {
return this.$u.toast(`不能超过${this.limit}`)
}
if (res.tempFiles?.length > 0) {
res.tempFiles.map(this.uploadFile)
} else if (res?.tempFile) {
this.uploadFile(res.tempFile)
}
},
}
if (this.type == 'image') {
uni.chooseImage(params)
} else if (this.type == 'video') {
uni.chooseVideo(params)
} else {
uni.chooseFile(params)
}
} else {
this.$u.toast(`不能超过${this.limit}`)
}
},
uploadFile(img) {
if (this.size > 0 && img.size > this.size) {
return this.$u.toast(`不能超过${Math.ceil(this.size / 1024 / 1024)}MB`)
}
uni.showLoading({title: '上传中'})
let formData = new FormData()
formData.append('file', img)
if (this.manual) {
this.$emit('manual', img)
uni.hideLoading()
} else {
this.$http.post(this.api, formData, {
params: {type: this.type},
withoutToken: this.withoutToken == 1 ? true : false,
}).then((res) => {
if (res?.data) {
this.$emit('data', res.data)
this.$u.toast('上传成功!')
if (!this.action) {
if (this.type == 'image') {
const [image = "",] = res.data
this.fileList.push({url: image.split(";")[0], id: image.split(";")?.[1]})
} else if (this.type == 'video') {
const [video = "", thumb = ""] = res.data
this.fileList.push({url: video.split(";")[0], id: video.split(";")?.[1], thumb: thumb.split(";")[0]})
}
} else if (this.api == '/app/wxcp/upload/uploadFile') {
this.$emit('update:mediaId', res.data?.media?.mediaId)
this.$emit('update:fileId', res.data.file.id)
this.fileList.push(res.data.file)
} else if (this.api == '/admin/file/add2') {
let info = res.data
this.$emit('update:fileId', info?.id)
this.fileList.push(res.data)
} else if (this.api == '/admin/file/add-portrait') {
this.fileList.push({url: res.data?.split(";")?.[0], id: res.data?.split(";")?.[1]})
}
this.$emit("update:def", this.fileList)
this.$emit("list", this.fileList)
} else {
this.$u.toast(res.msg)
}
}).catch(err => {
this.$u.toast(err)
}).finally(() => uni.hideLoading())
}
},
handleReUpload(i) {
this.upload(() => this.remove(i))
},
},
}
</script>
<style lang="scss" scoped>
.ai-uploader {
width: 100%;
line-height: normal;
margin-bottom: 16px;
::v-deep.fileList {
display: flex;
flex-wrap: wrap;
.item {
width: initial;
padding: 0 10px 10px 0;
position: relative;
.delBtn {
position: absolute;
right: -8px;
top: -8px;
z-index: 2;
border-radius: 50%;
overflow: hidden;
background-color: #fff;
height: 40px;
}
image, video {
width: 29vw;
height: 29vw;
}
i {
font-style: normal;
color: #9b9b9b;
}
.info {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
align-items: flex-start;
overflow: hidden;
text-overflow: ellipsis;
& > span {
flex: 1;
min-width: 0;
}
}
div[btn] {
color: $uni-color-primary;
}
div:nth-child(4) {
color: #f72c27;
}
& > * + * {
margin-left: 20px;
}
}
.default {
width: 30vw;
height: 30vw;
box-sizing: border-box;
border-radius: 8px;
background: #f3f4f7;
color: #89b;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.iconfont-iconAdd {
font-size: 64px;
}
span {
display: block;
text-align: center;
font-size: 28px;
}
}
.file {
width: 100vw;
display: flex;
align-items: center;
}
}
}
</style>