diff --git a/main_dc/yalarba/easySite/easySite/app/components/BookingModal.vue b/main_dc/yalarba/easySite/easySite/app/components/BookingModal.vue new file mode 100644 index 0000000..0644545 --- /dev/null +++ b/main_dc/yalarba/easySite/easySite/app/components/BookingModal.vue @@ -0,0 +1,31 @@ + + + \ No newline at end of file diff --git a/main_dc/yalarba/easySite/easySite/app/components/ImageGallery.vue b/main_dc/yalarba/easySite/easySite/app/components/ImageGallery.vue new file mode 100644 index 0000000..5f61e63 --- /dev/null +++ b/main_dc/yalarba/easySite/easySite/app/components/ImageGallery.vue @@ -0,0 +1,32 @@ + + + \ No newline at end of file diff --git a/main_dc/yalarba/easySite/easySite/app/components/layout/ObjectsNavigation.vue b/main_dc/yalarba/easySite/easySite/app/components/layout/ObjectsNavigation.vue new file mode 100644 index 0000000..aa0019e --- /dev/null +++ b/main_dc/yalarba/easySite/easySite/app/components/layout/ObjectsNavigation.vue @@ -0,0 +1,117 @@ + + + + + + \ No newline at end of file diff --git a/main_dc/yalarba/easySite/easySite/app/pages/objects/[id]/edit.vue b/main_dc/yalarba/easySite/easySite/app/pages/objects/[id]/edit.vue index e3b2099..2ad9a4e 100644 --- a/main_dc/yalarba/easySite/easySite/app/pages/objects/[id]/edit.vue +++ b/main_dc/yalarba/easySite/easySite/app/pages/objects/[id]/edit.vue @@ -1,42 +1,50 @@ - @@ -67,7 +75,7 @@ const mockObject: ObjectData = { id: 1, title: 'Гостевой дом "У озера"', type: 'guest_house', - description: 'Уютный гостевой дом на берегу живописного озера в Карелии', + description: 'Уютный гостевой дом на берегу живописного озера в Карелии. Идеальное место для отдыха от городской суеты.', city: 'Карелия', address: 'ул. Озерная, 15', price: 2800, @@ -92,16 +100,16 @@ onMounted(async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const handleSubmit = async (formData: any) => { updating.value = true - + try { // Имитация обновления await new Promise(resolve => setTimeout(resolve, 1000)) - + console.log('Обновление объекта:', { id: parseInt(route.params.id as string), ...formData }) - + alert('Объект успешно обновлен!') await navigateTo(`/objects/${route.params.id}`) } catch (error) { @@ -116,4 +124,149 @@ const handleCancel = () => { const objectId = route.params.id navigateTo(`/objects/${objectId}`) } - \ No newline at end of file + + + \ No newline at end of file diff --git a/main_dc/yalarba/easySite/easySite/app/pages/objects/[id]/index.vue b/main_dc/yalarba/easySite/easySite/app/pages/objects/[id]/index.vue index a10c01f..5a9caec 100644 --- a/main_dc/yalarba/easySite/easySite/app/pages/objects/[id]/index.vue +++ b/main_dc/yalarba/easySite/easySite/app/pages/objects/[id]/index.vue @@ -1,211 +1,986 @@ - \ No newline at end of file + +const openGallery = (index: number) => { + galleryIndex.value = index + showGallery.value = true +} + +const toggleObjectStatus = async () => { + if (!object.value) return + + object.value.isActive = !object.value.isActive + // В реальном приложении здесь был бы API-запрос +} + +const handleBooking = (bookingData: any) => { + console.log('Booking confirmed:', bookingData) + showBookingModal.value = false + // Здесь обработка бронирования +} + + + \ No newline at end of file diff --git a/main_dc/yalarba/easySite/easySite/app/pages/objects/create.vue b/main_dc/yalarba/easySite/easySite/app/pages/objects/create.vue index 3669c8f..8cba4d8 100644 --- a/main_dc/yalarba/easySite/easySite/app/pages/objects/create.vue +++ b/main_dc/yalarba/easySite/easySite/app/pages/objects/create.vue @@ -1,14 +1,28 @@ - @@ -45,4 +59,68 @@ const handleSubmit = async (formData: any) => { const handleCancel = () => { navigateTo('/objects/my-objects') } - \ No newline at end of file + + + \ No newline at end of file diff --git a/main_dc/yalarba/easySite/easySite/app/pages/objects/index.vue b/main_dc/yalarba/easySite/easySite/app/pages/objects/index.vue index a10c01f..b41834d 100644 --- a/main_dc/yalarba/easySite/easySite/app/pages/objects/index.vue +++ b/main_dc/yalarba/easySite/easySite/app/pages/objects/index.vue @@ -1,103 +1,144 @@ - @@ -112,8 +153,40 @@ interface ObjectItem { image: string description: string isActive: boolean + createdAt: string } +// Навигация +useHead({ + title: 'Все объекты - EasySite' +}) + +// Состояние +const objects = ref([]) +const loading = ref(true) +const showFilters = ref(false) +const viewMode = ref<'grid' | 'list'>('grid') +const sortBy = ref<'title' | 'price' | 'rating' | 'city'>('title') +const sortOrder = ref<'asc' | 'desc'>('asc') +const currentPage = ref(1) +const itemsPerPage = 9 + +const filters = ref({ + search: '', + type: '', + city: '', + maxPrice: null as number | null, + minRating: 0 +}) + +// Быстрые фильтры +const quickTypes = [ + { value: 'hotel', label: 'Гостиницы', icon: '🏨' }, + { value: 'sanatorium', label: 'Санатории', icon: '🏥' }, + { value: 'tour', label: 'Туры', icon: '🧳' }, + { value: 'restaurant', label: 'Рестораны', icon: '🍴' } +] + // Мок-данные const mockObjects: ObjectItem[] = [ { @@ -124,88 +197,407 @@ const mockObjects: ObjectItem[] = [ price: 4500, rating: 4.8, image: '/images/hotels/edelweiss.jpg', - description: 'Комфортабельный отель в горах с видом на море', - isActive: true + description: 'Комфортабельный отель в горах с видом на море. Идеальное место для отдыха от городской суеты.', + isActive: true, + createdAt: '2024-01-15' }, { id: 2, - title: 'Тур по Алтаю', - type: 'tour', - city: 'Горно-Алтайск', - price: 12500, - rating: 4.9, - image: '/images/tours/altai.jpg', - description: '7-дневный тур по самым живописным местам Алтая', - isActive: true - }, - { - id: 3, title: 'Санаторий "Здоровье"', type: 'sanatorium', city: 'Кисловодск', price: 3200, rating: 4.6, image: '/images/sanatoriums/health.jpg', - description: 'Лечебно-оздоровительный комплекс с минеральными водами', - isActive: true + description: 'Лечебно-оздоровительный комплекс с минеральными водами и современным оборудованием.', + isActive: true, + createdAt: '2024-01-10' + }, + { + id: 3, + title: 'Тур по Золотому кольцу', + type: 'tour', + city: 'Москва', + price: 12500, + rating: 4.9, + image: '/images/tours/golden-ring.jpg', + description: '7-дневный тур по древним городам России с опытным гидом и комфортабельным транспортом.', + isActive: true, + createdAt: '2024-01-08' } ] -const objects = ref(mockObjects) -const loading = ref(false) - -const filters = ref({ - search: '', - type: '', - city: '', - maxPrice: null as number | null +// Вычисляемые свойства +const activeFiltersCount = computed(() => { + return Object.values(filters.value).filter(val => + val !== '' && val !== null && val !== 0 + ).length }) -const searchObjects = async () => { - loading.value = true - // Имитация загрузки - await new Promise(resolve => setTimeout(resolve, 500)) - - let filtered = [...mockObjects] - +const filteredObjects = computed(() => { + let filtered = [...objects.value] + if (filters.value.search) { const search = filters.value.search.toLowerCase() - filtered = filtered.filter(obj => + filtered = filtered.filter(obj => obj.title.toLowerCase().includes(search) || obj.city.toLowerCase().includes(search) || obj.description.toLowerCase().includes(search) ) } - + if (filters.value.type) { filtered = filtered.filter(obj => obj.type === filters.value.type) } - + if (filters.value.city) { - filtered = filtered.filter(obj => + filtered = filtered.filter(obj => obj.city.toLowerCase().includes(filters.value.city.toLowerCase()) ) } - + if (filters.value.maxPrice) { filtered = filtered.filter(obj => obj.price <= filters.value.maxPrice!) } - - objects.value = filtered - loading.value = false + + if (filters.value.minRating) { + filtered = filtered.filter(obj => obj.rating >= filters.value.minRating!) + } + + return filtered +}) + +const sortedObjects = computed(() => { + const sorted = [...filteredObjects.value].sort((a, b) => { + let aVal = a[sortBy.value] + let bVal = b[sortBy.value] + + if (sortBy.value === 'price' || sortBy.value === 'rating') { + return sortOrder.value === 'asc' ? aVal - bVal : bVal - aVal + } + + aVal = String(aVal).toLowerCase() + bVal = String(bVal).toLowerCase() + + if (sortOrder.value === 'asc') { + return aVal.localeCompare(bVal) + } else { + return bVal.localeCompare(aVal) + } + }) + + return sorted +}) + +const paginatedObjects = computed(() => { + const start = (currentPage.value - 1) * itemsPerPage + return sortedObjects.value.slice(start, start + itemsPerPage) +}) + +const totalPages = computed(() => { + return Math.ceil(filteredObjects.value.length / itemsPerPage) +}) + +// Методы +const toggleQuickFilter = (type: string) => { + filters.value.type = filters.value.type === type ? '' : type + applyFilters() } -const resetSearch = async () => { +const applyFilters = () => { + currentPage.value = 1 +} + +const resetFilters = () => { filters.value = { search: '', type: '', city: '', - maxPrice: null + maxPrice: null, + minRating: 0 } - objects.value = mockObjects + currentPage.value = 1 } const navigateToObject = (id: number) => { navigateTo(`/objects/${id}`) } - \ No newline at end of file + +// Инициализация +onMounted(async () => { + loading.value = true + await new Promise(resolve => setTimeout(resolve, 800)) + objects.value = mockObjects + loading.value = false +}) + +// Следим за изменениями фильтров +watch([filters, sortBy, sortOrder], () => { + applyFilters() +}) + + + \ No newline at end of file diff --git a/main_dc/yalarba/easySite/easySite/app/pages/objects/my-objects.vue b/main_dc/yalarba/easySite/easySite/app/pages/objects/my-objects.vue index b24073c..23fcadd 100644 --- a/main_dc/yalarba/easySite/easySite/app/pages/objects/my-objects.vue +++ b/main_dc/yalarba/easySite/easySite/app/pages/objects/my-objects.vue @@ -1,29 +1,32 @@ - @@ -186,7 +174,7 @@ const mockMyObjects: MyObjectItem[] = [ { id: 2, title: 'Экскурсия по историческому центру', - type: 'excursion', + type: 'tour', city: 'Санкт-Петербург', price: 1500, isActive: true, @@ -214,25 +202,25 @@ const filters = ref({ const applyFilters = () => { let filtered = [...mockMyObjects] - + if (filters.value.status) { - filtered = filtered.filter(obj => + filtered = filtered.filter(obj => filters.value.status === 'active' ? obj.isActive : !obj.isActive ) } - + if (filters.value.type) { filtered = filtered.filter(obj => obj.type === filters.value.type) } - + if (filters.value.search) { const search = filters.value.search.toLowerCase() - filtered = filtered.filter(obj => + filtered = filtered.filter(obj => obj.title.toLowerCase().includes(search) || obj.city.toLowerCase().includes(search) ) } - + myObjects.value = filtered } @@ -247,7 +235,6 @@ const resetFilters = () => { const deleteObject = async (id: number) => { if (confirm('Вы уверены, что хотите удалить этот объект?')) { - // Имитация удаления myObjects.value = myObjects.value.filter(obj => obj.id !== id) } } @@ -274,4 +261,266 @@ const formatPrice = (price: number) => { const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString('ru-RU') } - \ No newline at end of file + + + \ No newline at end of file