173
Account.html
173
Account.html
@@ -1,47 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
|
||||
<title>Интернет-магазин: ЛК</title>
|
||||
<link rel="stylesheet" href="css/style.css" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header">
|
||||
<div class="d-block mt-3 ms-3">
|
||||
<img src="images/logo.jpg" alt="Название магазина" class="me-3" style="width: 200px; height: auto;">
|
||||
<a href="newSite.html" class="text-decoration-none text-dark m-1">
|
||||
<h1 class="display-4 h3 mt-3"><b>Название магазина</b></h1>
|
||||
</a>
|
||||
</div>
|
||||
<navbar>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-primary dropdown-toggle" type="button" id="navigationDropdown"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
Навигация
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="navigationDropdown">
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center"
|
||||
href="Account.html">Личный кабинет<i class="bi bi-person-circle ms-2"></i></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center"
|
||||
href="Basket.html">Корзина<i class="bi bi-cart4 ms-2"></i></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center"
|
||||
href="Order.html">Заказы<i class="bi bi-receipt ms-2"></i></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center"
|
||||
href="Favorites.html">Избранное<i class="bi bi-heart-fill ms-2"></i></a></li>
|
||||
</ul>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
|
||||
<title>Интернет-магазин: ЛК</title>
|
||||
<link rel="stylesheet" href="css/style.css"/>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css">
|
||||
</head>
|
||||
<body>
|
||||
<header">
|
||||
<div class="d-block mt-3 ms-3">
|
||||
<img src="images/logo.jpg" alt="Название магазина" class="me-3" style="width: 200px; height: auto;">
|
||||
<a href="newSite.html" class="text-decoration-none text-dark m-1"><h1 class="display-4 h3 mt-3"><b>Название магазина</b></h1></a>
|
||||
</div>
|
||||
</navbar>
|
||||
<navbar>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-primary dropdown-toggle" type="button" id="navigationDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
Навигация
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="navigationDropdown">
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="Account.html">Личный кабинет<i class="bi bi-person-circle ms-2"></i></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="Basket.html">Корзина<i class="bi bi-cart4 ms-2"></i></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="Order.html">Заказы<i class="bi bi-receipt ms-2"></i></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="Favorites.html">Избранное<i class="bi bi-heart-fill ms-2"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</navbar>
|
||||
</header>
|
||||
<div class="container mt-5">
|
||||
<div class="card text-center mx-auto" style="max-width: 400px; max-height: 400px;">
|
||||
<img src="images/бананы.jpg" class="card-img-top" alt="Профиль"
|
||||
style="width: 100%; height: 300px; object-fit: cover;">
|
||||
<img src="images/бананы.jpg" class="card-img-top" alt="Профиль" style="width: 100%; height: 300px; object-fit: cover;">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Имя Фамилия</h3>
|
||||
<p class="card-text">Описание</p>
|
||||
@@ -58,8 +47,7 @@
|
||||
</div>
|
||||
<div class="d-flex align-items-center me-4 mb-3">
|
||||
<img src="images/vk.png" alt="VK" class="me-2" style="width: 24px; height: 24px;">
|
||||
<a href="https://vk.com/howmakesite_nn?from=search" target="_blank"
|
||||
class="text-decoration-none text-dark">vk.com</a>
|
||||
<a href="https://vk.com/howmakesite_nn?from=search" target="_blank" class="text-decoration-none text-dark">vk.com</a>
|
||||
</div>
|
||||
<div class="d-flex align-items-center me-4 mb-3">
|
||||
<img src="images/telegram.png" alt="Telegram" class="me-2" style="width: 24px; height: 24px;">
|
||||
@@ -67,112 +55,11 @@
|
||||
</div>
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<img src="images/gmail.png" alt="Gmail" class="me-2" style="width: 24px; height: 24px;">
|
||||
<a href="mailto:ozon-zon-zon@mail.joke"
|
||||
class="text-decoration-none text-dark">ozon-zon-zon@mail.joke</a>
|
||||
<a href="mailto:ozon-zon-zon@mail.joke" class="text-decoration-none text-dark">ozon-zon-zon@mail.joke</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
|
||||
crossorigin="anonymous"></script>
|
||||
<script type="module">
|
||||
let profile = {
|
||||
firstName: "Иван",
|
||||
lastName: "Иванов",
|
||||
image: "images/бананы.jpg"
|
||||
};
|
||||
|
||||
function renderProfile() {
|
||||
const card = document.querySelector('.container .card');
|
||||
card.innerHTML = `
|
||||
<img src="${profile.image || 'images/бананы.jpg'}" class="card-img-top" alt="Профиль" style="width: 100%; height: 300px; object-fit: cover;">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">${profile.firstName} ${profile.lastName}</h3>
|
||||
<button class="btn btn-primary" id="editProfileBtn"><i class="bi bi-pencil"></i> Редактировать профиль</button>
|
||||
</div>
|
||||
`;
|
||||
card.querySelector('#editProfileBtn').onclick = showEditModal;
|
||||
}
|
||||
|
||||
function showEditModal() {
|
||||
let modalDiv = document.getElementById('profileModal');
|
||||
if (!modalDiv) {
|
||||
modalDiv = document.createElement('div');
|
||||
modalDiv.className = 'modal fade';
|
||||
modalDiv.id = 'profileModal';
|
||||
modalDiv.tabIndex = -1;
|
||||
modalDiv.innerHTML = `
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content" id="profileModalContent"></div>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(modalDiv);
|
||||
}
|
||||
const modalContent = modalDiv.querySelector('#profileModalContent');
|
||||
modalContent.innerHTML = `
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Редактировать профиль</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form id="profileForm">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Имя</label>
|
||||
<input type="text" class="form-control" name="firstName" value="${profile.firstName}" required pattern="^[А-Яа-яЁё]+$" title="Только русские буквы!">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Фамилия</label>
|
||||
<input type="text" class="form-control" name="lastName" value="${profile.lastName}" required pattern="^[А-Яа-яЁё]+$" title="Только русские буквы!">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Фото профиля</label>
|
||||
<input type="file" class="form-control" name="image" accept="image/*">
|
||||
<img id="profilePreviewImage" src="${profile.image || ''}" style="max-width:100%;margin-top:10px;${profile.image ? '' : 'display:none;'}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-success">Сохранить</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
const modal = new bootstrap.Modal(modalDiv);
|
||||
modal.show();
|
||||
|
||||
// Предпросмотр картинки
|
||||
const fileInput = modalContent.querySelector('input[type="file"]');
|
||||
|
||||
document.getElementById('profileForm').onsubmit = function (e) {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(e.target);
|
||||
const firstName = formData.get('firstName');
|
||||
const lastName = formData.get('lastName');
|
||||
// Валидация кириллицы
|
||||
if (!/^[А-Яа-яЁё]+$/.test(firstName) || !/^[А-Яа-яЁё]+$/.test(lastName)) {
|
||||
alert('Имя и фамилия должны быть только на русском!');
|
||||
return;
|
||||
}
|
||||
profile.firstName = firstName;
|
||||
profile.lastName = lastName;
|
||||
if (fileInput.files.length) {
|
||||
const file = fileInput.files[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (event) {
|
||||
profile.image = event.target.result; // base64
|
||||
modal.hide();
|
||||
renderProfile();
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
profile.image = fileInput.src || "images/бананы.jpg";
|
||||
modal.hide();
|
||||
renderProfile();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
renderProfile();
|
||||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,52 +0,0 @@
|
||||
// js/controller.js
|
||||
|
||||
import Model from './model.js';
|
||||
import View from './view.js';
|
||||
|
||||
export default {
|
||||
async init() {
|
||||
this.products = await Model.getProducts();
|
||||
this.categories = await Model.getCategories();
|
||||
this.brands = await Model.getBrands();
|
||||
|
||||
View.renderProductList(this.products, this.handleEdit.bind(this), this.handleDelete.bind(this));
|
||||
|
||||
// Кнопка "Добавить товар"
|
||||
document.getElementById('addProductBtn').onclick = () => {
|
||||
View.showProductModal(
|
||||
{ categories: this.categories, brands: this.brands },
|
||||
this.handleAdd.bind(this)
|
||||
);
|
||||
};
|
||||
},
|
||||
|
||||
async handleAdd(productData, modal) {
|
||||
await Model.addProduct(productData);
|
||||
modal.hide();
|
||||
await this.refresh();
|
||||
},
|
||||
|
||||
async handleEdit(productId) {
|
||||
const product = await Model.getProductById(productId);
|
||||
View.showProductModal(
|
||||
{ product, categories: this.categories, brands: this.brands },
|
||||
async (formData, modal) => {
|
||||
await Model.updateProduct(productId, formData);
|
||||
modal.hide();
|
||||
await this.refresh();
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
async handleDelete(productId) {
|
||||
if (confirm('Удалить товар?')) {
|
||||
await Model.deleteProduct(productId);
|
||||
await this.refresh();
|
||||
}
|
||||
},
|
||||
|
||||
async refresh() {
|
||||
this.products = await Model.getProducts();
|
||||
View.renderProductList(this.products, this.handleEdit.bind(this), this.handleDelete.bind(this));
|
||||
}
|
||||
};
|
||||
46
js/model.js
46
js/model.js
@@ -1,46 +0,0 @@
|
||||
// js/model.js
|
||||
|
||||
const API_URL = 'http://localhost:5000';
|
||||
|
||||
export default {
|
||||
// --- PRODUCTS ---
|
||||
async getProducts() {
|
||||
const res = await fetch(`${API_URL}/products?_expand=category&_expand=brand`);
|
||||
return res.json();
|
||||
},
|
||||
async getProductById(id) {
|
||||
const res = await fetch(`${API_URL}/products/${id}`);
|
||||
return res.json();
|
||||
},
|
||||
async addProduct(product) {
|
||||
const res = await fetch(`${API_URL}/products`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(product)
|
||||
});
|
||||
return res.json();
|
||||
},
|
||||
async updateProduct(id, product) {
|
||||
const res = await fetch(`${API_URL}/products/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(product)
|
||||
});
|
||||
return res.json();
|
||||
},
|
||||
async deleteProduct(id) {
|
||||
await fetch(`${API_URL}/products/${id}`, { method: 'DELETE' });
|
||||
},
|
||||
|
||||
// --- CATEGORIES ---
|
||||
async getCategories() {
|
||||
const res = await fetch(`${API_URL}/categories`);
|
||||
return res.json();
|
||||
},
|
||||
|
||||
// --- BRANDS ---
|
||||
async getBrands() {
|
||||
const res = await fetch(`${API_URL}/brands`);
|
||||
return res.json();
|
||||
}
|
||||
};
|
||||
124
js/view.js
124
js/view.js
@@ -1,124 +0,0 @@
|
||||
// js/view.js
|
||||
|
||||
export default {
|
||||
renderProductList(products, onEdit, onDelete) {
|
||||
const list = document.getElementById('productsList');
|
||||
list.innerHTML = '';
|
||||
products.forEach(product => {
|
||||
const col = document.createElement('div');
|
||||
col.className = 'col';
|
||||
// Если image не начинается с "data:" — выводим как есть (старые товары), иначе как base64
|
||||
const imgSrc = product.image?.startsWith('data:') ? product.image : (product.image || 'images/no-image.png');
|
||||
col.innerHTML = `
|
||||
<div class="card h-100">
|
||||
<img src="${imgSrc}" class="card-img-top" alt="${product.name}" style="width: 100%; height: 300px; object-fit: cover;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">${product.name}</h5>
|
||||
<p class="card-text">${product.price} руб</p>
|
||||
<p class="card-text">
|
||||
<small class="text-muted">Категория: ${product.category?.name || '-'}</small><br>
|
||||
<small class="text-muted">Бренд: ${product.brand?.name || '-'}</small>
|
||||
</p>
|
||||
<button class="btn btn-primary btn-sm me-2 edit-btn"><i class="bi bi-pencil"></i> Редактировать</button>
|
||||
<button class="btn btn-danger btn-sm delete-btn"><i class="bi bi-trash"></i> Удалить</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
// Навесить обработчики
|
||||
col.querySelector('.edit-btn').onclick = () => onEdit(product.id);
|
||||
col.querySelector('.delete-btn').onclick = () => onDelete(product.id);
|
||||
list.appendChild(col);
|
||||
});
|
||||
},
|
||||
|
||||
showProductModal({ product = {}, categories = [], brands = [] }, onSubmit) {
|
||||
const modalContent = document.getElementById('productModalContent');
|
||||
modalContent.innerHTML = `
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">${product.id ? 'Редактировать' : 'Добавить'} товар</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form id="productForm">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Название товара</label>
|
||||
<input type="text" class="form-control" name="name" value="${product.name || ''}" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Цена (руб)</label>
|
||||
<input type="number" class="form-control" name="price" value="${product.price || ''}" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Изображение</label>
|
||||
<input type="file" class="form-control" name="image" accept="image/*" ${product.id ? "" : "required"}>
|
||||
<img id="previewImage" src="${product.image || ''}" style="max-width:100%;margin-top:10px;${product.image ? '' : 'display:none;'}"/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Категория</label>
|
||||
<select class="form-select" name="categoryId" required>
|
||||
<option value="">Выберите категорию</option>
|
||||
${categories.map(cat => `
|
||||
<option value="${cat.id}" ${product.categoryId == cat.id ? 'selected' : ''}>${cat.name}</option>
|
||||
`).join('')}
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Бренд</label>
|
||||
<select class="form-select" name="brandId" required>
|
||||
<option value="">Выберите бренд</option>
|
||||
${brands.map(br => `
|
||||
<option value="${br.id}" ${product.brandId == br.id ? 'selected' : ''}>${br.name}</option>
|
||||
`).join('')}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-success">${product.id ? 'Сохранить' : 'Добавить'}</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
// Показываем модалку через Bootstrap JS
|
||||
const modal = new bootstrap.Modal(document.getElementById('productModal'));
|
||||
modal.show();
|
||||
|
||||
// Предпросмотр выбранной картинки
|
||||
const fileInput = modalContent.querySelector('input[type="file"]');
|
||||
const preview = modalContent.querySelector('#previewImage');
|
||||
fileInput.onchange = () => {
|
||||
const file = fileInput.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = e => {
|
||||
preview.src = e.target.result;
|
||||
preview.style.display = '';
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
};
|
||||
|
||||
// Обработка формы (с поддержкой base64-картинки)
|
||||
document.getElementById('productForm').onsubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(e.target);
|
||||
const obj = Object.fromEntries(formData.entries());
|
||||
obj.price = +obj.price;
|
||||
obj.categoryId = +obj.categoryId;
|
||||
obj.brandId = +obj.brandId;
|
||||
|
||||
if (fileInput.files.length) {
|
||||
const file = fileInput.files[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(event) {
|
||||
obj.image = event.target.result; // base64
|
||||
onSubmit(obj, modal);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
obj.image = product.image || '';
|
||||
onSubmit(obj, modal);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
260
newSite.html
260
newSite.html
@@ -1,99 +1,191 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
|
||||
<title>Интернет-магазин</title>
|
||||
<link rel="stylesheet" href="css/style.css" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header">
|
||||
<div class="d-block mt-3 ms-3">
|
||||
<img src="images/logo.jpg" alt="Название магазина" class="me-3" style="width: 200px; height: auto;">
|
||||
<a href="newSite.html" class="text-decoration-none text-dark m-1">
|
||||
<h1 class="display-4 h3 mt-3"><b>Название магазина</b></h1>
|
||||
</a>
|
||||
</div>
|
||||
<navbar>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-primary dropdown-toggle" type="button" id="navigationDropdown"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
Навигация
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="navigationDropdown">
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center"
|
||||
href="Account.html">Личный кабинет<i class="bi bi-person-circle ms-2"></i></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center"
|
||||
href="Basket.html">Корзина<i class="bi bi-cart4 ms-2"></i></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center"
|
||||
href="Order.html">Заказы<i class="bi bi-receipt ms-2"></i></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center"
|
||||
href="Favorites.html">Избранное<i class="bi bi-heart-fill ms-2"></i></a></li>
|
||||
</ul>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
|
||||
<title>Интернет-магазин</title>
|
||||
<link rel="stylesheet" href="css/style.css"/>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css">
|
||||
</head>
|
||||
<body>
|
||||
<header">
|
||||
<div class="d-block mt-3 ms-3">
|
||||
<img src="images/logo.jpg" alt="Название магазина" class="me-3" style="width: 200px; height: auto;">
|
||||
<a href="newSite.html" class="text-decoration-none text-dark m-1"><h1 class="display-4 h3 mt-3"><b>Название магазина</b></h1></a>
|
||||
</div>
|
||||
</navbar>
|
||||
<navbar>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-primary dropdown-toggle" type="button" id="navigationDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
Навигация
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="navigationDropdown">
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="Account.html">Личный кабинет<i class="bi bi-person-circle ms-2"></i></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="Basket.html">Корзина<i class="bi bi-cart4 ms-2"></i></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="Order.html">Заказы<i class="bi bi-receipt ms-2"></i></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="Favorites.html">Избранное<i class="bi bi-heart-fill ms-2"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</navbar>
|
||||
</header>
|
||||
<main class="container">
|
||||
<div class="d-flex justify-content-end my-4">
|
||||
<button class="btn btn-success" id="addProductBtn">
|
||||
<i class="bi bi-plus-circle"></i> Добавить товар
|
||||
</button>
|
||||
</div>
|
||||
<!-- Модальное окно для формы добавления/редактирования -->
|
||||
<div class="modal fade" id="productModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content" id="productModalContent">
|
||||
<!-- JS сам отрисует тут форму через View.showProductForm() -->
|
||||
</div>
|
||||
<div class="card mb-5 border-primary">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h3 class="mb-0">Добавить новый товар</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="addProductForm" class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="productName" class="form-label">Название товара</label>
|
||||
<input type="text" class="form-control" id="productName" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="productPrice" class="form-label">Цена (руб)</label>
|
||||
<input type="number" class="form-control" step="10" id="productPrice" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="productImage" class="form-label">Изображение товара</label>
|
||||
<input type="file" class="form-control" id="productImage" accept="image/*" required>
|
||||
</div>
|
||||
<div class="col-12 d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="bi bi-plus-circle"></i> Добавить товар
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h2 class="text-center my-3">Рекомендуемые товары:</h2>
|
||||
<div class="row row-cols-1 row-cols-md-3 g-4" id="productsList">
|
||||
<!-- Здесь будут карточки товаров (рендерит JS) -->
|
||||
</div>
|
||||
</main>
|
||||
<footer class="container mt-5">
|
||||
<div class="bg-light p-4">
|
||||
<h5>Помощь:</h5>
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="d-flex align-items-center me-4 mb-3">
|
||||
<i class="bi bi-telephone-fill me-2"></i>
|
||||
<a href="#" class="text-decoration-none text-dark">8 (800)-555-35-35</a>
|
||||
</div>
|
||||
<div class="d-flex align-items-center me-4 mb-3">
|
||||
<img src="images/vk.png" alt="VK" class="me-2" style="width: 24px; height: 24px;">
|
||||
<a href="https://vk.com/howmakesite_nn?from=search" target="_blank"
|
||||
class="text-decoration-none text-dark">vk.com</a>
|
||||
</div>
|
||||
<div class="d-flex align-items-center me-4 mb-3">
|
||||
<img src="images/telegram.png" alt="Telegram" class="me-2" style="width: 24px; height: 24px;">
|
||||
<a href="#" class="text-decoration-none text-dark">tg.me</a>
|
||||
</div>
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<img src="images/gmail.png" alt="Gmail" class="me-2" style="width: 24px; height: 24px;">
|
||||
<a href="mailto:ozon-zon-zon@mail.joke"
|
||||
class="text-decoration-none text-dark">ozon-zon-zon@mail.joke</a>
|
||||
<div class="row row-cols-1 row-cols-md-3 g-4 recomended">
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<img src="images/iron.jpg" class="card-img-top" alt="Утюг" style="width: 100%; height: 300%; object-fit: cover;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Утюг</h5>
|
||||
<p class="card-text">2600 руб</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center mt-4">
|
||||
<img src="images/бананы.jpg" alt="Бананы" class="img-fluid">
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<img src="images/child.jpg" class="card-img-top" alt="Ребёнок" style="width: 100%; height: 300%; object-fit: cover;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Ребёнок</h5>
|
||||
<p class="card-text">2600 без костей</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
|
||||
crossorigin="anonymous"></script>
|
||||
<script type="module">
|
||||
import Controller from './js/controller.js';
|
||||
Controller.init();
|
||||
</script>
|
||||
</body>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<img src="images/screwdriver.jpg" class="card-img-top" alt="Отвертка" style="width: 100%; height: 300%; object-fit: cover;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Отвертка</h5>
|
||||
<p class="card-text">620 руб</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<img src="images/skateboard.jpg" class="card-img-top" alt="Скейтборд" style="width: 100%; height: 300%; object-fit: cover;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Скейтборд</h5>
|
||||
<p class="card-text">4300 руб</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<img src="images/bananas.jpg" class="card-img-top" alt="Бананы" style="width: 100%; height: 300%; object-fit: cover;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Бананы</h5>
|
||||
<p class="card-text">120 руб</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="container mt-5">
|
||||
<div class="bg-light p-4">
|
||||
<h5>Помощь:</h5>
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="d-flex align-items-center me-4 mb-3">
|
||||
<i class="bi bi-telephone-fill me-2"></i>
|
||||
<a href="#" class="text-decoration-none text-dark">8 (800)-555-35-35</a>
|
||||
</div>
|
||||
<div class="d-flex align-items-center me-4 mb-3">
|
||||
<img src="images/vk.png" alt="VK" class="me-2" style="width: 24px; height: 24px;">
|
||||
<a href="https://vk.com/howmakesite_nn?from=search" target="_blank" class="text-decoration-none text-dark">vk.com</a>
|
||||
</div>
|
||||
<div class="d-flex align-items-center me-4 mb-3">
|
||||
<img src="images/telegram.png" alt="Telegram" class="me-2" style="width: 24px; height: 24px;">
|
||||
<a href="#" class="text-decoration-none text-dark">tg.me</a>
|
||||
</div>
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<img src="images/gmail.png" alt="Gmail" class="me-2" style="width: 24px; height: 24px;">
|
||||
<a href="mailto:ozon-zon-zon@mail.joke" class="text-decoration-none text-dark">ozon-zon-zon@mail.joke</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center mt-4">
|
||||
<img src="images/бананы.jpg" alt="Бананы" class="img-fluid">
|
||||
</div>
|
||||
</footer>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
document.getElementById('addProductForm').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const name = document.getElementById('productName').value;
|
||||
const price = document.getElementById('productPrice').value;
|
||||
const imageInput = document.getElementById('productImage');
|
||||
|
||||
// Проверка выбора файла
|
||||
if (imageInput.files.length === 0) {
|
||||
alert('Пожалуйста, выберите изображение!');
|
||||
return;
|
||||
}
|
||||
|
||||
var text = document.getElementById('productName').value;
|
||||
if(!text.match(/^[А-Яа-яЁё]+(?: [А-Яа-яЁё]+)*$/)){
|
||||
alert('Пожалуйста, введите корректное название на русском!');
|
||||
return;
|
||||
}
|
||||
|
||||
const file = imageInput.files[0];
|
||||
|
||||
// Проверка размера файла (до 5MB)
|
||||
if (file.size > 5 * 1024 * 1024) {
|
||||
alert('Файл слишком большой! Максимум 5MB.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Создаем превью изображения
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
const imageUrl = e.target.result;
|
||||
|
||||
// Создаем карточку товара
|
||||
const productCard = `
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<img src="${imageUrl}" class="card-img-top" alt="${name}" style="width: 100%; height: 300%; object-fit: cover;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">${name}</h5>
|
||||
<p class="card-text">${price} руб</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.querySelector('.row-cols-1').insertAdjacentHTML('afterbegin', productCard);
|
||||
alert('Товар успешно добавлен!');
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
this.reset();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -7,8 +7,7 @@
|
||||
"build": "vite build",
|
||||
"server": "http-server -p 3000 ./dist/",
|
||||
"prod": "npm-run-all build server",
|
||||
"lint": "eslint …",
|
||||
"json-server": "json-server --watch db.json --port 5000"
|
||||
"lint": "eslint …"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
|
||||
Reference in New Issue
Block a user