diff --git a/LabWork4Report.docx b/LabWork4Report.docx new file mode 100644 index 0000000..4457c87 Binary files /dev/null and b/LabWork4Report.docx differ diff --git a/lab3/LabWork3Report.docx b/lab3/LabWork3Report.docx deleted file mode 100644 index 64e3f09..0000000 Binary files a/lab3/LabWork3Report.docx and /dev/null differ diff --git a/lab3/my-project/punkrock.html b/lab3/my-project/punkrock.html deleted file mode 100644 index f4e5dd0..0000000 --- a/lab3/my-project/punkrock.html +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - Панкуха - - - - - - - - - - - - - -
-
-
-
-

- Тут будет перечень исполнителей, принадлежащих жанру -

-

- Инфа будет +- такая -

- - -
-
-
- -
-
-
-

Добавить исполнителя

- -
- -
- - -
- -
- - -
- - - -
- - -
- - -
- - -
- - - -
-
-
-
- - -
- - - -
- - - - - - - - - \ No newline at end of file diff --git a/lab3/my-project/src/main.js b/lab3/my-project/src/main.js deleted file mode 100644 index 5a4a3a1..0000000 --- a/lab3/my-project/src/main.js +++ /dev/null @@ -1,27 +0,0 @@ -import './style.css' -import javascriptLogo from './javascript.svg' -import viteLogo from '/vite.svg' -import { setupCounter } from './counter.js' -import 'bootstrap/dist/css/bootstrap.min.css'; -import 'bootstrap-icons/font/bootstrap-icons.css'; -import 'bootstrap'; - -document.querySelector('#app').innerHTML = ` -
- - - - - - -

Hello Vite!

-
- -
-

- Click on the Vite logo to learn more -

-
-` - -setupCounter(document.querySelector('#counter')) diff --git a/lab3/~$bWork3Report.docx b/lab3/~$bWork3Report.docx deleted file mode 100644 index 4eed6a4..0000000 Binary files a/lab3/~$bWork3Report.docx and /dev/null differ diff --git a/lab3/my-project/.eslintrc.json b/lab4/my-project/.eslintrc.json similarity index 100% rename from lab3/my-project/.eslintrc.json rename to lab4/my-project/.eslintrc.json diff --git a/lab3/my-project/.gitignore b/lab4/my-project/.gitignore similarity index 100% rename from lab3/my-project/.gitignore rename to lab4/my-project/.gitignore diff --git a/lab3/my-project/.prettierrc.json b/lab4/my-project/.prettierrc.json similarity index 100% rename from lab3/my-project/.prettierrc.json rename to lab4/my-project/.prettierrc.json diff --git a/lab3/my-project/catalog.html b/lab4/my-project/catalog.html similarity index 100% rename from lab3/my-project/catalog.html rename to lab4/my-project/catalog.html diff --git a/lab4/my-project/db.json b/lab4/my-project/db.json new file mode 100644 index 0000000..dfed923 --- /dev/null +++ b/lab4/my-project/db.json @@ -0,0 +1,82 @@ +{ + "artists": [ + { + "id": "28d5", + "name": "что-то", + "description": "цуцй", + "epochId": 1, + "countryId": 2 + }, + { + "id": "9e30", + "name": "что-то", + "description": "бб", + "epochId": 2, + "countryId": 1 + }, + { + "id": "8ugr", + "name": "Летов Игорь", + "description": "Беспонтовый пирожок", + "epochId": 1, + "countryId": 4 + }, + { + "id": "0823", + "name": "киш", + "description": "бб", + "epochId": 1, + "countryId": 4 + }, + { + "id": "94a1", + "name": "dfad", + "description": "dfas", + "epochId": 2, + "countryId": 1 + }, + { + "id": "ee1c", + "name": "Отчет1", + "description": "Очень крутой отчет", + "epochId": 3, + "countryId": 1 + } + ], + "countries": [ + { + "id": "1", + "name": "Россия" + }, + { + "id": "2", + "name": "США" + }, + { + "id": "3", + "name": "ОАЭ" + }, + { + "id": "4", + "name": "Тайга" + } + ], + "epochs": [ + { + "id": "1", + "name": "1980-е" + }, + { + "id": "2", + "name": "1990-е" + }, + { + "id": "3", + "name": "2000-е" + }, + { + "id": "4", + "name": "2010-е" + } + ] +} \ No newline at end of file diff --git a/lab3/my-project/grob.html b/lab4/my-project/grob.html similarity index 100% rename from lab3/my-project/grob.html rename to lab4/my-project/grob.html diff --git a/lab3/my-project/grobKaifIliBolshe.html b/lab4/my-project/grobKaifIliBolshe.html similarity index 100% rename from lab3/my-project/grobKaifIliBolshe.html rename to lab4/my-project/grobKaifIliBolshe.html diff --git a/lab3/my-project/index.html b/lab4/my-project/index.html similarity index 100% rename from lab3/my-project/index.html rename to lab4/my-project/index.html diff --git a/lab4/my-project/index.zip b/lab4/my-project/index.zip new file mode 100644 index 0000000..1597430 Binary files /dev/null and b/lab4/my-project/index.zip differ diff --git a/lab3/my-project/package-lock.json b/lab4/my-project/package-lock.json similarity index 100% rename from lab3/my-project/package-lock.json rename to lab4/my-project/package-lock.json diff --git a/lab3/my-project/package.json b/lab4/my-project/package.json similarity index 74% rename from lab3/my-project/package.json rename to lab4/my-project/package.json index f07b1cc..4a916a1 100644 --- a/lab3/my-project/package.json +++ b/lab4/my-project/package.json @@ -9,7 +9,8 @@ "preview": "vite preview", "lint": "eslint .", "format": "prettier --write .", - "prepare": "husky install" + "prepare": "husky install", + "start:server": "json-server --watch db.json --port 3000" }, "dependencies": { "bootstrap": "^5.3.3", @@ -20,6 +21,7 @@ "eslint-config-prettier": "^10.0.2", "prettier": "^3.2.5", "vite": "^5.1.0", - "vite-plugin-html": "^3.2.0" + "vite-plugin-html": "^3.2.0", + "json-server": "^0.17.4" } } \ No newline at end of file diff --git a/lab3/my-project/public/vite.svg b/lab4/my-project/public/vite.svg similarity index 100% rename from lab3/my-project/public/vite.svg rename to lab4/my-project/public/vite.svg diff --git a/lab4/my-project/punkrock.html b/lab4/my-project/punkrock.html new file mode 100644 index 0000000..3c92437 --- /dev/null +++ b/lab4/my-project/punkrock.html @@ -0,0 +1,195 @@ + + + + + + Панк-рок | Панкуха + + + + + + + + + + + + + +
+
+
+
+

+ Перечень исполнителей панк-рока +

+

+ Список культовых групп жанра +

+ + +
+
+
+ + +
+
+
+

Добавить исполнителя

+ +
+ +
+ + +
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + +
+
+
+
+ + +
+ + + +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/lab3/my-project/res/garajnipunk.jpg b/lab4/my-project/res/garajnipunk.jpg similarity index 100% rename from lab3/my-project/res/garajnipunk.jpg rename to lab4/my-project/res/garajnipunk.jpg diff --git a/lab3/my-project/res/grob.jpg b/lab4/my-project/res/grob.jpg similarity index 100% rename from lab3/my-project/res/grob.jpg rename to lab4/my-project/res/grob.jpg diff --git a/lab3/my-project/res/logo.png b/lab4/my-project/res/logo.png similarity index 100% rename from lab3/my-project/res/logo.png rename to lab4/my-project/res/logo.png diff --git a/lab3/my-project/res/nekrofilia.jpg b/lab4/my-project/res/nekrofilia.jpg similarity index 100% rename from lab3/my-project/res/nekrofilia.jpg rename to lab4/my-project/res/nekrofilia.jpg diff --git a/lab3/my-project/res/pankrock.jpg b/lab4/my-project/res/pankrock.jpg similarity index 100% rename from lab3/my-project/res/pankrock.jpg rename to lab4/my-project/res/pankrock.jpg diff --git a/lab3/my-project/res/psy.png b/lab4/my-project/res/psy.png similarity index 100% rename from lab3/my-project/res/psy.png rename to lab4/my-project/res/psy.png diff --git a/lab3/my-project/res/vk.png b/lab4/my-project/res/vk.png similarity index 100% rename from lab3/my-project/res/vk.png rename to lab4/my-project/res/vk.png diff --git a/lab3/my-project/src/counter.js b/lab4/my-project/src/counter.js similarity index 100% rename from lab3/my-project/src/counter.js rename to lab4/my-project/src/counter.js diff --git a/lab3/my-project/src/css/style.css b/lab4/my-project/src/css/style.css similarity index 100% rename from lab3/my-project/src/css/style.css rename to lab4/my-project/src/css/style.css diff --git a/lab3/my-project/src/javascript.svg b/lab4/my-project/src/javascript.svg similarity index 100% rename from lab3/my-project/src/javascript.svg rename to lab4/my-project/src/javascript.svg diff --git a/lab4/my-project/src/js/controller/ArtistController.js b/lab4/my-project/src/js/controller/ArtistController.js new file mode 100644 index 0000000..732b79a --- /dev/null +++ b/lab4/my-project/src/js/controller/ArtistController.js @@ -0,0 +1,96 @@ +export default class ArtistController { + constructor(model, view) { + this.model = model; + this.view = view; + + // Привязка обработчиков + this.view.bindAddArtist(this.handleAddArtist); + this.view.bindDeleteArtist(this.handleDeleteArtist); + this.view.bindEditArtist(this.handleEditArtist); + this.view.bindSaveEditArtist(this.handleUpdateArtist); + + // Инициализация приложения + this.init(); + } + + async init() { + try { + const [artists, countries, epochs] = await Promise.all([ + this.model.getAll(), + this.model.getCountries(), + this.model.getEpochs() + ]); + console.log('Инициализация данных:', { artists, countries, epochs }); // Отладка + // Проверяем, есть ли epoch и country у артистов + if (artists.length > 0) { + console.log('Пример артиста:', artists[0]); + } + this.view.renderArtists(artists); + this.view.initCountries(countries); + this.view.initEpochs(epochs); + } catch (error) { + console.error('Ошибка в init:', error); + alert('Ошибка загрузки данных: ' + error.message); + } + } + + handleAddArtist = async (artist) => { + try { + console.log('Добавление артиста:', artist); // Отладка + await this.model.create(artist); + await this.init(); + alert('Исполнитель добавлен!'); + } catch (error) { + console.error('Ошибка в handleAddArtist:', error); + alert('Ошибка: ' + error.message); + } + }; + + Z + handleDeleteArtist = async (id) => { + if (confirm('Удалить исполнителя?')) { + try { + await this.model.delete(id); + await this.init(); + alert('Исполнитель удален!'); + } catch (error) { + console.error('Ошибка в handleDeleteArtist:', error); + alert('Ошибка: ' + error.message); + } + } + }; + + handleEditArtist = async (id) => { + try { + const artist = await this.model.getById(id); + console.log('Редактирование артиста:', artist); // Отладка + if (!artist) { + throw new Error('Исполнитель не найден'); + } + this.view.showEditForm(artist); + } catch (error) { + console.error('Ошибка в handleEditArtist:', error); + alert('Ошибка: ' + error.message); + } + }; + + handleUpdateArtist = async (artist) => { + try { + console.log('Обновление артиста:', artist); // Отладка + if (!artist.epochId || !artist.countryId) { + throw new Error('Эпоха и страна обязательны'); + } + await this.model.update(artist.id, { + name: artist.name, + description: artist.description, + epochId: artist.epochId, + countryId: artist.countryId + }); + await this.init(); + alert('Изменения сохранены!'); + } catch (error) { + console.error('Ошибка в handleUpdateArtist:', error); + alert('Ошибка: ' + error.message); + } + }; +} \ No newline at end of file diff --git a/lab4/my-project/src/js/main.js b/lab4/my-project/src/js/main.js new file mode 100644 index 0000000..0652920 --- /dev/null +++ b/lab4/my-project/src/js/main.js @@ -0,0 +1,19 @@ +import '../css/style.css' +import 'bootstrap'; + +// Импорты компонентов MVC +import ArtistModel from './model/ArtistModel.js'; +import ArtistView from './view/ArtistView.js'; +import ArtistController from './controller/ArtistController.js'; + +// Инициализация приложения +document.addEventListener('DOMContentLoaded', () => { + try { + const model = new ArtistModel(); + const view = new ArtistView(); + new ArtistController(model, view); + console.log('Приложение инициализировано'); + } catch (error) { + console.error('Ошибка инициализации:', error); + } +}); \ No newline at end of file diff --git a/lab4/my-project/src/js/model/ArtistModel.js b/lab4/my-project/src/js/model/ArtistModel.js new file mode 100644 index 0000000..ad1dbff --- /dev/null +++ b/lab4/my-project/src/js/model/ArtistModel.js @@ -0,0 +1,147 @@ +export default class ArtistModel { + constructor() { + this.apiUrl = 'http://localhost:3000'; + } + + async getAll() { + try { + const [artistsResponse, countriesResponse, epochsResponse] = await Promise.all([ + fetch(`${this.apiUrl}/artists`), + fetch(`${this.apiUrl}/countries`), + fetch(`${this.apiUrl}/epochs`) + ]); + if (!artistsResponse.ok || !countriesResponse.ok || !epochsResponse.ok) { + throw new Error('Ошибка загрузки данных'); + } + const artists = await artistsResponse.json(); + const countries = await countriesResponse.json(); + const epochs = await epochsResponse.json(); + + console.log('Сырые артисты:', artists); + console.log('Страны:', countries); + console.log('Эпохи:', epochs); + + const artistsWithRelations = artists.map(artist => { + const countryId = Number(artist.countryId); // Приводим к числу + const epochId = Number(artist.epochId); // Приводим к числу + const country = countries.find(c => Number(c.id) === countryId) || { id: null, name: 'Не указана' }; + const epoch = epochs.find(e => Number(e.id) === epochId) || { id: null, name: 'Не указана' }; + console.log(`Артист ${artist.name}: countryId=${countryId}, country=${JSON.stringify(country)}, epochId=${epochId}, epoch=${JSON.stringify(epoch)}`); + return { + ...artist, + country, + epoch + }; + }); + + console.log('Артисты с отношениями:', artistsWithRelations); + return artistsWithRelations; + } catch (error) { + console.error('Ошибка в getAll:', error); + throw error; + } + } + + async getById(id) { + try { + const [artistResponse, countriesResponse, epochsResponse] = await Promise.all([ + fetch(`${this.apiUrl}/artists/${id}`), + fetch(`${this.apiUrl}/countries`), + fetch(`${this.apiUrl}/epochs`) + ]); + if (!artistResponse.ok || !countriesResponse.ok || !epochsResponse.ok) { + throw new Error('Ошибка загрузки данных'); + } + const artist = await artistResponse.json(); + const countries = await countriesResponse.json(); + const epochs = await epochsResponse.json(); + + const countryId = Number(artist.countryId); // Приводим к числу + const epochId = Number(artist.epochId); // Приводим к числу + const country = countries.find(c => Number(c.id) === countryId) || { id: null, name: 'Не указана' }; + const epoch = epochs.find(e => Number(e.id) === epochId) || { id: null, name: 'Не указана' }; + console.log(`Артист ${artist.name}: countryId=${countryId}, country=${JSON.stringify(country)}, epochId=${epochId}, epoch=${JSON.stringify(epoch)}`); + + const artistWithRelations = { + ...artist, + country, + epoch + }; + + console.log('Полученный артист с отношениями:', artistWithRelations); + return artistWithRelations; + } catch (error) { + console.error('Ошибка в getById:', error); + throw error; + } + } + + async getCountries() { + try { + const response = await fetch(`${this.apiUrl}/countries`); + if (!response.ok) throw new Error('Ошибка загрузки стран'); + return await response.json(); + } catch (error) { + console.error('Ошибка в getCountries:', error); + throw error; + } + } + + async getEpochs() { + try { + const response = await fetch(`${this.apiUrl}/epochs`); + if (!response.ok) throw new Error('Ошибка загрузки эпох'); + return await response.json(); + } catch (error) { + console.error('Ошибка в getEpochs:', error); + throw error; + } + } + + async create(artist) { + try { + const response = await fetch(`${this.apiUrl}/artists`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(artist) + }); + if (!response.ok) throw new Error('Ошибка создания исполнителя'); + const createdArtist = await response.json(); + console.log('Созданный артист:', createdArtist); + return createdArtist; + } catch (error) { + console.error('Ошибка в create:', error); + throw error; + } + } + + async update(id, artist) { + try { + const response = await fetch(`${this.apiUrl}/artists/${id}`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(artist) + }); + if (!response.ok) throw new Error('Ошибка обновления исполнителя'); + const updatedArtist = await response.json(); + console.log('Обновленный артист:', updatedArtist); + return updatedArtist; + } catch (error) { + console.error('Ошибка в update:', error); + throw error; + } + } + + async delete(id) { + try { + const response = await fetch(`${this.apiUrl}/artists/${id}`, { + method: 'DELETE' + }); + if (!response.ok) throw new Error('Ошибка удаления исполнителя'); + return true; + } catch (error) { + console.error('Ошибка в delete:', error); + throw error; + } + } +} \ No newline at end of file diff --git a/lab4/my-project/src/js/view/ArtistView.js b/lab4/my-project/src/js/view/ArtistView.js new file mode 100644 index 0000000..2b4d4d0 --- /dev/null +++ b/lab4/my-project/src/js/view/ArtistView.js @@ -0,0 +1,148 @@ +export default class ArtistView { + constructor() { + this.artistsContainer = document.getElementById('artistsContainer'); + this.artistForm = document.getElementById('artistForm'); + this.editArtistModal = document.getElementById('editArtistModal'); + this.saveEditArtistBtn = document.getElementById('saveEditArtist'); + + if (!this.artistsContainer || !this.artistForm || !this.editArtistModal || !this.saveEditArtistBtn) { + console.error('Не найдены необходимые элементы DOM'); + } + } + + renderArtists(artists) { + console.log('Рендеринг артистов:', artists); // Отладка + this.artistsContainer.innerHTML = artists.map(artist => { + console.log('Обработка артиста:', artist); // Отладка + return ` +
+
+
+
${artist.name}
+

${artist.description || 'Нет описания'}

+

Эпоха: ${artist.epoch?.name || 'Не указана'}

+

Страна: ${artist.country?.name || 'Не указана'}

+ + +
+
+
+ `; + }).join(''); + } + + initCountries(countries) { + const renderSelect = (selectId) => { + const select = document.getElementById(selectId); + select.innerHTML = ''; + countries.forEach(country => { + const option = document.createElement('option'); + option.value = country.id; + option.textContent = country.name; + select.appendChild(option); + }); + }; + + renderSelect('artistCountry'); + renderSelect('editArtistCountry'); + } + + initEpochs(epochs) { + const renderSelect = (selectId) => { + const select = document.getElementById(selectId); + select.innerHTML = ''; + epochs.forEach(epoch => { + const option = document.createElement('option'); + option.value = epoch.id; + option.textContent = epoch.name; + select.appendChild(option); + }); + }; + + renderSelect('artistEpoch'); + renderSelect('editArtistEpoch'); + } + + showEditForm(artist) { + console.log('Открытие формы редактирования:', artist); // Отладка + document.getElementById('editArtistName').value = artist.name || ''; + document.getElementById('editDescription').value = artist.description || ''; + document.getElementById('editArtistEpoch').value = artist.epoch?.id || artist.epochId || ''; + document.getElementById('editArtistCountry').value = artist.country?.id || artist.countryId || ''; + document.getElementById('editArtistId').value = artist.id; + + new bootstrap.Modal(this.editArtistModal).show(); + } + + bindAddArtist(handler) { + this.artistForm.addEventListener('submit', async (e) => { + e.preventDefault(); + const artist = { + name: document.getElementById('artistName').value.trim(), + description: document.getElementById('description').value.trim(), + epochId: parseInt(document.getElementById('artistEpoch').value) || null, + countryId: parseInt(document.getElementById('artistCountry').value) || null + }; + + console.log('Данные для добавления:', artist); // Отладка + if (!artist.name || !artist.description || !artist.epochId || !artist.countryId) { + alert('Все поля обязательны!'); + return; + } + + try { + await handler(artist); + this.artistForm.reset(); + } catch (error) { + alert('Ошибка при добавлении исполнителя: ' + error.message); + } + }); + } + + bindDeleteArtist(handler) { + this.artistsContainer.addEventListener('click', (e) => { + if (e.target.closest('.delete-btn')) { + const id = e.target.closest('.delete-btn').dataset.id; + handler(id); + } + }); + } + + bindEditArtist(handler) { + this.artistsContainer.addEventListener('click', (e) => { + if (e.target.closest('.edit-btn')) { + const id = e.target.closest('.edit-btn').dataset.id; + handler(id); + } + }); + } + + bindSaveEditArtist(handler) { + this.saveEditArtistBtn.addEventListener('click', async () => { + const artist = { + id: document.getElementById('editArtistId').value, + name: document.getElementById('editArtistName').value.trim(), + description: document.getElementById('editDescription').value.trim(), + epochId: parseInt(document.getElementById('editArtistEpoch').value) || null, + countryId: parseInt(document.getElementById('editArtistCountry').value) || null + }; + + console.log('Данные для обновления:', artist); // Отладка + if (!artist.name || !artist.description || !artist.epochId || !artist.countryId) { + alert('Все поля обязательны!'); + return; + } + + try { + await handler(artist); + bootstrap.Modal.getInstance(this.editArtistModal).hide(); + } catch (error) { + alert('Ошибка при обновлении исполнителя: ' + error.message); + } + }); + } +} \ No newline at end of file diff --git a/~$bWork4Report.docx b/~$bWork4Report.docx new file mode 100644 index 0000000..289d252 Binary files /dev/null and b/~$bWork4Report.docx differ