complete Complete User Request Submission section RAD-1

This commit is contained in:
2026-01-03 19:14:30 +03:30
commit 7137ec5792
393 changed files with 152602 additions and 0 deletions
@@ -0,0 +1,174 @@
<script setup>
import {onMounted, reactive, ref, watch} from "vue";
import {useMediumStore} from "../../store/Medium.js";
import Media from "./Media.vue";
import PaginationAjax from "../PaginationAjax.vue";
import AddMedium from "./AddMedia.vue";
const MediumStore = useMediumStore();
const emit = defineEmits(['update:modelValue', 'remove-item']);
const props = defineProps({
modelValue: { type: [Boolean, Array], required: true },
multiple: { type: Boolean, default: false },
uploadEndpoint: { type: String, default: '/admin/upload-medium' }
});
const selectImage = ref({});
const selectedImages = ref([]);
const isChooseMedium = ref(false);
const visible_modal_mediums = ref(false);
const hasLoaded = ref(false);
watch(() => props.modelValue, (newVal) => {
if (props.multiple) {
selectedImages.value = Array.isArray(newVal) ? newVal : [];
isChooseMedium.value = selectedImages.value.length > 0;
} else {
selectImage.value = newVal;
isChooseMedium.value = newVal && newVal.url ? true : false;
}
}, { immediate: true });
const diselect_medium = () => {
if (props.multiple) {
selectedImages.value = [];
isChooseMedium.value = false;
emit('update:modelValue', []);
} else {
selectImage.value = {};
isChooseMedium.value = false;
emit('update:modelValue', selectImage.value);
}
}
const getMediums = (page = 1) => {
axios.get(`/admin/get-medium?page=${page}`).then(res => {
MediumStore.mediums = res.data.data ?? [];
MediumStore.paginate.total = res.data.total ?? null;
MediumStore.paginate.last_page = res.data.last_page ?? null;
MediumStore.paginate.current_page = res.data.current_page ?? null;
MediumStore.paginate.links = res.data.links ?? null;
MediumStore.paginate.per_page = res.data.per_page ?? null;
hasLoaded.value = true;
})
}
const toggle_select_image = (medium, event) => {
if (props.multiple) {
const isCtrlPressed = event.ctrlKey || event.metaKey;
const existingIndex = selectedImages.value.findIndex(c => c.id === medium.id);
if (existingIndex > -1) {
selectedImages.value.splice(existingIndex, 1);
} else {
if (isCtrlPressed) {
selectedImages.value.push(medium);
} else {
selectedImages.value = [medium];
}
}
} else {
if (selectImage.value != medium) {
selectImage.value = medium;
} else {
selectImage.value = {};
}
}
}
const chooseMedium = () => {
isChooseMedium.value = true;
if (props.multiple) {
emit('update:modelValue', selectedImages.value);
} else {
emit('update:modelValue', selectImage.value);
}
toggle_show_modal();
}
const toggle_show_modal = () => {
visible_modal_mediums.value = !visible_modal_mediums.value;
if (!hasLoaded.value){
getMediums();
}
}
const removeSelectedImage = (index) => {
emit('remove-item', index);
}
</script>
<template>
<div class="card flex justify-center">
<div @click="toggle_show_modal" class="m-auto mt-6 grid grid-cols-a shadow-lg items-center border-3 border-client-gray/5 relative w-[14rem] content-center justify-center
rounded-2xl h-[14rem] cursor-pointer text-center text-client-Fontcolor/90 shadow-client-gray/10">
<div v-if="!isChooseMedium && (!selectImage?.url && selectedImages.length === 0)" class="grid grid-cols-a">
<div class="flex justify-center m-auto bg-client-gray/10 p-2 rounded-2xl">
<i class="fi fi-rr-cloud-upload-alt flex text-client-Fontcolor/80 m-auto text-4xl"></i>
</div>
<div class="absolute -top-3 -right-3 shadow-all p-3 rounded-3xl">
<i class="fi fi-rr-add-image flex text-xl"></i>
</div>
<span class="block text-sm text-client-Fontcolor/80 font-black mt-3">
{{ multiple ? 'انتخاب یا بارگذاری فایل‌ها' : 'انتخاب یا بارگذاری تصویر کاربر' }}
</span>
<span class="block text-xs mt-1">حداکثر آپلود ۲ مگابایت میباشد</span>
</div>
<div v-else-if="multiple && selectedImages.length > 0" class="p-2">
<h1 class="font-bold text-sm">
انتخاب فایل های بیشتر
</h1>
<div class="text-center mt-2">
<span class="text-xs text-gray-500">{{ selectedImages.length }} فایل انتخاب شده</span>
</div>
</div>
<div v-else-if="!multiple && selectImage?.url">
<figure class="h-[13rem] px-4 py-0">
<img class="w-full h-full object-contain" :src="selectImage.url" :alt="selectImage.filename">
</figure>
</div>
</div>
<Dialog v-model:visible="visible_modal_mediums" maximizable modal header="انتخاب رسانه"
:style="{ width: '75vw' , minHeight: '45rem' }"
:pt="{header : '!bg-client-primaryBlue'}"
:breakpoints="{ '1199px': '75vw', '575px': '90vw' }">
<template #header>
<div class="flex items-center justify-between w-full">
<h2 class="font-black text-lg">نمایش همه رسانه</h2>
<div class="flex gap-2 px-6" v-if="(selectImage && selectImage?.id) || (multiple && selectedImages.length > 0)">
<Button @click="chooseMedium" label="انتخاب میکنم" variant="outlined" size="small" severity="" class="" />
</div>
</div>
</template>
<div class="grid grid-cols-1 overflow-y-auto max-h-[12rem]">
<add-medium class="h-full w-full" :upload-endpoint="uploadEndpoint"></add-medium>
</div>
<div id="startModal" class="grid grid-cols-[repeat(auto-fill,_minmax(8rem,11rem))] mt-3 gap-4 justify-center">
<Media :action="false" @click="toggle_select_image(medium, $event)" v-for="(medium , index) in MediumStore.mediums"
:medium="medium" :class="['border-[2px] border-transparent transition-all',
{'!border-[2px] !border-client-primary' : multiple ? selectedImages.some(c => c.id === medium.id) : medium.id == selectImage.id }]" :key="index"></Media>
</div>
<PaginationAjax
:onPaginate="(page) => getMediums(page)"
top-scroll="startModal"
:total="MediumStore.paginate.total"
:current-page="MediumStore.paginate.current_page"
:perPage="MediumStore.paginate.per_page"
:lastPage="MediumStore.paginate.last_page"
:links="MediumStore.paginate.links">
</PaginationAjax>
</Dialog>
</div>
<div v-if="((selectImage && selectImage?.id) || (multiple && selectedImages.length > 0)) && isChooseMedium" class="grid mt-4 grid-cols-a justify-center gap-2">
<Button @click="diselect_medium" variant="outlined" size="small" severity="secondary" class="flex m-auto" label="لغو انتخاب"/>
<div v-if="multiple && selectedImages.length > 0" class="space-y-1">
<div v-for="(image, index) in selectedImages" :key="index" class="flex items-center justify-between bg-gray-100 p-2 rounded text-sm">
<span class="truncate text-xs px-4">{{ image.filename }}</span>
<Button icon="fi fi-rr-trash" size="small" severity="danger" text @click="removeSelectedImage(index)" />
</div>
</div>
</div>
</template>