upload file form WIP
This commit is contained in:
parent
7e1fced429
commit
3cfef87efb
|
@ -12,6 +12,7 @@
|
||||||
"@quasar/extras": "^1.16.4",
|
"@quasar/extras": "^1.16.4",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"chromium": "^3.0.3",
|
"chromium": "^3.0.3",
|
||||||
|
"croppie": "^2.6.5",
|
||||||
"pinia": "^2.1.3",
|
"pinia": "^2.1.3",
|
||||||
"quasar": "^2.12.0",
|
"quasar": "^2.12.0",
|
||||||
"validator": "^13.9.0",
|
"validator": "^13.9.0",
|
||||||
|
@ -3169,6 +3170,11 @@
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/croppie": {
|
||||||
|
"version": "2.6.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/croppie/-/croppie-2.6.5.tgz",
|
||||||
|
"integrity": "sha512-IlChnVUGG5T3w2gRZIaQgBtlvyuYnlUWs2YZIXXR3H9KrlO1PtBT3j+ykxvy9eZIWhk+V5SpBmhCQz5UXKrEKQ=="
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
"@quasar/extras": "^1.16.4",
|
"@quasar/extras": "^1.16.4",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"chromium": "^3.0.3",
|
"chromium": "^3.0.3",
|
||||||
|
"croppie": "^2.6.5",
|
||||||
"pinia": "^2.1.3",
|
"pinia": "^2.1.3",
|
||||||
"quasar": "^2.12.0",
|
"quasar": "^2.12.0",
|
||||||
"validator": "^13.9.0",
|
"validator": "^13.9.0",
|
||||||
|
|
|
@ -1,22 +1,38 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, ref } from 'vue';
|
import { reactive, computed, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
import FormModelPopup from './FormModelPopup.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
const emit = defineEmits(['onDataSaved']);
|
import Croppie from 'croppie/croppie';
|
||||||
|
import 'croppie/croppie.css';
|
||||||
|
import useNotify from 'src/composables/useNotify.js';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
const props = defineProps({});
|
const props = defineProps({});
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const { notify } = useNotify();
|
||||||
|
|
||||||
const editFormData = reactive({
|
const editPhotoFormData = reactive({
|
||||||
uploadMethod: 'computer',
|
uploadMethod: 'computer',
|
||||||
file: null,
|
file: null,
|
||||||
quantity: null,
|
url: null,
|
||||||
|
viewportType: {
|
||||||
|
code: 'normal',
|
||||||
|
description: t('Normal'),
|
||||||
|
viewport: {
|
||||||
|
width: 400,
|
||||||
|
height: 400,
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
width: 1200,
|
||||||
|
height: 1200,
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const options = [
|
const options = [
|
||||||
|
@ -24,59 +40,295 @@ const options = [
|
||||||
{ label: t('Import from external URL'), value: 'URL' },
|
{ label: t('Import from external URL'), value: 'URL' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const onDataSaved = (data) => {
|
const viewportTypes = [
|
||||||
emit('onDataSaved', data);
|
{
|
||||||
|
code: 'normal',
|
||||||
|
description: t('Normal'),
|
||||||
|
viewport: {
|
||||||
|
width: 400,
|
||||||
|
height: 400,
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
width: 1200,
|
||||||
|
height: 1200,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'panoramic',
|
||||||
|
description: t('Panoramic'),
|
||||||
|
viewport: {
|
||||||
|
width: 675,
|
||||||
|
height: 450,
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
width: 1350,
|
||||||
|
height: 900,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'vertical',
|
||||||
|
description: t('Vertical'),
|
||||||
|
viewport: {
|
||||||
|
width: 306.66,
|
||||||
|
height: 533.33,
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
width: 460,
|
||||||
|
height: 800,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const allowedContentTypes = ref('');
|
||||||
|
const photoContainerRef = ref(null);
|
||||||
|
const editor = ref(null);
|
||||||
|
|
||||||
|
const displayEditor = () => {
|
||||||
|
const viewportType = editPhotoFormData.viewportType;
|
||||||
|
const viewport = viewportType.viewport;
|
||||||
|
const boundaryWidth = viewport.width + 200;
|
||||||
|
const boundaryHeight = viewport.height + 200;
|
||||||
|
|
||||||
|
if (editor.value) editor.value.destroy();
|
||||||
|
editor.value = new Croppie(photoContainerRef.value, {
|
||||||
|
viewport: { width: viewport.width, height: viewport.height },
|
||||||
|
boundary: { width: boundaryWidth, height: boundaryHeight },
|
||||||
|
enableOrientation: true,
|
||||||
|
showZoomer: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewportSelection = computed({
|
||||||
|
get() {
|
||||||
|
return editPhotoFormData.viewportType;
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
editPhotoFormData.viewportType = val;
|
||||||
|
|
||||||
|
const hasFile = editPhotoFormData.file || editPhotoFormData.url;
|
||||||
|
if (!val || !hasFile) return;
|
||||||
|
|
||||||
|
let file;
|
||||||
|
if (editPhotoFormData.uploadMethod == 'computer') file = editPhotoFormData.file;
|
||||||
|
else if (editPhotoFormData.uploadMethod == 'URL') file = editPhotoFormData.url;
|
||||||
|
|
||||||
|
updatePhotoPreview(file);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatePhotoPreview = (value) => {
|
||||||
|
if (value) {
|
||||||
|
displayEditor();
|
||||||
|
if (editPhotoFormData.uploadMethod == 'computer') {
|
||||||
|
editPhotoFormData.file = value;
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => editor.value.bind({ url: e.target.result });
|
||||||
|
reader.readAsDataURL(value);
|
||||||
|
} else if (editPhotoFormData.uploadMethod == 'URL') {
|
||||||
|
const img = new Image();
|
||||||
|
img.crossOrigin = 'Anonymous';
|
||||||
|
img.src = value;
|
||||||
|
img.onload = () => editor.value.bind({ url: value });
|
||||||
|
img.onerror = () => {
|
||||||
|
notify(
|
||||||
|
t("This photo provider doesn't allow remote downloads"),
|
||||||
|
'negative'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const rotateLeft = () => {
|
||||||
|
editor.value.rotate(90);
|
||||||
|
};
|
||||||
|
|
||||||
|
const rotateRight = () => {
|
||||||
|
editor.value.rotate(-90);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onUploadAccept = () => {
|
||||||
|
try {
|
||||||
|
if (!this.newPhoto.files) throw new Error(`Select an image`);
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
type: 'blob',
|
||||||
|
};
|
||||||
|
return this.editor
|
||||||
|
.result(options)
|
||||||
|
.then((blob) => (this.newPhoto.blob = blob))
|
||||||
|
.then(() => this.makeRequest());
|
||||||
|
} catch (e) {
|
||||||
|
this.vnApp.showError(this.$t(e.message));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const makeRequest = async () => {
|
||||||
|
// const options = {
|
||||||
|
// method: 'POST',
|
||||||
|
// url: `Images/upload`,
|
||||||
|
// params: this.newPhoto,
|
||||||
|
// headers: { 'Content-Type': undefined },
|
||||||
|
// timeout: this.canceler.promise,
|
||||||
|
// transformRequest: ([file]) => {
|
||||||
|
// const formData = new FormData();
|
||||||
|
// const now = Date.vnNew();
|
||||||
|
// const timestamp = now.getTime();
|
||||||
|
// const fileName = `${file.name}_${timestamp}`;
|
||||||
|
|
||||||
|
// formData.append('blob', this.newPhoto.blob, fileName);
|
||||||
|
|
||||||
|
// return formData;
|
||||||
|
// },
|
||||||
|
// data: this.newPhoto.files,
|
||||||
|
// };
|
||||||
|
|
||||||
|
await axios.post('Images/upload');
|
||||||
|
|
||||||
|
this.$http(options)
|
||||||
|
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')))
|
||||||
|
.then(() => this.emit('response'))
|
||||||
|
.finally(() => (this.canceler = null));
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- <FetchData
|
<FetchData
|
||||||
url="Warehouses"
|
ref="allowTypesRef"
|
||||||
@on-fetch="(data) => (warehousesOptions = data)"
|
url="ImageContainers/allowedContentTypes"
|
||||||
|
@on-fetch="(data) => (allowedContentTypes = data.join(', '))"
|
||||||
auto-load
|
auto-load
|
||||||
/> -->
|
/>
|
||||||
<FormModelPopup
|
<QForm class="all-pointer-events">
|
||||||
url-create="Items/regularize"
|
<QCard class="q-pa-lg">
|
||||||
model="Items"
|
<span ref="closeButton" class="close-icon" v-close-popup>
|
||||||
:title="t('Edit photo')"
|
<QIcon name="close" size="sm" />
|
||||||
:form-initial-data="editFormData"
|
</span>
|
||||||
@on-data-saved="onDataSaved($event)"
|
<h1 class="title">{{ t('Edit photo') }}</h1>
|
||||||
|
<div class="row q-gutter-lg">
|
||||||
|
<div
|
||||||
|
v-show="editPhotoFormData.file || editPhotoFormData.url"
|
||||||
|
class="row q-gutter-lg items-center"
|
||||||
>
|
>
|
||||||
<template #form-inputs="{}">
|
<QIcon
|
||||||
|
name="rotate_left"
|
||||||
|
size="sm"
|
||||||
|
color="primary"
|
||||||
|
class="cursor-pointer"
|
||||||
|
@click="rotateLeft()"
|
||||||
|
>
|
||||||
|
<!-- <QTooltip class="no-pointer-events">
|
||||||
|
{{ t('Rotate left') }}
|
||||||
|
</QTooltip> -->
|
||||||
|
</QIcon>
|
||||||
|
<div>
|
||||||
|
<div ref="photoContainerRef" />
|
||||||
|
</div>
|
||||||
|
<QIcon
|
||||||
|
name="rotate_right"
|
||||||
|
size="sm"
|
||||||
|
color="primary"
|
||||||
|
class="cursor-pointer"
|
||||||
|
@click="rotateRight()"
|
||||||
|
>
|
||||||
|
<!-- <QTooltip class="no-pointer-events">
|
||||||
|
{{ t('Rotate right') }}
|
||||||
|
</QTooltip> -->
|
||||||
|
</QIcon>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="column">
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<QOptionGroup
|
<QOptionGroup
|
||||||
:options="options"
|
:options="options"
|
||||||
type="radio"
|
type="radio"
|
||||||
v-model="editFormData.uploadMethod"
|
v-model="editPhotoFormData.uploadMethod"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow class="row q-gutter-md q-mb-md">
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<QFile
|
<QFile
|
||||||
:label="t('entry.buys.file')"
|
v-if="editPhotoFormData.uploadMethod === 'computer'"
|
||||||
|
:label="t('File')"
|
||||||
:multiple="false"
|
:multiple="false"
|
||||||
v-model="editFormData.file"
|
@update:model-value="updatePhotoPreview($event)"
|
||||||
@update:model-value="onFileChange($event)"
|
:accept="allowedContentTypes"
|
||||||
class="required"
|
class="required"
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
<QIcon name="vn:attach" class="cursor-pointer">
|
<QIcon
|
||||||
|
name="vn:attach"
|
||||||
|
class="cursor-pointer q-mr-sm"
|
||||||
|
>
|
||||||
<QTooltip>{{ t('Select a file') }}</QTooltip>
|
<QTooltip>{{ t('Select a file') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
|
<QIcon name="info" class="cursor-pointer">
|
||||||
|
<QTooltip>{{
|
||||||
|
t(
|
||||||
|
'components.editPictureForm.allowedFilesText',
|
||||||
|
{
|
||||||
|
allowedContentTypes:
|
||||||
|
allowedContentTypes,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
</template>
|
</template>
|
||||||
</QFile>
|
</QFile>
|
||||||
|
<VnInput
|
||||||
|
v-if="editPhotoFormData.uploadMethod === 'URL'"
|
||||||
|
v-model="editPhotoFormData.url"
|
||||||
|
@update:model-value="updatePhotoPreview($event)"
|
||||||
|
placeholder="https://"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<pre>{{ editFormData }}</pre>
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
</template>
|
<div class="col">
|
||||||
</FormModelPopup>
|
<VnSelectFilter
|
||||||
|
:label="t('Orientation')"
|
||||||
|
:options="viewportTypes"
|
||||||
|
hide-selected
|
||||||
|
option-label="description"
|
||||||
|
v-model="viewportSelection"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</QCard>
|
||||||
|
</QForm>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.title {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
es:
|
es:
|
||||||
Edit photo: Editar foto
|
Edit photo: Editar foto
|
||||||
Select from computer: Seleccionar desde ordenador
|
Select from computer: Seleccionar desde ordenador
|
||||||
Import from external URL: Importar desde URL externa
|
Import from external URL: Importar desde URL externa
|
||||||
|
Vertical: Vertical
|
||||||
|
Normal: Normal
|
||||||
|
Panoramic: Panorámica
|
||||||
|
Orientation: Orientación
|
||||||
|
File: Fichero
|
||||||
|
This photo provider doesn't allow remote downloads: Este proveedor de fotos no permite descargas remotas
|
||||||
|
Rotate left: Girar a la izquierda
|
||||||
|
Rotate right: Girar a la derecha
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -1102,5 +1102,8 @@ export default {
|
||||||
addToPinned: 'Add to pinned',
|
addToPinned: 'Add to pinned',
|
||||||
removeFromPinned: 'Remove from pinned',
|
removeFromPinned: 'Remove from pinned',
|
||||||
},
|
},
|
||||||
|
editPictureForm: {
|
||||||
|
allowedFilesText: 'Allowed file types: { allowedContentTypes }',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1102,5 +1102,8 @@ export default {
|
||||||
addToPinned: 'Añadir a fijados',
|
addToPinned: 'Añadir a fijados',
|
||||||
removeFromPinned: 'Eliminar de fijados',
|
removeFromPinned: 'Eliminar de fijados',
|
||||||
},
|
},
|
||||||
|
editPictureForm: {
|
||||||
|
allowedFilesText: 'Tipos de archivo permitidos: { allowedContentTypes }',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue