Image Upload
This commit is contained in:
parent
0771b43f56
commit
91ede95530
4 changed files with 117 additions and 34 deletions
|
@ -9,7 +9,14 @@
|
|||
<button type="submit" class="!w-fit !h-fit !p-0">
|
||||
<CheckIcon class="h-5 w-5 cursor-pointer" />
|
||||
</button>
|
||||
<button type="reset" class="!w-fit !h-fit !p-0" @click="enableEdit = false">
|
||||
<button
|
||||
type="reset"
|
||||
class="!w-fit !h-fit !p-0"
|
||||
@click="
|
||||
enableEdit = false;
|
||||
$emit('reset');
|
||||
"
|
||||
>
|
||||
<XMarkIcon class="h-5 w-5 cursor-pointer" />
|
||||
</button>
|
||||
</div>
|
||||
|
@ -48,6 +55,7 @@ export default defineComponent({
|
|||
required: true,
|
||||
},
|
||||
},
|
||||
emits: ["reset"],
|
||||
data() {
|
||||
return {
|
||||
enableEdit: false as boolean,
|
||||
|
|
|
@ -1,31 +1,48 @@
|
|||
<template>
|
||||
<BaseSetting title="Vereins-Auftritt Einstellungen" :submit-function="submit" v-slot="{ enableEdit }">
|
||||
<BaseSetting title="Vereins-Auftritt Einstellungen" :submit-function="submit" v-slot="{ enableEdit }" @reset="reset">
|
||||
<div class="w-full">
|
||||
<p>Vereins-Icon</p>
|
||||
<AppIcon v-if="clubSettings['club.icon'] != '' && !overwriteIcon" class="h-10! max-w-full mx-auto" />
|
||||
<img v-else-if="overwriteIcon" ref="icon_img" class="hidden w-full h-20 object-contain" />
|
||||
<div
|
||||
v-else
|
||||
class="flex h-10 w-full border-2 border-gray-300 rounded-md items-center justify-center text-sm cursor-pointer"
|
||||
@click="($refs.icon as HTMLInputElement).click()"
|
||||
>
|
||||
Kein eigenes Icon ausgewählt
|
||||
<div class="flex flex-row gap-2">
|
||||
<AppIcon v-if="icon != '' && !overwriteIcon" class="h-10! max-w-full mx-auto" />
|
||||
<div
|
||||
v-else-if="!overwriteIcon"
|
||||
class="flex h-10 w-full border-2 border-gray-300 rounded-md items-center justify-center text-sm"
|
||||
:class="{ 'cursor-pointer': enableEdit }"
|
||||
@click="enableEdit ? ($refs.icon as HTMLInputElement).click() : null"
|
||||
>
|
||||
Kein eigenes Icon ausgewählt
|
||||
</div>
|
||||
<img ref="icon_img" class="hidden w-full h-20 object-contain" />
|
||||
<XMarkIcon
|
||||
v-if="enableEdit && (icon != '' || overwriteIcon)"
|
||||
class="h-5 w-5 cursor-pointer"
|
||||
@click="resetImage('icon')"
|
||||
/>
|
||||
</div>
|
||||
<input class="hidden!" type="file" ref="icon" accept="image/*" @change="previewImage('icon')" />
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<p>Vereins-Logo</p>
|
||||
<AppLogo v-if="clubSettings['club.logo'] != '' && !overwriteLogo" class="h-10! max-w-full mx-auto" />
|
||||
<img v-else-if="overwriteLogo" ref="logo_img" class="hidden w-full h-20 object-contain" />
|
||||
<div
|
||||
v-else
|
||||
class="flex h-10 w-full border-2 border-gray-300 rounded-md items-center justify-center text-sm cursor-pointer"
|
||||
@click="($refs.logo as HTMLInputElement).click()"
|
||||
>
|
||||
Kein eigenes Logo ausgewählt
|
||||
<div class="flex flex-row gap-2">
|
||||
<AppLogo v-if="logo != '' && !overwriteLogo" class="h-10! max-w-full mx-auto" />
|
||||
<div
|
||||
v-else-if="!overwriteLogo"
|
||||
class="flex h-10 w-full border-2 border-gray-300 rounded-md items-center justify-center text-sm"
|
||||
:class="{ 'cursor-pointer': enableEdit }"
|
||||
@click="enableEdit ? ($refs.logo as HTMLInputElement).click() : null"
|
||||
>
|
||||
Kein eigenes Logo ausgewählt
|
||||
</div>
|
||||
<img ref="logo_img" class="hidden w-full h-20 object-contain" />
|
||||
<XMarkIcon
|
||||
v-if="enableEdit && (logo != '' || overwriteLogo)"
|
||||
class="h-5 w-5 cursor-pointer"
|
||||
@click="resetImage('logo')"
|
||||
/>
|
||||
</div>
|
||||
<input class="hidden!" type="file" ref="logo" accept="image/*" @change="previewImage('logo')" /></div
|
||||
></BaseSetting>
|
||||
<input class="hidden!" type="file" ref="logo" accept="image/*" @change="previewImage('logo')" />
|
||||
</div>
|
||||
</BaseSetting>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -37,12 +54,20 @@ import AppLogo from "@/components/AppLogo.vue";
|
|||
import { useAbilityStore } from "@/stores/ability";
|
||||
import type { SettingString } from "@/types/settingTypes";
|
||||
import BaseSetting from "./BaseSetting.vue";
|
||||
import { XMarkIcon } from "@heroicons/vue/24/outline";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default defineComponent({
|
||||
watch: {
|
||||
clubSettings() {
|
||||
this.reset();
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
logo: "",
|
||||
icon: "",
|
||||
overwriteIcon: false as boolean,
|
||||
overwriteLogo: false as boolean,
|
||||
};
|
||||
|
@ -54,8 +79,35 @@ export default defineComponent({
|
|||
return this.readByTopic("club");
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.reset();
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useSettingStore, ["updateSettings", "uploadImage"]),
|
||||
reset() {
|
||||
this.icon = this.clubSettings["club.icon"];
|
||||
this.overwriteIcon = false;
|
||||
(this.$refs.icon_img as HTMLImageElement).style.display = "none";
|
||||
(this.$refs.icon as HTMLInputElement).value = "";
|
||||
|
||||
this.logo = this.clubSettings["club.logo"];
|
||||
this.overwriteLogo = false;
|
||||
(this.$refs.logo_img as HTMLImageElement).style.display = "none";
|
||||
(this.$refs.logo as HTMLInputElement).value = "";
|
||||
},
|
||||
resetImage(inputname: "icon" | "logo") {
|
||||
if (inputname == "icon") {
|
||||
this.icon = "";
|
||||
this.overwriteIcon = false;
|
||||
(this.$refs.icon_img as HTMLImageElement).style.display = "none";
|
||||
(this.$refs.icon as HTMLInputElement).value = "";
|
||||
} else {
|
||||
this.logo = "";
|
||||
this.overwriteLogo = false;
|
||||
(this.$refs.logo_img as HTMLImageElement).style.display = "none";
|
||||
(this.$refs.logo as HTMLInputElement).value = "";
|
||||
}
|
||||
},
|
||||
previewImage(inputname: "icon" | "logo") {
|
||||
let input = this.$refs[inputname] as HTMLInputElement;
|
||||
let previewElement = this.$refs[inputname + "_img"] as HTMLImageElement;
|
||||
|
@ -68,6 +120,12 @@ export default defineComponent({
|
|||
};
|
||||
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
|
||||
if (inputname == "icon") {
|
||||
this.overwriteIcon = true;
|
||||
} else {
|
||||
this.overwriteLogo = true;
|
||||
}
|
||||
} else {
|
||||
previewElement.src = "";
|
||||
previewElement.style.display = "none";
|
||||
|
@ -76,11 +134,11 @@ export default defineComponent({
|
|||
submit(e: any) {
|
||||
return this.uploadImage([
|
||||
{
|
||||
key: "club.icon" as SettingString,
|
||||
key: "club.icon",
|
||||
value: (this.$refs.icon as HTMLInputElement).files?.[0],
|
||||
},
|
||||
{
|
||||
key: "club.logo" as SettingString,
|
||||
key: "club.logo",
|
||||
value: (this.$refs.logo as HTMLInputElement).files?.[0],
|
||||
},
|
||||
]);
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
<label for="secure">Secure-Verbindung (setzen bei Port 465)</label>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label for="password">Passwort (optional)</label>
|
||||
<label for="password">Passwort (optional - leeres Feld setzt Passwort nicht zurück)</label>
|
||||
<input id="password" type="password" :readonly="!enableEdit" autocomplete="new-password" />
|
||||
</div>
|
||||
</BaseSetting>
|
||||
|
|
|
@ -54,26 +54,43 @@ export const useSettingStore = defineStore("setting", {
|
|||
key: K,
|
||||
value: SettingValueMapping[K]
|
||||
): Promise<AxiosResponse<any, any>> {
|
||||
return await http.put("/admin/setting", {
|
||||
setting: key,
|
||||
value: value,
|
||||
});
|
||||
return await http
|
||||
.put("/admin/setting", {
|
||||
setting: key,
|
||||
value: value,
|
||||
})
|
||||
.then((res) => {
|
||||
this.settings[key] = value;
|
||||
return res;
|
||||
});
|
||||
},
|
||||
async updateSettings<K extends SettingString>(
|
||||
data: { key: K; value: SettingValueMapping[K] }[]
|
||||
): Promise<AxiosResponse<any, any>> {
|
||||
return await http.put("/admin/setting/multi", data);
|
||||
return await http.put("/admin/setting/multi", data).then((res) => {
|
||||
for (const element of data) {
|
||||
this.settings[element.key] = element.value;
|
||||
}
|
||||
return res;
|
||||
});
|
||||
},
|
||||
async uploadImage(data: { key: SettingString; value?: File }[]): Promise<AxiosResponse<any, any>> {
|
||||
async uploadImage(data: { key: "club.logo" | "club.icon"; value?: File }[]): Promise<AxiosResponse<any, any>> {
|
||||
const formData = new FormData();
|
||||
for (let entry of data) {
|
||||
if (entry.value) formData.append(entry.key, entry.value);
|
||||
}
|
||||
return await http.put("/admin/setting/images", formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
});
|
||||
return await http
|
||||
.put("/admin/setting/images", formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
for (const element of data) {
|
||||
this.settings[element.key] = element.value ? "configured" : "";
|
||||
}
|
||||
return res;
|
||||
});
|
||||
},
|
||||
async resetSetting(key: SettingString): Promise<AxiosResponse<any, any>> {
|
||||
return await http.delete(`/admin/setting/${key}`);
|
||||
|
|
Loading…
Add table
Reference in a new issue