200 lines
5.7 KiB
Vue
200 lines
5.7 KiB
Vue
<template>
|
||
<div class="common-phone-upload">
|
||
<div class="upload-controller">
|
||
<AButton type="text" shape="circle" size="middle">
|
||
<template #icon>
|
||
<APopover placement="bottomRight" trigger="click">
|
||
<template #content>
|
||
<UploadSetting/>
|
||
</template>
|
||
<AAvatar size="small" shape="circle" :src="setting"/>
|
||
</APopover>
|
||
</template>
|
||
</AButton>
|
||
<ASelect size="middle" style="width: 150px" placeholder="选择相册"
|
||
:options="albumList"
|
||
v-model:value="upload.albumSelected"
|
||
:allow-clear="true"
|
||
:field-names="{label: 'name', value: 'id'}"
|
||
>
|
||
</ASelect>
|
||
</div>
|
||
<div class="upload-content">
|
||
<div class="upload">
|
||
<AUploadDragger
|
||
v-model:fileList="upload.fileList"
|
||
:beforeUpload="upload.beforeUpload"
|
||
:customRequest="customUploadRequest"
|
||
:directory="false"
|
||
:maxCount="10"
|
||
:multiple="true"
|
||
:disabled="upload.predicting"
|
||
:progress="upload.progress"
|
||
@remove="upload.removeFile"
|
||
@reject="upload.rejectFile"
|
||
:openFileDialogOnClick="true"
|
||
accept="image/*,video/*"
|
||
list-type="picture"
|
||
method="post"
|
||
name="file"
|
||
>
|
||
<p class="ant-upload-drag-icon">
|
||
<FileImageOutlined/>
|
||
</p>
|
||
<p v-show="!predicting" class="ant-upload-text">单击或拖动文件到此区域以上传</p>
|
||
<p v-show="!predicting" class="ant-upload-hint">
|
||
支持单次或批量上传,严禁上传非法图片,违者将受到法律惩戒。
|
||
</p>
|
||
<p v-show="predicting" class="ant-upload-hint">
|
||
AI 正在识别图片,请稍候...
|
||
</p>
|
||
<AProgress :stroke-color="{'0%': '#108ee9','100%': '#87d068',}" :percent="progressPercent"
|
||
:status="progressStatus"
|
||
:show-info="true" size="small" type="line" v-show="predicting" style="width: 80%"/>
|
||
</AUploadDragger>
|
||
</div>
|
||
|
||
<AEmpty :image="empty" v-if="fileList.length === 0">
|
||
<template #description>
|
||
<span style="color: #999999;font-size: 16px;font-weight: 500;line-height: 1.5;">
|
||
上传列表为空,点击或直接拖动文件到此区域上传。
|
||
</span>
|
||
</template>
|
||
</AEmpty>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<script setup lang="ts">
|
||
import setting from "@/assets/svgs/setting.svg";
|
||
import {albumListApi, uploadFile} from "@/api/phone";
|
||
import useStore from "@/store";
|
||
import empty from "@/assets/svgs/empty.svg";
|
||
import {useRequest} from "alova/client";
|
||
import imageCompression from "browser-image-compression";
|
||
import {generateThumbnail} from "@/utils/imageUtils/generateThumb.ts";
|
||
import UploadSetting from "@/components/ImageUpload/UploadSetting.vue";
|
||
|
||
const route = useRoute();
|
||
|
||
const fileList = ref([]);
|
||
const predicting = ref<boolean>(false);
|
||
const progressPercent = ref<number>(0);
|
||
const progressStatus = ref<string>('active');
|
||
|
||
const accessToken = computed(() => {
|
||
const token = route.query.token;
|
||
return Array.isArray(token) ? token[0] : token;
|
||
});
|
||
const userId = computed(() => {
|
||
const uid = route.query.user_id;
|
||
return Array.isArray(uid) ? uid[0] : uid;
|
||
});
|
||
|
||
|
||
const upload = useStore().upload;
|
||
const albumList = ref<any[]>([]);
|
||
/**
|
||
* 获取相册列表
|
||
*/
|
||
const {send: getAlbumList} = useRequest(albumListApi, {
|
||
immediate: false,
|
||
debounce: 500,
|
||
}).onSuccess((res: any) => {
|
||
if (res.data && res.data.code === 200) {
|
||
albumList.value = res.data.data.albums;
|
||
}
|
||
});
|
||
|
||
const {uploading, send: submitFile} = useRequest(uploadFile, {
|
||
immediate: false,
|
||
debounce: 500,
|
||
});
|
||
|
||
/**
|
||
* 自定义上传请求
|
||
* @param file
|
||
*/
|
||
async function customUploadRequest(file: any) {
|
||
const compressedFile = await imageCompression(file.file, upload.options);
|
||
// 生成缩略图
|
||
const {binaryData, width, height, size} = await generateThumbnail(compressedFile);
|
||
upload.predictResult.thumb_w = width;
|
||
upload.predictResult.thumb_h = height;
|
||
upload.predictResult.thumb_size = size;
|
||
|
||
const formData = new FormData();
|
||
formData.append("file", file.file);
|
||
if (binaryData) {
|
||
formData.append("thumbnail", binaryData);
|
||
}
|
||
formData.append("data", JSON.stringify({
|
||
provider: upload.storageSelected?.[0],
|
||
bucket: upload.storageSelected?.[1],
|
||
fileType: file.file.type,
|
||
albumId: upload.albumSelected ? upload.albumSelected : 0,
|
||
...upload.predictResult,
|
||
}));
|
||
watch(
|
||
() => uploading.value,
|
||
(upload) => {
|
||
if (upload && upload.loaded && upload.total) {
|
||
file.onProgress({percent: Number(Math.round((upload.loaded / upload.total) * 100).toFixed(2))}, file);
|
||
}
|
||
},
|
||
);
|
||
submitFile(formData, {
|
||
'Authorization': `Bearer ${accessToken.value}`,
|
||
'X-UID': userId.value,
|
||
}).then((response: any) => {
|
||
if (response && response.code === 200) {
|
||
file.onSuccess(response.data, file);
|
||
} else {
|
||
file.onError(response.data, file);
|
||
}
|
||
}).catch(file.onError);
|
||
}
|
||
|
||
|
||
onMounted(() => {
|
||
getAlbumList(0, true, {
|
||
'Authorization': `Bearer ${accessToken.value}`,
|
||
'X-UID': userId.value,
|
||
});
|
||
});
|
||
|
||
|
||
</script>
|
||
<style scoped lang="scss">
|
||
.common-phone-upload {
|
||
width: 90%;
|
||
height: 95vh;
|
||
padding: 15px;
|
||
margin: 0 auto;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
gap: 10px;
|
||
|
||
.upload-controller {
|
||
width: 100%;
|
||
height: 50px;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
gap: 20px;
|
||
}
|
||
|
||
.upload-content {
|
||
width: 100%;
|
||
height: calc(95vh - 60px);
|
||
|
||
.upload {
|
||
width: 100%;
|
||
height: 30vh;
|
||
}
|
||
}
|
||
}
|
||
</style>
|