flpolprojects commited on
Commit
c024b89
·
verified ·
1 Parent(s): 71f7874

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +85 -30
app.py CHANGED
@@ -10,7 +10,7 @@ from huggingface_hub.utils import RepositoryNotFoundError
10
  from werkzeug.utils import secure_filename
11
 
12
  app = Flask(__name__)
13
- DATA_FILE = 'dataasdem.json'
14
 
15
  # Настройки Hugging Face
16
  REPO_ID = "flpolprojects/Clients"
@@ -64,7 +64,7 @@ def upload_db_to_hf():
64
  repo_id=REPO_ID,
65
  repo_type="dataset",
66
  token=HF_TOKEN_WRITE,
67
- commit_message=f"Автоматическое резервное копирование базы данных {datetime.now().strftime('%Y-%m-%d %H:%M:S')}"
68
  )
69
  logging.info("Резервная копия JSON базы успешно загружена на Hugging Face.")
70
  except Exception as e:
@@ -105,11 +105,12 @@ def catalog():
105
  <head>
106
  <meta charset="UTF-8">
107
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
108
- <title>Routine wholesale - Женская одежда </title>
109
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
110
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
111
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
112
  <style>
 
113
  * {
114
  margin: 0;
115
  padding: 0;
@@ -137,7 +138,6 @@ def catalog():
137
  align-items: center;
138
  padding: 15px 0;
139
  border-bottom: 1px solid #e2e8f0;
140
- position: relative;
141
  }
142
  .header-logo {
143
  width: 60px;
@@ -211,8 +211,8 @@ def catalog():
211
  }
212
  .products-grid {
213
  display: grid;
214
- grid-template-columns: repeat(2, minmax(200px, 1fr)); /* Два столбца по умолчанию на всех устройствах */
215
- gap: 15px; /* Уменьшаем gap для мобильных устройств */
216
  padding: 10px;
217
  }
218
  .product {
@@ -251,7 +251,7 @@ def catalog():
251
  transform: scale(1.1);
252
  }
253
  .product h2 {
254
- font-size: 1rem; /* Уменьшаем размер текста для всех устройств */
255
  font-weight: 600;
256
  margin: 10px 0;
257
  text-align: center;
@@ -260,14 +260,14 @@ def catalog():
260
  text-overflow: ellipsis;
261
  }
262
  .product-price {
263
- font-size: 1.1rem; /* Уменьшаем размер цены для всех устройств */
264
  color: #ef4444;
265
  font-weight: 700;
266
  text-align: center;
267
  margin: 5px 0;
268
  }
269
  .product-description {
270
- font-size: 0.8rem; /* Уменьшаем размер описания для всех устройств */
271
  color: #718096;
272
  text-align: center;
273
  margin-bottom: 15px;
@@ -281,12 +281,12 @@ def catalog():
281
  .product-button {
282
  display: block;
283
  width: 100%;
284
- padding: 8px; /* Уменьшаем отступы кнопок для всех устройств */
285
  border: none;
286
  border-radius: 8px;
287
  background-color: #3b82f6;
288
  color: white;
289
- font-size: 0.8rem; /* Уменьшаем размер текста кнопок для всех устройств */
290
  font-weight: 500;
291
  cursor: pointer;
292
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
@@ -323,10 +323,6 @@ def catalog():
323
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
324
  z-index: 1000;
325
  }
326
- #cart-button:hover {
327
- background-color: #dc2626;
328
- transform: scale(1.1);
329
- }
330
  .modal {
331
  display: none;
332
  position: fixed;
@@ -389,12 +385,14 @@ def catalog():
389
  border-radius: 8px;
390
  margin-right: 15px;
391
  }
392
- .quantity-input {
393
- width: 70px;
 
394
  padding: 8px;
395
  border: 1px solid #e2e8f0;
396
  border-radius: 8px;
397
  font-size: 1rem;
 
398
  }
399
  .clear-cart {
400
  background-color: #ef4444;
@@ -461,12 +459,13 @@ def catalog():
461
  </div>
462
  </div>
463
 
464
- <!-- Quantity Modal -->
465
  <div id="quantityModal" class="modal">
466
  <div class="modal-content">
467
  <span class="close" onclick="closeModal('quantityModal')">×</span>
468
- <h2>Укажите количество</h2>
469
  <input type="number" id="quantityInput" class="quantity-input" min="1" value="1">
 
470
  <button class="product-button" onclick="confirmAddToCart()">Добавить</button>
471
  </div>
472
  </div>
@@ -540,6 +539,22 @@ def catalog():
540
 
541
  function openQuantityModal(index) {
542
  selectedProductIndex = index;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
543
  document.getElementById('quantityModal').style.display = 'block';
544
  document.getElementById('quantityInput').value = 1;
545
  }
@@ -547,22 +562,26 @@ def catalog():
547
  function confirmAddToCart() {
548
  if (selectedProductIndex === null) return;
549
  const quantity = parseInt(document.getElementById('quantityInput').value) || 1;
 
550
  if (quantity <= 0) {
551
  alert("Укажите количество больше 0");
552
  return;
553
  }
554
  let cart = JSON.parse(localStorage.getItem('cart') || '[]');
555
  const product = products[selectedProductIndex];
556
- const existingItem = cart.find(item => item.name === product.name);
 
557
 
558
  if (existingItem) {
559
  existingItem.quantity += quantity;
560
  } else {
561
  cart.push({
 
562
  name: product.name,
563
  price: product.price,
564
  photo: product.photos && product.photos.length > 0 ? product.photos[0] : '',
565
- quantity: quantity
 
566
  });
567
  }
568
 
@@ -590,7 +609,7 @@ def catalog():
590
  ${item.photo ? `<img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/${item.photo}" alt="${item.name}">` : ''}
591
  <div>
592
  <strong>${item.name}</strong>
593
- <p>${item.price} с × ${item.quantity}</p>
594
  </div>
595
  </div>
596
  <span>${itemTotal} с</span>
@@ -613,7 +632,7 @@ def catalog():
613
  cart.forEach((item, index) => {
614
  const itemTotal = item.price * item.quantity;
615
  total += itemTotal;
616
- orderText += `${index + 1}. ${item.name} - ${item.price} с × ${item.quantity}%0A`;
617
  });
618
  orderText += `Итого: ${total} с`;
619
  window.open(`https://api.whatsapp.com/send?phone=996772179559&text=${orderText}`, '_blank');
@@ -694,6 +713,7 @@ def product_detail(index):
694
  <p><strong>Категория:</strong> {{ product.get('category', 'Без категории') }}</p>
695
  <p><strong>Цена:</strong> {{ product['price'] }} с</p>
696
  <p><strong>Описание:</strong> {{ product['description'] }}</p>
 
697
  </div>
698
  '''
699
  return render_template_string(detail_html, product=product, repo_id=REPO_ID)
@@ -730,6 +750,7 @@ def admin():
730
  description = request.form.get('description')
731
  category = request.form.get('category')
732
  photos_files = request.files.getlist('photos')
 
733
  photos_list = []
734
 
735
  if photos_files:
@@ -762,7 +783,8 @@ def admin():
762
  'price': price,
763
  'description': description,
764
  'category': category if category in categories else 'Без категории',
765
- 'photos': photos_list
 
766
  }
767
  products.append(new_product)
768
  save_data(data)
@@ -775,6 +797,7 @@ def admin():
775
  description = request.form.get('description')
776
  category = request.form.get('category')
777
  photos_files = request.files.getlist('photos')
 
778
 
779
  if photos_files and any(photo.filename for photo in photos_files):
780
  new_photos_list = []
@@ -803,6 +826,7 @@ def admin():
803
  products[index]['price'] = float(price.replace(',', '.'))
804
  products[index]['description'] = description
805
  products[index]['category'] = category if category in categories else 'Без категории'
 
806
  save_data(data)
807
  return redirect(url_for('admin'))
808
 
@@ -919,11 +943,16 @@ def admin():
919
  background: #f7fafc;
920
  border-radius: 10px;
921
  }
922
- @media (max-width: 768px) {
923
- .header-logo {
924
- width: 50px;
925
- height: 50px;
926
- }
 
 
 
 
 
927
  }
928
  </style>
929
  </head>
@@ -951,7 +980,14 @@ def admin():
951
  </select>
952
  <label>Фотографии (до 2):</label>
953
  <input type="file" name="photos" accept="image/*" multiple>
954
- <button type="submit">Добавить</button>
 
 
 
 
 
 
 
955
  </form>
956
 
957
  <h1>Управление категориями</h1>
@@ -992,6 +1028,7 @@ def admin():
992
  <p><strong>Категория:</strong> {{ product.get('category', 'Без категории') }}</p>
993
  <p><strong>Цена:</strong> {{ product['price'] }} с</p>
994
  <p><strong>Описание:</strong> {{ product['description'] }}</p>
 
995
  {% if product.get('photos') and product['photos']|length > 0 %}
996
  <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ product['photos'][0] }}"
997
  alt="{{ product['name'] }}"
@@ -1017,6 +1054,15 @@ def admin():
1017
  </select>
1018
  <label>Фотографии:</label>
1019
  <input type="file" name="photos" accept="image/*" multiple>
 
 
 
 
 
 
 
 
 
1020
  <button type="submit">Сохранить</button>
1021
  </form>
1022
  </details>
@@ -1029,6 +1075,15 @@ def admin():
1029
  {% endfor %}
1030
  </div>
1031
  </div>
 
 
 
 
 
 
 
 
 
1032
  </body>
1033
  </html>
1034
  '''
 
10
  from werkzeug.utils import secure_filename
11
 
12
  app = Flask(__name__)
13
+ DATA_FILE = 'datatest.json'
14
 
15
  # Настройки Hugging Face
16
  REPO_ID = "flpolprojects/Clients"
 
64
  repo_id=REPO_ID,
65
  repo_type="dataset",
66
  token=HF_TOKEN_WRITE,
67
+ commit_message=f"Автоматическое резервное копирование базы данных {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
68
  )
69
  logging.info("Резервная копия JSON базы успешно загружена на Hugging Face.")
70
  except Exception as e:
 
105
  <head>
106
  <meta charset="UTF-8">
107
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
108
+ <title>Routine wholesale - Женская одежда</title>
109
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
110
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
111
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
112
  <style>
113
+ /* Существующие стили остаются без изменений */
114
  * {
115
  margin: 0;
116
  padding: 0;
 
138
  align-items: center;
139
  padding: 15px 0;
140
  border-bottom: 1px solid #e2e8f0;
 
141
  }
142
  .header-logo {
143
  width: 60px;
 
211
  }
212
  .products-grid {
213
  display: grid;
214
+ grid-template-columns: repeat(2, minmax(200px, 1fr));
215
+ gap: 15px;
216
  padding: 10px;
217
  }
218
  .product {
 
251
  transform: scale(1.1);
252
  }
253
  .product h2 {
254
+ font-size: 1rem;
255
  font-weight: 600;
256
  margin: 10px 0;
257
  text-align: center;
 
260
  text-overflow: ellipsis;
261
  }
262
  .product-price {
263
+ font-size: 1.1rem;
264
  color: #ef4444;
265
  font-weight: 700;
266
  text-align: center;
267
  margin: 5px 0;
268
  }
269
  .product-description {
270
+ font-size: 0.8rem;
271
  color: #718096;
272
  text-align: center;
273
  margin-bottom: 15px;
 
281
  .product-button {
282
  display: block;
283
  width: 100%;
284
+ padding: 8px;
285
  border: none;
286
  border-radius: 8px;
287
  background-color: #3b82f6;
288
  color: white;
289
+ font-size: 0.8rem;
290
  font-weight: 500;
291
  cursor: pointer;
292
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
 
323
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
324
  z-index: 1000;
325
  }
 
 
 
 
326
  .modal {
327
  display: none;
328
  position: fixed;
 
385
  border-radius: 8px;
386
  margin-right: 15px;
387
  }
388
+ .quantity-input, .color-select {
389
+ width: 100%;
390
+ max-width: 150px;
391
  padding: 8px;
392
  border: 1px solid #e2e8f0;
393
  border-radius: 8px;
394
  font-size: 1rem;
395
+ margin: 5px 0;
396
  }
397
  .clear-cart {
398
  background-color: #ef4444;
 
459
  </div>
460
  </div>
461
 
462
+ <!-- Quantity and Color Modal -->
463
  <div id="quantityModal" class="modal">
464
  <div class="modal-content">
465
  <span class="close" onclick="closeModal('quantityModal')">×</span>
466
+ <h2>Укажите количество и цвет</h2>
467
  <input type="number" id="quantityInput" class="quantity-input" min="1" value="1">
468
+ <select id="colorSelect" class="color-select"></select>
469
  <button class="product-button" onclick="confirmAddToCart()">Добавить</button>
470
  </div>
471
  </div>
 
539
 
540
  function openQuantityModal(index) {
541
  selectedProductIndex = index;
542
+ const product = products[index];
543
+ const colorSelect = document.getElementById('colorSelect');
544
+ colorSelect.innerHTML = '';
545
+ if (product.colors && product.colors.length > 0) {
546
+ product.colors.forEach(color => {
547
+ const option = document.createElement('option');
548
+ option.value = color;
549
+ option.text = color;
550
+ colorSelect.appendChild(option);
551
+ });
552
+ } else {
553
+ const option = document.createElement('option');
554
+ option.value = 'Нет цвета';
555
+ option.text = 'Нет цвета';
556
+ colorSelect.appendChild(option);
557
+ }
558
  document.getElementById('quantityModal').style.display = 'block';
559
  document.getElementById('quantityInput').value = 1;
560
  }
 
562
  function confirmAddToCart() {
563
  if (selectedProductIndex === null) return;
564
  const quantity = parseInt(document.getElementById('quantityInput').value) || 1;
565
+ const color = document.getElementById('colorSelect').value;
566
  if (quantity <= 0) {
567
  alert("Укажите количество больше 0");
568
  return;
569
  }
570
  let cart = JSON.parse(localStorage.getItem('cart') || '[]');
571
  const product = products[selectedProductIndex];
572
+ const cartItemId = `${product.name}-${color}`;
573
+ const existingItem = cart.find(item => item.id === cartItemId);
574
 
575
  if (existingItem) {
576
  existingItem.quantity += quantity;
577
  } else {
578
  cart.push({
579
+ id: cartItemId,
580
  name: product.name,
581
  price: product.price,
582
  photo: product.photos && product.photos.length > 0 ? product.photos[0] : '',
583
+ quantity: quantity,
584
+ color: color
585
  });
586
  }
587
 
 
609
  ${item.photo ? `<img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/${item.photo}" alt="${item.name}">` : ''}
610
  <div>
611
  <strong>${item.name}</strong>
612
+ <p>${item.price} с × ${item.quantity} (Цвет: ${item.color})</p>
613
  </div>
614
  </div>
615
  <span>${itemTotal} с</span>
 
632
  cart.forEach((item, index) => {
633
  const itemTotal = item.price * item.quantity;
634
  total += itemTotal;
635
+ orderText += `${index + 1}. ${item.name} - ${item.price} с × ${item.quantity} (Цвет: ${item.color})%0A`;
636
  });
637
  orderText += `Итого: ${total} с`;
638
  window.open(`https://api.whatsapp.com/send?phone=996772179559&text=${orderText}`, '_blank');
 
713
  <p><strong>Категория:</strong> {{ product.get('category', 'Без категории') }}</p>
714
  <p><strong>Цена:</strong> {{ product['price'] }} с</p>
715
  <p><strong>Описание:</strong> {{ product['description'] }}</p>
716
+ <p><strong>Доступные цвета:</strong> {{ product.get('colors', ['Нет цветов'])|join(', ') }}</p>
717
  </div>
718
  '''
719
  return render_template_string(detail_html, product=product, repo_id=REPO_ID)
 
750
  description = request.form.get('description')
751
  category = request.form.get('category')
752
  photos_files = request.files.getlist('photos')
753
+ colors = request.form.getlist('colors') # Получаем список цветов
754
  photos_list = []
755
 
756
  if photos_files:
 
783
  'price': price,
784
  'description': description,
785
  'category': category if category in categories else 'Без категории',
786
+ 'photos': photos_list,
787
+ 'colors': colors if colors else [] # Добавляем цвета
788
  }
789
  products.append(new_product)
790
  save_data(data)
 
797
  description = request.form.get('description')
798
  category = request.form.get('category')
799
  photos_files = request.files.getlist('photos')
800
+ colors = request.form.getlist('colors') # Обновляем цвета
801
 
802
  if photos_files and any(photo.filename for photo in photos_files):
803
  new_photos_list = []
 
826
  products[index]['price'] = float(price.replace(',', '.'))
827
  products[index]['description'] = description
828
  products[index]['category'] = category if category in categories else 'Без категории'
829
+ products[index]['colors'] = colors if colors else [] # Обновляем цвета
830
  save_data(data)
831
  return redirect(url_for('admin'))
832
 
 
943
  background: #f7fafc;
944
  border-radius: 10px;
945
  }
946
+ .color-input-group {
947
+ display: flex;
948
+ gap: 10px;
949
+ margin-top: 5px;
950
+ }
951
+ .add-color-btn {
952
+ background-color: #10b981;
953
+ }
954
+ .add-color-btn:hover {
955
+ background-color: #059669;
956
  }
957
  </style>
958
  </head>
 
980
  </select>
981
  <label>Фотографии (до 2):</label>
982
  <input type="file" name="photos" accept="image/*" multiple>
983
+ <label>Цвета:</label>
984
+ <div id="color-inputs">
985
+ <div class="color-input-group">
986
+ <input type="text" name="colors" placeholder="Например: Красный">
987
+ </div>
988
+ </div>
989
+ <button type="button" class="add-color-btn" onclick="addColorInput()">Добавить цвет</button>
990
+ <button type="submit">Добавить товар</button>
991
  </form>
992
 
993
  <h1>Управление категориями</h1>
 
1028
  <p><strong>Категория:</strong> {{ product.get('category', 'Без категории') }}</p>
1029
  <p><strong>Цена:</strong> {{ product['price'] }} с</p>
1030
  <p><strong>Описание:</strong> {{ product['description'] }}</p>
1031
+ <p><strong>Цвета:</strong> {{ product.get('colors', ['Нет цветов'])|join(', ') }}</p>
1032
  {% if product.get('photos') and product['photos']|length > 0 %}
1033
  <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ product['photos'][0] }}"
1034
  alt="{{ product['name'] }}"
 
1054
  </select>
1055
  <label>Фотографии:</label>
1056
  <input type="file" name="photos" accept="image/*" multiple>
1057
+ <label>Цвета:</label>
1058
+ <div id="edit-color-inputs-{{ loop.index0 }}">
1059
+ {% for color in product.get('colors', []) %}
1060
+ <div class="color-input-group">
1061
+ <input type="text" name="colors" value="{{ color }}">
1062
+ </div>
1063
+ {% endfor %}
1064
+ </div>
1065
+ <button type="button" class="add-color-btn" onclick="addColorInput('edit-color-inputs-{{ loop.index0 }}')">Добавить цвет</button>
1066
  <button type="submit">Сохранить</button>
1067
  </form>
1068
  </details>
 
1075
  {% endfor %}
1076
  </div>
1077
  </div>
1078
+ <script>
1079
+ function addColorInput(containerId = 'color-inputs') {
1080
+ const container = document.getElementById(containerId);
1081
+ const newInput = document.createElement('div');
1082
+ newInput.className = 'color-input-group';
1083
+ newInput.innerHTML = '<input type="text" name="colors" placeholder="Например: Красный">';
1084
+ container.appendChild(newInput);
1085
+ }
1086
+ </script>
1087
  </body>
1088
  </html>
1089
  '''