Compare commits

..

5 Commits
main ... pages

Author SHA1 Message Date
798b9b4d48 parent self registration 2026-08-10 09:58:28 +00:00
e48c07aa27 whatsapp code sending 2026-08-10 09:36:34 +00:00
d5ca8012e6 online payment kaspi 2026-08-10 09:34:27 +00:00
c6f5baae6e add print codes button 2026-08-10 09:26:56 +00:00
b6d1cbec67 add add product button on main 2026-08-10 09:23:14 +00:00

View File

@ -23,6 +23,9 @@ body{font:17px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,s
.card-title{font-size:20px;font-weight:700;margin-bottom:8px}
.card-price{font-size:24px;font-weight:800;color:var(--ink);margin-bottom:12px}
.card-cat{display:inline-block;background:var(--cyan-50);color:var(--ink);padding:4px 12px;border-radius:20px;font-size:14px;font-weight:600;margin-bottom:12px}
.status-badge{display:inline-block;padding:4px 12px;border-radius:20px;font-size:13px;font-weight:600;margin-left:8px}
.status-paid{background:#d4edda;color:#155724}
.status-waiting{background:#fff3cd;color:#856404}
.btn{display:inline-block;background:var(--cyan);color:var(--ink);padding:14px 28px;border-radius:8px;font-weight:700;text-decoration:none;border:none;cursor:pointer}
.btn:hover{opacity:0.9}
.btn-green{background:var(--green);color:#fff}
@ -82,8 +85,11 @@ body{font:17px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,s
<div class="grid" id="products-grid"></div>
<div class="empty" id="empty-msg" style="display:none">Товаров пока нет 😔</div>
<div style="text-align:center;margin-top:40px">
<div style="text-align:center;margin-top:40px;display:flex;gap:16px;justify-content:center;flex-wrap:wrap">
<button class="btn" onclick="openParentCodeModal()" style="background:var(--green);color:#fff">👨‍👩‍👧 Получить код родителя</button>
<button class="btn" onclick="openParentRegisterModal()" style="background:#FF5500;color:#fff">👨‍👩‍👧 Родителям: регистрация</button>
<button class="btn" onclick="openPaymentModal()" style="background:#FF5500;color:#fff">💳 Оплатить онлайн</button>
<button class="btn" onclick="showPage('admin');setTimeout(() => document.getElementById('nav-admin').click(), 100)" style="background:var(--ink);color:#fff">➕ Добавить товар</button>
</div>
</div>
</section>
@ -122,10 +128,19 @@ body{font:17px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,s
<button type="submit" class="btn btn-green">Зарегистрировать родителя</button>
</form>
<h4 style="margin-bottom:16px">Зарегистрированные родители:</h4>
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;flex-wrap:wrap;gap:12px">
<h4 style="margin:0">Зарегистрированные родители:</h4>
<button class="btn" onclick="printCodes()" style="padding:8px 16px;font-size:14px">🖨️ Распечатать коды</button>
</div>
<div id="parents-list" style="margin-bottom:32px"></div>
</div>
<div class="admin-panel">
<h3>📋 Предоплаченные заказы (онлайн оплата)</h3>
<p style="margin-bottom:16px;color:var(--gray-500)">Родитель оплатил онлайн → ребёнок показывает код → забирает товар</p>
<div id="orders-list" style="margin-top:16px"></div>
</div>
<div class="admin-panel">
<h3>➕ Добавить товар</h3>
<form id="add-form">
@ -189,6 +204,24 @@ body{font:17px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,s
</div>
</div>
<div class="modal" id="payment-modal">
<div class="modal-content">
<h3>💳 Онлайн оплата</h3>
<p style="margin-bottom:16px">Родитель оплачивает — ребёнок забирает</p>
<div style="background:var(--cyan-50);padding:16px;border-radius:8px;margin-bottom:16px">
<strong>Товар:</strong> <span id="pay-product"></span><br>
<strong>Цена:</strong> <span id="pay-price"></span> ₸
</div>
<div class="form-group">
<label>Телефон родителя (для входа)</label>
<input type="tel" id="pay-phone" placeholder="+7 777 123 45 67" style="width:100%;padding:12px;border:1px solid #ddd;border-radius:8px">
</div>
<button class="btn btn-green" onclick="processPayment()" style="width:100%">💳 Оплатить через Kaspi Pay</button>
<button class="btn" style="background:var(--gray-100);margin-top:12px;width:100%" onclick="closePaymentModal()">Отмена</button>
<p style="margin-top:16px;font-size:13px;color:var(--gray-500)">🔒 Тестовый режим — оплата не списывается</p>
</div>
</div>
<div class="modal" id="success-modal">
<div class="modal-content" style="text-align:center">
<h3>✅ Покупка разрешена!</h3>
@ -199,12 +232,35 @@ body{font:17px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,s
</div>
</div>
<div class="modal" id="parent-register-modal">
<div class="modal-content">
<h3>👨‍👩‍👧 Регистрация родителя</h3>
<p style="margin-bottom:20px">Контролируйте покупки ребёнка — установите лимит и получайте код</p>
<div class="form-group">
<label>Ваше имя</label>
<input type="text" id="reg-name" placeholder="Иванова Мария" style="width:100%;padding:12px;border:1px solid #ddd;border-radius:8px;margin-bottom:12px">
</div>
<div class="form-group">
<label>Телефон</label>
<input type="tel" id="reg-phone" placeholder="+7 777 123 45 67" style="width:100%;padding:12px;border:1px solid #ddd;border-radius:8px;margin-bottom:12px">
</div>
<div class="form-group">
<label>Лимит на день (₸)</label>
<input type="number" id="reg-limit" placeholder="1000" style="width:100%;padding:12px;border:1px solid #ddd;border-radius:8px;margin-bottom:12px">
</div>
<button class="btn btn-green" onclick="registerParent()" style="width:100%">Зарегистрироваться</button>
<button class="btn" style="background:var(--gray-100);margin-top:12px;width:100%" onclick="closeParentRegisterModal()">Отмена</button>
<p style="margin-top:16px;font-size:13px;color:var(--gray-500)">После регистрации вы получите персональный код для ребёнка</p>
</div>
</div>
<script>
// === Данные ===
const CATEGORIES = {еда:'🍫', напитки:'🥤', школа:'✏️', разное:'🎁'};
let products = [];
let parents = [];
let purchases = [];
let orders = []; // Предоплаченные заказы
let isAdmin = false;
const ADMIN_PASS = 'admin123'; // Поменяй на свой!
@ -214,10 +270,12 @@ function loadProducts() {
products = localStorage.getItem('shop-products') ? JSON.parse(localStorage.getItem('shop-products')) : getDefaults();
parents = localStorage.getItem('shop-parents') ? JSON.parse(localStorage.getItem('shop-parents')) : [];
purchases = localStorage.getItem('shop-purchases') ? JSON.parse(localStorage.getItem('shop-purchases')) : [];
orders = localStorage.getItem('shop-orders') ? JSON.parse(localStorage.getItem('shop-orders')) : [];
} catch {
products = getDefaults();
parents = [];
purchases = [];
orders = [];
}
}
@ -225,6 +283,7 @@ function saveProducts() {
localStorage.setItem('shop-products', JSON.stringify(products));
localStorage.setItem('shop-parents', JSON.stringify(parents));
localStorage.setItem('shop-purchases', JSON.stringify(purchases));
localStorage.setItem('shop-orders', JSON.stringify(orders));
}
function getDefaults() {
@ -259,7 +318,10 @@ function render(filter = 'all') {
<div class="card-title">${p.name}</div>
<div class="card-price">${p.price} ₸</div>
<p style="color:var(--gray-500);font-size:14px">${p.desc || ''}</p>
<button class="btn" style="margin-top:12px;width:100%" onclick="buyProduct(${p.id})">Купить</button>
<div style="display:flex;gap:8px;margin-top:12px">
<button class="btn" style="flex:1" onclick="buyProduct(${p.id})">Купить</button>
<button class="btn btn-green" style="flex:1" onclick="openPaymentModalForProduct(${JSON.stringify(p).replace(/"/g, '&quot;')})">💳 Оплатить</button>
</div>
</div>
</div>
`).join('');
@ -307,6 +369,47 @@ function render(filter = 'all') {
</div>
`).join('');
}
// Предоплаченные заказы
const ordersList = document.getElementById('orders-list');
if (ordersList) {
const activeOrders = orders.filter(o => !o.pickedUp);
const completedOrders = orders.filter(o => o.pickedUp);
if (activeOrders.length === 0 && completedOrders.length === 0) {
ordersList.innerHTML = '<p style="color:var(--gray-500)">Предоплаченных заказов пока нет</p>';
} else {
let html = '';
if (activeOrders.length > 0) {
html += '<h5 style="margin:16px 0 8px;color:var(--green)">⏳ Ожидают выдачи:</h5>';
html += activeOrders.map(o => `
<div class="card" style="margin-bottom:12px;padding:16px;border-left:4px solid var(--green)">
<strong>${o.product}</strong>
<span class="status-badge status-waiting">⏳ Ждёт выдачи</span><br>
<span style="color:var(--gray-500)">Родитель: ${o.parentName} (${o.parentPhone})</span><br>
<span style="color:var(--gray-500)">Код выдачи: <strong style="color:var(--cyan);font-size:20px">${o.code}</strong></span><br>
<span style="color:var(--gray-500)">Оплачено: ${o.price} ₸ | ${new Date(o.date).toLocaleString('ru-RU')}</span><br>
<div style="display:flex;gap:8px;margin-top:12px">
<button class="btn btn-green" style="flex:1;padding:8px 16px" onclick="markAsPickedUp(${o.id})">✅ Товар выдан</button>
<button class="btn" style="flex:1;padding:8px 16px;background:#25D366;color:#fff" onclick="resendWhatsApp('${o.parentPhone}','${o.product}',${o.price},'${o.code}')">📱 WhatsApp</button>
</div>
</div>
`).join('');
}
if (completedOrders.length > 0) {
html += '<h5 style="margin:16px 0 8px;color:var(--gray-500)">✅ Выданные:</h5>';
html += completedOrders.slice(-5).reverse().map(o => `
<div class="card" style="margin-bottom:12px;padding:16px;border-left:4px solid #28a745">
<strong>${o.product}</strong>
<span class="status-badge status-paid">✅ Выдан</span><br>
<span style="color:var(--gray-500)">Родитель: ${o.parentName} | Код: ${o.code}</span><br>
<span style="color:var(--gray-500)">Выдан: ${new Date(o.pickedUpAt).toLocaleString('ru-RU')}</span>
</div>
`).join('');
}
ordersList.innerHTML = html;
}
}
}
function getSpentToday(parentId) {
@ -390,6 +493,129 @@ function closeParentModal() {
document.getElementById('parent-code-modal').classList.remove('on');
}
function openParentRegisterModal() {
document.getElementById('parent-register-modal').classList.add('on');
}
function closeParentRegisterModal() {
document.getElementById('parent-register-modal').classList.remove('on');
}
function registerParent() {
const name = document.getElementById('reg-name').value.trim();
const phone = document.getElementById('reg-phone').value.trim();
const limit = Number(document.getElementById('reg-limit').value);
if (!name || !phone || !limit) {
alert('Заполните все поля!');
return;
}
// Проверяем, есть ли уже такой родитель
const exists = parents.find(p => p.phone === phone);
if (exists) {
alert('Такой родитель уже зарегистрирован! Ваш код: ' + exists.code);
closeParentRegisterModal();
return;
}
const parent = {
id: Date.now(),
name: name,
phone: phone,
limit: limit,
code: generateCode()
};
parents.push(parent);
saveProducts();
render();
closeParentRegisterModal();
// Очищаем форму
document.getElementById('reg-name').value = '';
document.getElementById('reg-phone').value = '';
document.getElementById('reg-limit').value = '';
// Показываем код
document.getElementById('success-message').textContent = `✅ Вы зарегистрированы!\n\nВаш код: ${parent.code}\n\nСообщите этот код ребёнку. Он будет использовать его для покупок.`;
document.getElementById('success-code').textContent = parent.code;
document.getElementById('success-modal').classList.add('on');
// Предлагаем отправить код в WhatsApp
setTimeout(() => {
const message = `✅ Вы зарегистрированы в школьном магазине!\n\nВаш код: *${parent.code}*\nЛимит: ${limit} ₸ в день\n\nСообщите этот код ребёнку для покупок.`;
const url = `https://wa.me/${phone.replace(/\D/g, '')}?text=${encodeURIComponent(message)}`;
if (confirm('📱 Отправить себе код в WhatsApp?')) {
window.open(url, '_blank');
}
}, 500);
}
let currentProductForPayment = null;
function openPaymentModal() {
document.getElementById('payment-modal').classList.add('on');
}
function closePaymentModal() {
document.getElementById('payment-modal').classList.remove('on');
}
function openPaymentModalForProduct(product) {
currentProductForPayment = product;
document.getElementById('pay-product').textContent = product.name;
document.getElementById('pay-price').textContent = product.price;
document.getElementById('payment-modal').classList.add('on');
}
function processPayment() {
const phone = document.getElementById('pay-phone').value.trim();
if (!phone || !currentProductForPayment) {
alert('Введите номер телефона и выберите товар');
return;
}
// Имитация оплаты Kaspi Pay
const orderCode = Math.floor(100000 + Math.random() * 900000).toString();
const order = {
id: Date.now(),
productId: currentProductForPayment.id,
product: currentProductForPayment.name,
price: currentProductForPayment.price,
parentPhone: phone,
parentName: phone,
code: orderCode,
date: new Date().toISOString(),
pickedUp: false,
pickedUpAt: null
};
orders.push(order);
saveProducts();
closePaymentModal();
// Отправка в WhatsApp
const whatsappMessage = `✅ *Оплата в школьном магазине*\n\nТовар: ${order.product}\nЦена: ${order.price} ₸\n\n🔑 *Ваш код выдачи: ${orderCode}*\n\nПокажите этот код продавцу и получите товар.\nСпасибо за покупку! 🏪`;
const whatsappUrl = `https://wa.me/${phone.replace(/\D/g, '')}?text=${encodeURIComponent(whatsappMessage)}`;
document.getElementById('success-message').textContent = `✅ Оплата прошла успешно!\n\nКод отправлен в WhatsApp на номер ${phone}`;
document.getElementById('success-code').textContent = orderCode;
document.getElementById('success-modal').classList.add('on');
// Открываем WhatsApp через 1 секунду
setTimeout(() => {
if (confirm('📱 Открыть WhatsApp для отправки кода родителю?')) {
window.open(whatsappUrl, '_blank');
}
}, 1000);
currentProductForPayment = null;
document.getElementById('pay-phone').value = '';
}
function verifyParentCode() {
const code = document.getElementById('parent-code-input').value.trim();
const parent = parents.find(p => p.code === code);
@ -426,6 +652,25 @@ function verifyParentCode() {
}
}
function markAsPickedUp(orderId) {
if (confirm('Подтвердить выдачу товара?')) {
const order = orders.find(o => o.id === orderId);
if (order) {
order.pickedUp = true;
order.pickedUpAt = new Date().toISOString();
saveProducts();
render();
alert('✅ Товар выдан!');
}
}
}
function resendWhatsApp(phone, product, price, code) {
const message = `✅ *Оплата в школьном магазине*\n\nТовар: ${product}\nЦена: ${price} ₸\n\n🔑 *Ваш код выдачи: ${code}*\n\nПокажите этот код продавцу и получите товар.\nСпасибо за покупку! 🏪`;
const url = `https://wa.me/${phone.replace(/\D/g, '')}?text=${encodeURIComponent(message)}`;
window.open(url, '_blank');
}
// === Родители ===
document.getElementById('parent-form').addEventListener('submit', (e) => {
e.preventDefault();
@ -455,6 +700,35 @@ function deleteParent(id) {
}
}
function printCodes() {
if (parents.length === 0) {
alert('Пока нет зарегистрированных родителей!');
return;
}
const content = parents.map(p =>
`${p.name} (${p.phone}) — КОД: ${p.code} (лимит ${p.limit}₸)`
).join('\n\n');
const printWindow = window.open('', '', 'width=600,height=400');
printWindow.document.write(`
<html><head><title>Коды родителей</title>
<style>
body{font-family:Arial,sans-serif;padding:40px}
h1{color:#0F1218}
.code{background:#E8FCFF;padding:15px;margin:10px 0;border-radius:8px;font-size:18px}
.code strong{color:#00E5FF;font-size:24px}
</style>
</head><body>
<h1>🏪 Школьный магазин — Коды родителей</h1>
<p style="color:#5B6573">Распечатайте этот список и повесьте на кассе для проверки</p>
${parents.map(p => `<div class="code"><strong>КОД: ${p.code}</strong><br>${p.name} (${p.phone})<br>Лимит: ${p.limit}₸</div>`).join('')}
<p style="margin-top:30px;color:#5B6573;font-size:14px">Распечатано: ${new Date().toLocaleString('ru-RU')}</p>
</body></html>
`);
printWindow.document.close();
printWindow.print();
}
// === Добавление/удаление ===
document.getElementById('add-form').addEventListener('submit', (e) => {
e.preventDefault();