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,179 @@
<script setup>
import { ref, watch } from 'vue';
import Pagination from './Pagination.vue';
import DataTable from 'primevue/datatable';
import Column from 'primevue/column';
import Button from 'primevue/button';
import InputText from 'primevue/inputtext';
import Toolbar from 'primevue/toolbar';
const props = defineProps({
data: {
type: Array,
required: true,
default: () => []
},
columns: {
type: Array,
required: true,
default: () => []
},
selectable: {
type: Boolean,
default: false
},
modelValue: {
type: Array,
default: () => []
},
pagination: {
type: Object,
default: () => null
},
searchable: {
type: Boolean,
default: true
},
searchValue: {
type: String,
default: ''
}
});
const emit = defineEmits(['update:modelValue', 'selection-change', 'page-change', 'search-change']);
const localSelection = ref(props.modelValue);
watch(() => props.modelValue, (newValue) => {
localSelection.value = newValue;
}, { immediate: true });
const handleSelectionChange = (event) => {
localSelection.value = event;
emit('update:modelValue', event);
emit('selection-change', event);
};
const localSearchValue = ref(props.searchValue);
watch(() => props.searchValue, (newValue) => {
localSearchValue.value = newValue;
}, { immediate: true });
const handleSearchClick = () => {
emit('search-change', localSearchValue.value);
};
const renderColumnContent = (column, data) => {
let content = '';
if (column.render && typeof column.render === 'function') {
content = column.render(data);
} else {
content = data[column.key];
}
const defaultStyle = '!text-[11px] !font-normal';
const customStyle = column.style || defaultStyle;
return `<span class="${customStyle} text-right wrap-break-word text-sm">${content}</span>`;
};
const getColumnStyle = (column) => {
const baseStyle = { minWidth: '120px' };
if (column.width) {
baseStyle.width = column.width + 'px';
baseStyle.minWidth = column.width + 'px';
baseStyle.maxWidth = column.width + 'px';
}
return baseStyle;
};
</script>
<template>
<div class="table-generic">
<div v-if="searchable" class="p-4">
<Toolbar class="">
<template #start>
<div class="grid grid-cols-2a justify-start gap-2">
<InputText
size="small"
class="placeholder:!font-light placeholder:!text-xs"
placeholder="جستجو..."
type="text"
v-model="localSearchValue"
/>
<Button
:pt="{icon : 'flex'}"
icon="fi fi-rr-search"
class="!text-xs"
severity="secondary"
@click="handleSearchClick"
/>
</div>
<div v-if="localSelection && localSelection.length > 0" class="mr-2 !h-9 grid grid-cols-1">
<slot name="bulk-action" :selection="localSelection"></slot>
</div>
</template>
<template #end>
<slot name="toolbar-actions"></slot>
</template>
</Toolbar>
</div>
<DataTable
:value="data"
dataKey="id"
v-model:selection="localSelection"
:showGridlines="false"
:stripedRows="false"
@selection-change="handleSelectionChange"
>
<template #empty>
<div class="flex justify-center py-4 items-center h-full">
<span class="text-center text-sm">هیچ داده‌ای پیدا نشده!</span>
</div>
</template>
<Column
v-if="selectable"
selectionMode="multiple"
headerStyle="width: 4rem"
/>
<Column
v-for="column in columns"
:key="column.key"
:field="column.key"
:header="column.title"
:sortable="column.hasSort === true"
:style="getColumnStyle(column)"
>
<template #body="{ data }">
<slot v-if="column.slot" :name="`column-${column.key}`" :data="data" :column="column">
<div v-html="renderColumnContent(column, data)"></div>
</slot>
<div v-else v-html="renderColumnContent(column, data)"></div>
</template>
</Column>
</DataTable>
<Pagination
v-if="pagination && pagination.total"
:total="pagination.total"
:current-page="pagination.current_page"
:perPage="pagination.per_page"
:lastPage="pagination.last_page"
:links="pagination.links"
@page-change="(page) => emit('page-change', page)"
/>
</div>
</template>
<style scoped>
.table-generic {
width: 100%;
}
</style>