added date filter
This commit is contained in:
@@ -82,6 +82,13 @@ class BuildFiltersTask
|
|||||||
param: 'sort'
|
param: 'sort'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->filterBuilder->add(
|
||||||
|
key: 'date_filter',
|
||||||
|
type: 'date',
|
||||||
|
value: $filters['date'] ?? null,
|
||||||
|
param: 'date'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
return $this->filterBuilder->get();
|
return $this->filterBuilder->get();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,18 @@ class GetPostsTask
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
->when(!empty($filters['date']), function ($query) use ($filters) {
|
||||||
|
$dates = $filters['date'];
|
||||||
|
if ($dates[1] === null) {
|
||||||
|
// Если пришла одна дата, ищем по конкретной дате
|
||||||
|
$query->whereDate('publish_at', \Carbon\Carbon::createFromFormat('d.m.Y', $dates[0])->format('Y-m-d'));
|
||||||
|
} else {
|
||||||
|
// Если пришли две даты, ищем в диапазоне
|
||||||
|
$startDate = \Carbon\Carbon::createFromFormat('d.m.Y', $dates[0])->format('Y-m-d');
|
||||||
|
$endDate = \Carbon\Carbon::createFromFormat('d.m.Y', $dates[1])->format('Y-m-d');
|
||||||
|
$query->whereBetween('publish_at', [$startDate, $endDate]);
|
||||||
|
}
|
||||||
|
})
|
||||||
->when(!empty($filters['search']), function ($query) use ($filters) {
|
->when(!empty($filters['search']), function ($query) use ($filters) {
|
||||||
$query->whereRaw('LOWER(title) like ?', ["%".strtolower($filters['search'])."%"]);
|
$query->whereRaw('LOWER(title) like ?', ["%".strtolower($filters['search'])."%"]);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class IndexPostController extends Controller
|
|||||||
|
|
||||||
public function __invoke(Request $request)
|
public function __invoke(Request $request)
|
||||||
{
|
{
|
||||||
$filters = $request->only(['search', 'category', 'tag', 'sort', 'page']);
|
$filters = $request->only(['search', 'category', 'tag', 'sort', 'page', 'date']);
|
||||||
|
|
||||||
$data = $this->listPostsAction->run($filters);
|
$data = $this->listPostsAction->run($filters);
|
||||||
|
|
||||||
|
|||||||
Generated
+26
@@ -19,6 +19,7 @@
|
|||||||
"@preline/scrollspy": "^2.0.0",
|
"@preline/scrollspy": "^2.0.0",
|
||||||
"@preline/select": "^2.5.0",
|
"@preline/select": "^2.5.0",
|
||||||
"@vue/server-renderer": "^3.5.12",
|
"@vue/server-renderer": "^3.5.12",
|
||||||
|
"@vuepic/vue-datepicker": "^11.0.2",
|
||||||
"daisyui": "^4.12.14",
|
"daisyui": "^4.12.14",
|
||||||
"flowbite": "^2.5.2",
|
"flowbite": "^2.5.2",
|
||||||
"fslightbox": "^3.4.1",
|
"fslightbox": "^3.4.1",
|
||||||
@@ -1247,6 +1248,21 @@
|
|||||||
"integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==",
|
"integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@vuepic/vue-datepicker": {
|
||||||
|
"version": "11.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vuepic/vue-datepicker/-/vue-datepicker-11.0.2.tgz",
|
||||||
|
"integrity": "sha512-uHh78mVBXCEjam1uVfTzZ/HkyDwut/H6b2djSN9YTF+l/EA+XONfdCnOVSi1g+qVGSy65DcQAwyBNidAssnudQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"date-fns": "^4.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.12.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": ">=3.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.14.1",
|
"version": "8.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
||||||
@@ -2283,6 +2299,16 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/date-fns": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/kossnocorp"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
"@preline/scrollspy": "^2.0.0",
|
"@preline/scrollspy": "^2.0.0",
|
||||||
"@preline/select": "^2.5.0",
|
"@preline/select": "^2.5.0",
|
||||||
"@vue/server-renderer": "^3.5.12",
|
"@vue/server-renderer": "^3.5.12",
|
||||||
|
"@vuepic/vue-datepicker": "^11.0.2",
|
||||||
"daisyui": "^4.12.14",
|
"daisyui": "^4.12.14",
|
||||||
"flowbite": "^2.5.2",
|
"flowbite": "^2.5.2",
|
||||||
"fslightbox": "^3.4.1",
|
"fslightbox": "^3.4.1",
|
||||||
|
|||||||
@@ -21,9 +21,11 @@ import IsOnlineFilter from "@/componentss/shared/filter/filters/IsOnlineFilter.v
|
|||||||
import EventListSearch from "@/componentss/features/events/components/EventListSearch.vue";
|
import EventListSearch from "@/componentss/features/events/components/EventListSearch.vue";
|
||||||
import BreadcrumbsItem from "@/componentss/shared/Breadcrumbs/BreadcrumbsItem.vue";
|
import BreadcrumbsItem from "@/componentss/shared/Breadcrumbs/BreadcrumbsItem.vue";
|
||||||
import BaseBreadcrumbs from "@/componentss/shared/Breadcrumbs/BaseBreadcrumbs.vue";
|
import BaseBreadcrumbs from "@/componentss/shared/Breadcrumbs/BaseBreadcrumbs.vue";
|
||||||
|
import DateFilter from "@/componentss/shared/filter/filters/DateFilter.vue";
|
||||||
export default {
|
export default {
|
||||||
name: "Index",
|
name: "Index",
|
||||||
components: {
|
components: {
|
||||||
|
DateFilter,
|
||||||
BaseBreadcrumbs, BreadcrumbsItem,
|
BaseBreadcrumbs, BreadcrumbsItem,
|
||||||
WhenVisible,
|
WhenVisible,
|
||||||
EventListSearch, IsOnlineFilter, BasicPagination, EventArchiveListBreadcrumbs, BasicPageWrapper, BasicPageContainer,
|
EventListSearch, IsOnlineFilter, BasicPagination, EventArchiveListBreadcrumbs, BasicPageWrapper, BasicPageContainer,
|
||||||
@@ -76,7 +78,7 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
hasActiveFilters() {
|
hasActiveFilters() {
|
||||||
return this.filters.category_filter.value || this.filters.tag_filter.value || this.filters.search_filter.value;
|
return this.filters.category_filter.value || this.filters.tag_filter.value || this.filters.search_filter.value || this.filters.date_filter.value;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -102,6 +104,7 @@ export default {
|
|||||||
<PostListSearch :search_filter="filters.search_filter" />
|
<PostListSearch :search_filter="filters.search_filter" />
|
||||||
<BasicListFilter>
|
<BasicListFilter>
|
||||||
<SortingByFilter :sortingBy_filter="filters.sortingBy_filter" />
|
<SortingByFilter :sortingBy_filter="filters.sortingBy_filter" />
|
||||||
|
<DateFilter :date_filter="filters.date_filter" />
|
||||||
<CategoryFilter :categories="categories" :category_filter="filters.category_filter" />
|
<CategoryFilter :categories="categories" :category_filter="filters.category_filter" />
|
||||||
<TagFilter :tags="tags" :tag_filter="filters.tag_filter" />
|
<TagFilter :tags="tags" :tag_filter="filters.tag_filter" />
|
||||||
</BasicListFilter>
|
</BasicListFilter>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {linksReform} from "@/mixins/LinksReform.js";
|
|||||||
import YSmartCaptcha from 'vue3-yandex-smartcaptcha'
|
import YSmartCaptcha from 'vue3-yandex-smartcaptcha'
|
||||||
import cookieMixin from "@/mixins/cookieMixin.js";
|
import cookieMixin from "@/mixins/cookieMixin.js";
|
||||||
import store from '@/store/index.js';
|
import store from '@/store/index.js';
|
||||||
|
import '@vuepic/vue-datepicker/dist/main.css';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import TagBadge from "@/componentss/shared/badge/badges/TagBadge.vue";
|
|||||||
import SortingByBadge from "@/componentss/shared/badge/badges/SortingByBadge.vue";
|
import SortingByBadge from "@/componentss/shared/badge/badges/SortingByBadge.vue";
|
||||||
import IsOnlineBadge from "@/componentss/shared/badge/badges/IsOnlineBadge.vue";
|
import IsOnlineBadge from "@/componentss/shared/badge/badges/IsOnlineBadge.vue";
|
||||||
import EduBudgetBadge from "@/componentss/shared/badge/badges/EduBudgetBadge.vue";
|
import EduBudgetBadge from "@/componentss/shared/badge/badges/EduBudgetBadge.vue";
|
||||||
|
import DateBadge from "@/componentss/shared/badge/badges/DateBadge.vue";
|
||||||
export default {
|
export default {
|
||||||
name: "BasicListBadge",
|
name: "BasicListBadge",
|
||||||
components: {
|
components: {
|
||||||
@@ -23,7 +24,8 @@ export default {
|
|||||||
TagBadge,
|
TagBadge,
|
||||||
SortingByBadge,
|
SortingByBadge,
|
||||||
IsOnlineBadge,
|
IsOnlineBadge,
|
||||||
EduBudgetBadge
|
EduBudgetBadge,
|
||||||
|
DateBadge
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -37,7 +39,8 @@ export default {
|
|||||||
tag: 'TagBadge',
|
tag: 'TagBadge',
|
||||||
sort: 'SortingByBadge',
|
sort: 'SortingByBadge',
|
||||||
is_online: 'IsOnlineBadge',
|
is_online: 'IsOnlineBadge',
|
||||||
budget: 'EduBudgetBadge'
|
budget: 'EduBudgetBadge',
|
||||||
|
date: 'DateBadge'
|
||||||
};
|
};
|
||||||
return componentMap[type] || null;
|
return componentMap[type] || null;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<span v-if="this.filter.value !== null" class="inline-flex items-center gap-x-1.5 py-1.5 ps-3 pe-2 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
|
||||||
|
Дата: {{ firstDate }} {{ secondDate }}
|
||||||
|
<button @click.prevent="clearFilter" type="button" class="shrink-0 size-4 inline-flex items-center justify-center rounded-full hover:bg-primary-lighter focus:outline-none focus:bg-blue-200 focus:text-blue-500">
|
||||||
|
<span class="sr-only">Remove badge</span>
|
||||||
|
<svg class="shrink-0 size-3" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M18 6 6 18"></path>
|
||||||
|
<path d="m6 6 12 12"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Link } from "@inertiajs/vue3";
|
||||||
|
import slugify from "slugify";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "DateBadge",
|
||||||
|
components: { Link },
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
firstDate() {
|
||||||
|
return this.filter.value[0]
|
||||||
|
},
|
||||||
|
secondDate() {
|
||||||
|
return this.filter.value[1] ? "- " + this.filter.value[1] : ""
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clearFilter() {
|
||||||
|
let url = new URL(window.location.href);
|
||||||
|
|
||||||
|
// Создаем массив для хранения всех ключей, которые нужно удалить
|
||||||
|
const keysToDelete = [];
|
||||||
|
|
||||||
|
// Перебираем все параметры и добавляем ключи, начинающиеся с 'category', в массив
|
||||||
|
for (const [key] of url.searchParams) {
|
||||||
|
if (key.startsWith(this.filter.param)) {
|
||||||
|
keysToDelete.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Удаляем все ключи из массива
|
||||||
|
keysToDelete.forEach(key => url.searchParams.delete(key));
|
||||||
|
|
||||||
|
let newUrl = url.toString();
|
||||||
|
this.$inertia.visit(newUrl, {
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
filter: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div class="mt-2">
|
||||||
|
<VueDatePicker data-color="text-primary"
|
||||||
|
cancel-text="Назад"
|
||||||
|
select-text="Выбрать"
|
||||||
|
:model-value="date"
|
||||||
|
@update:model-value="filter"
|
||||||
|
:hide-input-icon="false"
|
||||||
|
placeholder="Выберете дату"
|
||||||
|
v-model="date" locale="ru"
|
||||||
|
range model-type="dd.MM.yyyy"
|
||||||
|
:enable-time-picker="false"
|
||||||
|
>
|
||||||
|
<template #input-icon>
|
||||||
|
<BasicIcon class="input-slot-image w-4 h-4 ml-2 text-gray-600" name="calendar-date-range" />
|
||||||
|
</template>
|
||||||
|
<template #clear-icon="{ clear }">
|
||||||
|
<BasicIcon class="input-slot-image w-4 h-4 mr-2 text-gray-600" @click="clear" name="delete" />
|
||||||
|
</template>
|
||||||
|
</VueDatePicker>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import {Link} from "@inertiajs/vue3";
|
||||||
|
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||||
|
import {debounce} from "lodash";
|
||||||
|
import VueDatePicker from '@vuepic/vue-datepicker';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "DateFilter",
|
||||||
|
components: {
|
||||||
|
BasicIcon,
|
||||||
|
Link,
|
||||||
|
VueDatePicker
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
date: this.date_filter.value ?? null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
filter: debounce(function () {
|
||||||
|
let url = new URL(window.location.href);
|
||||||
|
// Создаем массив для хранения всех ключей, которые нужно удалить
|
||||||
|
const keysToDelete = [];
|
||||||
|
|
||||||
|
// Перебираем все параметры и добавляем ключи, начинающиеся с 'budget', в массив
|
||||||
|
for (const [key] of url.searchParams) {
|
||||||
|
if (key.startsWith('date')) {
|
||||||
|
keysToDelete.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Удаляем все ключи из массива
|
||||||
|
keysToDelete.forEach(key => url.searchParams.delete(key));
|
||||||
|
url.searchParams.delete('page');
|
||||||
|
let newUrl = url.toString();
|
||||||
|
this.$inertia.visit(newUrl, {
|
||||||
|
method: 'get',
|
||||||
|
preserveState: true,
|
||||||
|
data: {
|
||||||
|
date: this.date,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}, 500),
|
||||||
|
clearFilter() {
|
||||||
|
let url = new URL(window.location.href);
|
||||||
|
// Создаем массив для хранения всех ключей, которые нужно удалить
|
||||||
|
const keysToDelete = [];
|
||||||
|
|
||||||
|
// Перебираем все параметры и добавляем ключи, начинающиеся с 'budget', в массив
|
||||||
|
for (const [key] of url.searchParams) {
|
||||||
|
if (key.startsWith('date')) {
|
||||||
|
keysToDelete.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Удаляем все ключи из массива
|
||||||
|
keysToDelete.forEach(key => url.searchParams.delete(key));
|
||||||
|
this.budgetEdu = [];
|
||||||
|
let newUrl = url.toString();
|
||||||
|
this.$inertia.visit(newUrl, {
|
||||||
|
method: 'get',
|
||||||
|
preserveState: true,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
date_filter: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--dp-font-size: 0.875rem; /*Default font-size*/
|
||||||
|
--dp-border-radius: 0.5rem; /*Configurable border-radius*/
|
||||||
|
--dp-input-icon-padding: 30px !important; /*Padding on the left side of the input if icon is present*/
|
||||||
|
}
|
||||||
|
.dp--clear-btn {
|
||||||
|
color: #0d120a;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user