92 lines
2.9 KiB
Vue
92 lines
2.9 KiB
Vue
<script setup lang="ts">
|
|
import { useDocumentStore } from '@/stores/documents'
|
|
import NotificationLoading from '@/components/NotificationLoading.vue'
|
|
import { FileAddFilled } from '@ant-design/icons-vue'
|
|
import { notification } from 'ant-design-vue';
|
|
import type { NotificationPlacement } from 'ant-design-vue';
|
|
import { h, ref } from 'vue';
|
|
|
|
const [api, contextHolder] = notification.useNotification();
|
|
|
|
const fileUploadButton = ref()
|
|
const documentStore = useDocumentStore();
|
|
const open = (placement: NotificationPlacement) => openNotification(placement);
|
|
|
|
const isNotificationOpen = ref(false);
|
|
const openNotification = (placement: NotificationPlacement) => {
|
|
if(!isNotificationOpen.value){
|
|
api.open({
|
|
message: `Uploading documents`,
|
|
description: h(NotificationLoading),
|
|
placement,
|
|
duration: 0,
|
|
onClose: () => { isNotificationOpen.value = false }
|
|
});
|
|
isNotificationOpen.value = true;
|
|
}
|
|
};
|
|
|
|
|
|
function uploadFileHandler() {
|
|
fileUploadButton.value.click()
|
|
}
|
|
|
|
async function load(file: File, start: number, end: number): Promise<ArrayBuffer> {
|
|
const reader = new FileReader();
|
|
const load = new Promise<Event>((resolve) => (reader.onload = resolve));
|
|
reader.readAsArrayBuffer(file.slice(start, end));
|
|
const event = await load;
|
|
if (event.target && event.target instanceof FileReader) {
|
|
return event.target.result as ArrayBuffer;
|
|
} else {
|
|
throw new Error('Error loading file' );
|
|
}
|
|
}
|
|
|
|
async function sendChunk(file :File, start: number, end: number) {
|
|
const ws = documentStore.wsUpload;
|
|
if(ws){
|
|
const chunk = await load(file, start, end)
|
|
|
|
ws.send(JSON.stringify({
|
|
name: file.name,
|
|
size: file.size,
|
|
start: start,
|
|
end: end
|
|
}))
|
|
ws.send(chunk)
|
|
}
|
|
}
|
|
|
|
async function uploadFileChangeHandler(event: Event) {
|
|
const target = event.target as HTMLInputElement;
|
|
const chunkSize = 1 << 20
|
|
if (target && target.files && target.files.length > 0) {
|
|
const file = target.files[0];
|
|
const numChunks = Math.ceil(file.size / chunkSize)
|
|
const document = documentStore.pushUploadingDocuments(file.name)
|
|
open('bottomRight')
|
|
for (let i = 0; i < numChunks; i++) {
|
|
const start = i * chunkSize
|
|
const end = Math.min(file.size, start + chunkSize)
|
|
const res = await sendChunk(file, start, end)
|
|
console.log( 'progress: '+ ( ( 100 * (i + 1) ) / numChunks) )
|
|
console.log( 'Num Chunks: '+ numChunks )
|
|
documentStore.updateUploadingDocuments( document.key, ((100 * (i + 1) ) / numChunks))
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<template>
|
|
<a-tooltip title="Upload files from disk">
|
|
<a-button @click="uploadFileHandler" type="text" class="action-button" :icon="h(FileAddFilled)" />
|
|
<input ref="fileUploadButton" @change="uploadFileChangeHandler" class="upload-input" type="file" onclick="this.value=null;" />
|
|
</a-tooltip>
|
|
<contextHolder />
|
|
</template>
|
|
<style scoped>
|
|
/* Extends styles from HeaderMain.vue too */
|
|
.upload-input{
|
|
display: none;
|
|
}
|
|
</style> |