jws-frontend/src/components/upload-file/UploadFile.vue
2024-09-25 10:55:06 +07:00

348 lines
8.9 KiB
Vue

<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { DeleteButton } from 'components/button';
import { dialog } from 'stores/utils';
import { useI18n } from 'vue-i18n';
import { VuePDF, usePDF } from '@tato30/vue-pdf';
const { t } = useI18n();
const currentFileSelected = ref<string>('');
const obj = defineModel<
{
name?: string;
group?: string;
url?: string;
file?: File;
}[]
>({
default: [],
});
const currentFile = computed(() => obj.value.at(currentIndex.value));
const statusOcr = defineModel<boolean>('statusOcr', { default: false });
const currentMode = ref<string>('');
const currentIndex = ref(0);
const scale = ref(1);
const page = ref(1);
const currentIndexDropdownList = ref(0);
const props = withDefaults(
defineProps<{
treeFile: { label: string; file: { label: string }[] }[];
readonly?: boolean;
dropdownList?: { label: string; value: string }[];
hideAction?: boolean;
autoSave?: boolean;
}>(),
{
autoSave: false,
treeFile: () => [],
},
);
function browse() {
inputFile?.click();
}
const inputFile = (() => {
const _element = document.createElement('input');
_element.type = 'file';
_element.accept = 'image/jpeg,image/png';
_element.addEventListener('change', change);
return _element;
})();
async function change(e: Event) {
const _element = e.target as HTMLInputElement | null;
const _file = _element?.files?.[0];
if (_file) {
if (!obj.value[currentIndex.value]) {
obj.value = [
...obj.value,
{
name: _file.name,
file: _file,
},
];
currentIndex.value = obj.value.length;
}
const reader = new FileReader();
reader.readAsDataURL(_file);
reader.onload = () => {
if (obj.value[currentIndex.value]) {
obj.value[currentIndex.value].url = reader.result as string;
currentFileSelected.value = _file.name;
}
};
if (!!props.autoSave) {
emit(
'save',
props.dropdownList?.[currentIndexDropdownList.value].value || '',
inputFile?.files?.[0],
);
}
}
}
// function change(e: Event) {
// const _element = e.target as HTMLInputElement | null;
// const _file = _element?.files?.[0];
// currentIndex.value = obj.value.length;
// if (_file) {
// currentIndex.value = obj.value.length + 1;
// const reader = new FileReader();
// reader.readAsDataURL(_file);
// reader.onload = () => {
// if (obj.value[currentIndex.value]) {
// obj.value[currentIndex.value].url = reader.result as string;
// console.log('asd');
// }
// };
// if (_file && obj.value[currentIndex.value]) {
// obj.value[currentIndex.value].file = _file;
// obj.value[currentIndex.value].group =
// props.dropdownList?.[currentIndexDropdownList.value].value;
// } else {
// obj.value.push({
// name: _file.name,
// group: props.dropdownList?.[currentIndexDropdownList.value].value,
// file: _file,
// });
// }
// if (!!props.autoSave) {
// emit(
// 'save',
// props.dropdownList?.[currentIndexDropdownList.value].value || '',
// inputFile?.files?.[0],
// );
// } else {
// }
// }
// }
watch(currentFileSelected, () => {
obj.value.findIndex((v, i) => {
if (v.name?.includes(currentFileSelected.value)) {
currentIndex.value = i;
const tempValue =
props.dropdownList?.findIndex((v) =>
v.value.includes(currentFileSelected.value.split('-')[0]),
) || 0;
currentMode.value = props.dropdownList?.[tempValue].label || 'other';
}
});
});
const emit = defineEmits<{
(e: 'sendOcr', dropdown: string, file?: File): void;
(e: 'save', group: string, file?: File): void;
(e: 'deleteFile', filename: string): void;
}>();
const { pdf, pages } = usePDF(computed(() => currentFile.value?.url));
function deleteFileOfBranch(filename: string, index: number) {
dialog({
color: 'negative',
icon: 'mdi-alert',
title: t('dialog.title.confirmDelete'),
actionText: t('general.delete'),
persistent: true,
message: t('dialog.message.confirmDelete'),
action: async () => {
if (!!props.autoSave) {
emit('deleteFile', filename);
} else {
obj.value.splice(index, 1);
}
},
cancel: () => {},
});
}
</script>
<template>
<div class="full-width row no-wrap wrapper" style="height: 250px">
<div class="col-3 full-height column no-wrap">
<div class="q-pa-sm text-center bordered" style="height: 50px">
<q-btn-dropdown
:disable="readonly"
icon="mdi-upload"
color="info"
:label="$t('general.uploadFile')"
@click="
() => {
currentIndex = obj.length;
browse();
}
"
></q-btn-dropdown>
</div>
<div class="bordered-l bordered-b q-pa-sm full-height scroll">
<q-item
clickable
v-for="(v, i) in obj"
:key="v.name"
dense
type="button"
class="no-padding items-center rounded"
active-class="menu-active"
:active="currentFileSelected === v.name"
@click="
async () => {
currentFileSelected = v.name || '';
}
"
>
<div class="full-width row items-center justify-between">
<div class="ellipsis col-8">
<q-tooltip>{{ v.name }}</q-tooltip>
{{ v.name }}
</div>
<DeleteButton
iconOnly
@click.stop="
() => {
deleteFileOfBranch(v.name || '', i);
}
"
/>
</div>
</q-item>
<!-- <q-tree
:nodes="
Object.values(
obj.reduce<
Record<string, { label: string; file: { label: string }[] }>
>((a, b) => {
if (b.name && !a[b.name]) {
a[b.name] = {
label: b.name,
file: [],
};
}
return a;
}, {}) || {},
) || []
"
node-key="label"
label-key="label"
children-key="file"
selected-color="primary"
v-model:selected="currentFileSelected"
default-expand-all
>
<template v-slot:default-header="prop">
<div class="full-width row items-center justify-between">
<div class="col-8 ellipsis">
<q-tooltip>{{ prop.node.label }}</q-tooltip>
{{ prop.node.label }}
</div>
<DeleteButton
iconOnly
@click.stop="
() => {
deleteFileOfBranch(prop.node.label);
}
"
/>
</div>
</template>
</q-tree> -->
</div>
</div>
<div class="col full-height column no-wrap">
<div
class="bordered row items-center justify-evenly q-pa-sm no-wrap"
style="height: 50px"
>
<q-btn
@click="page = page > 1 ? page - 1 : page"
class="btn-next"
icon="mdi-chevron-left"
unelevated
dense
id="btn-prev-page-top"
/>
<div class="ellipsis">Page {{ page }} of {{ pages }}</div>
<q-btn
@click="scale = scale > 0.25 ? scale - 0.25 : scale"
flat
dense
round
size="12px"
icon="mdi-magnify-minus-outline"
class="app-text-dark"
>
<q-tooltip>{{ $t('zoomOut') }}</q-tooltip>
</q-btn>
<div>{{ scale * 100 }}%</div>
<q-btn
flat
dense
round
size="12px"
class="app-text-dark"
icon="mdi-magnify-plus-outline"
@click="scale = scale < 2 ? scale + 0.25 : scale"
>
<q-tooltip>{{ $t('general.zoomIn') }}</q-tooltip>
</q-btn>
<q-btn
@click="page = page < pages ? page + 1 : page"
class="btn-next"
icon="mdi-chevron-right"
unelevated
dense
id="btn-prev-page-top"
/>
</div>
<div
class="flex flex-center surface-2 bordered-l bordered-r bordered-b full-height scroll"
>
<VuePDF
style="height: 100%"
v-if="
currentFile?.url?.split('?').at(0)?.endsWith('.pdf') ||
currentFile?.file?.type === 'application/pdf'
"
class="q-py-md"
:pdf="pdf"
:page="page"
:scale="scale"
/>
<q-img
v-else
class="q-py-md full-width"
:src="currentFile?.url"
style="height: 220px; max-width: 300px"
/>
</div>
</div>
</div>
</template>
<style lang="scss">
.wrapper > * {
height: 300px;
}
</style>