118 lines
3.9 KiB
Vue
118 lines
3.9 KiB
Vue
<template>
|
|
<label class="flex flex-col" :for="id">
|
|
<span v-if="label" class="text-sm font-semibold text-gray-400">
|
|
{{ label }}
|
|
<span v-show="required" class="text-red-800"> *</span>
|
|
</span>
|
|
<div class="h-[35px] border-2 border-solid relative rounded-lg cursor-pointer flex-none border-gray-600 text-gray-300 bg-gray-700">
|
|
<div class="flex items-center justify-center h-full" v-if="inner === null">
|
|
<div class="relative text-sm text-gray-300 leading-none">Klicken oder Datei hierhin ziehen zum hochladen</div>
|
|
<input class="hidden" ref="uploader" @change="upload($event.target.files)" type="file" :name="name" :id="id" :multiple="false" />
|
|
<div class="absolute w-full h-full top-0 left-0 cursor-pointer" @drop="onDropping" @dragenter="onDragEnter" @dragover="onDragOver" @dragleave="onDragLeave"></div>
|
|
</div>
|
|
|
|
<div class="flex justify-between items-center h-full space-x-2 px-2" v-else>
|
|
<img :src="inner.icon" class="w-6 h-6" />
|
|
<div v-text="inner.file_name" class="text-sm text-gray-300 leading-none grow"></div>
|
|
<a href="#" @click.prevent="onDelete" v-tooltip="`Löschen`" class="flex justify-center items-center w-6 h-6 rounded-full bg-red-200">
|
|
<trash-icon class="text-red-800 w-3 h-3"></trash-icon>
|
|
</a>
|
|
<a :href="inner.original_url" v-tooltip="`Öffnen`" class="flex justify-center items-center w-6 h-6 rounded-full bg-primary-700" target="_BLANK">
|
|
<external-icon class="text-primary-200 w-3 h-3"></external-icon>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</label>
|
|
</template>
|
|
|
|
<script setup>
|
|
import {watch, ref, inject} from 'vue';
|
|
import TrashIcon from './TrashIcon.vue';
|
|
import ExternalIcon from './ExternalIcon.vue';
|
|
import useReadFile from '../composables/useReadFile.js';
|
|
import {useToast} from 'vue-toastification';
|
|
const emit = defineEmits(['update:modelValue']);
|
|
const axios = inject('axios');
|
|
const toast = useToast();
|
|
|
|
const inner = ref(null);
|
|
const {dropping, onDragEnter, onDragOver, onDragLeave, processDrop, read} = useReadFile();
|
|
|
|
const props = defineProps({
|
|
required: {
|
|
type: Boolean,
|
|
default: () => false,
|
|
},
|
|
collection: {
|
|
required: true,
|
|
type: String,
|
|
},
|
|
parentName: {
|
|
required: true,
|
|
type: String,
|
|
},
|
|
parentId: {
|
|
required: true,
|
|
validator: (value) => typeof value === 'number' || value === null,
|
|
},
|
|
name: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
id: {
|
|
required: true,
|
|
type: String,
|
|
},
|
|
label: {
|
|
required: false,
|
|
default: () => null,
|
|
validator: (value) => value === null || typeof value === 'string',
|
|
},
|
|
});
|
|
|
|
function parseValue(v) {
|
|
if (v === null) {
|
|
return null;
|
|
}
|
|
if (v.fallback) {
|
|
return null;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
async function reload() {
|
|
var response = await axios.get(`/mediaupload/${props.parentName}/${props.parentId}/${props.collection}`);
|
|
inner.value = parseValue(response.data);
|
|
emit('update:modelValue', inner.value.id);
|
|
}
|
|
async function onDropping(e) {
|
|
await upload(await processDrop(e, 1));
|
|
}
|
|
|
|
async function upload(files) {
|
|
await realUpload(await read(files[0]));
|
|
}
|
|
|
|
async function realUpload(file) {
|
|
inner.value = (
|
|
await axios.post('/mediaupload', {
|
|
parent: {model: props.parentName, collection_name: props.collection, id: props.parentId ? props.parentId : null},
|
|
payload: file,
|
|
})
|
|
).data;
|
|
emit('update:modelValue', inner.value);
|
|
toast.success('Datei hochgeladen');
|
|
}
|
|
|
|
async function onDelete() {
|
|
await axios.delete(`/mediaupload/${inner.value.id}`);
|
|
inner.value = null;
|
|
emit('update:modelValue', null);
|
|
toast.success('Datei entfernt');
|
|
}
|
|
|
|
if (props.parentId !== null) {
|
|
reload();
|
|
}
|
|
</script>
|