Kgshop commited on
Commit
c600fac
·
verified ·
1 Parent(s): b1c7292

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -31
app.py CHANGED
@@ -204,7 +204,10 @@ CATALOG_TEMPLATE = '''
204
  .quantity-control { display: flex; align-items: center; background: var(--bg); border-radius: 8px; overflow: hidden; border: 1px solid var(--border); }
205
  .quantity-control button { border: none; background: transparent; width: 32px; height: 32px; font-size: 1.1rem; cursor: pointer; color: var(--primary); display: flex; align-items: center; justify-content: center; transition: background 0.2s; }
206
  .quantity-control button:active { background: #e0e0e0; }
207
- .quantity-control input { width: 36px; height: 32px; border: none; text-align: center; background: transparent; font-weight: 600; font-size: 0.95rem; pointer-events: none; color: var(--primary); }
 
 
 
208
  .box-btn { background: var(--primary); color: #fff; border: none; border-radius: 8px; padding: 0 10px; height: 32px; font-size: 0.8rem; font-weight: 600; cursor: pointer; transition: opacity 0.2s; }
209
  .box-btn:active { opacity: 0.8; }
210
 
@@ -232,7 +235,10 @@ CATALOG_TEMPLATE = '''
232
  .cart-item-controls { display: flex; align-items: center; background: var(--surface); border-radius: 8px; border: 1px solid var(--border); overflow: hidden; }
233
  .cart-item-controls button { border: none; background: transparent; width: 30px; height: 30px; font-size: 1rem; cursor: pointer; color: var(--primary); }
234
  .cart-item-controls button:active { background: #e0e0e0; }
235
- .cart-item-controls span { width: 35px; text-align: center; font-weight: 600; font-size: 0.9rem; }
 
 
 
236
  .cart-item-price { font-weight: 700; color: var(--primary); min-width: 70px; text-align: right; }
237
  .cart-item-delete { color: #ff7675; background: none; border: none; font-size: 1.1rem; cursor: pointer; padding: 5px; }
238
 
@@ -446,7 +452,7 @@ CATALOG_TEMPLATE = '''
446
  ${addBoxBtn}
447
  <div class="quantity-control">
448
  <button onclick="updateCart('${p.product_id}', -1)"><i class="fas fa-minus" style="font-size:0.8rem;"></i></button>
449
- <input type="text" id="qty-${p.product_id}" value="${qty}" readonly>
450
  <button onclick="updateCart('${p.product_id}', 1)"><i class="fas fa-plus" style="font-size:0.8rem;"></i></button>
451
  </div>
452
  </div>
@@ -499,6 +505,12 @@ CATALOG_TEMPLATE = '''
499
  updateCartUI();
500
  }
501
 
 
 
 
 
 
 
502
  function updateCartUI() {
503
  let total = 0;
504
  for (let id in cart) {
@@ -537,7 +549,7 @@ CATALOG_TEMPLATE = '''
537
  <div style="display:flex; align-items:center; gap: 10px;">
538
  <div class="cart-item-controls">
539
  <button onclick="updateCart('${id}', -1)"><i class="fas fa-minus" style="font-size:0.8rem;"></i></button>
540
- <span>${item.quantity}</span>
541
  <button onclick="updateCart('${id}', 1)"><i class="fas fa-plus" style="font-size:0.8rem;"></i></button>
542
  </div>
543
  <button class="cart-item-delete" onclick="updateCart('${id}', 0, 0)"><i class="fas fa-trash-alt"></i></button>
@@ -692,12 +704,16 @@ ORDER_TEMPLATE = '''
692
  .total-row { background: #fafafa; font-weight: 800; }
693
  .total-row td { font-size: 1.1rem; border-bottom: none; }
694
 
695
- .qty-info { font-size: 0.8rem; color: #00b894; font-weight: 600; margin-top: 4px; display: block; }
 
 
 
 
 
 
696
 
697
- .action-btns { display: flex; align-items: center; justify-content: center; gap: 5px; }
698
- .edit-btn { background: #f1f2f6; border: 1px solid var(--border); border-radius: 6px; width: 28px; height: 28px; cursor: pointer; color: var(--primary); display: flex; align-items: center; justify-content: center; }
699
- .edit-btn:active { background: #dfe6e9; }
700
- .delete-btn { color: #ff7675; }
701
 
702
  .action-bar { position: fixed; bottom: 0; left: 0; width: 100%; background: var(--surface); box-shadow: 0 -4px 20px rgba(0,0,0,0.08); padding: 15px 20px calc(15px + env(safe-area-inset-bottom)); display: flex; gap: 15px; z-index: 100; justify-content: center; border-top-left-radius: 20px; border-top-right-radius: 20px; }
703
  .action-bar-inner { display: flex; gap: 15px; width: 100%; max-width: 900px; }
@@ -715,7 +731,8 @@ ORDER_TEMPLATE = '''
715
  .table-responsive { border: none; overflow: visible; }
716
  table { min-width: 100%; }
717
  th, td { border: 1px solid #000; }
718
- .action-bar, .no-print { display: none !important; }
 
719
  }
720
  @media (max-width: 600px) {
721
  .header h1 { font-size: 1.4rem; }
@@ -758,7 +775,6 @@ ORDER_TEMPLATE = '''
758
  <th style="text-align: left;">Наименование</th>
759
  <th>Фото</th>
760
  <th>Кол-во</th>
761
- <th class="no-print">Действия</th>
762
  <th>Цена</th>
763
  <th>Сумма</th>
764
  </tr>
@@ -766,27 +782,38 @@ ORDER_TEMPLATE = '''
766
  <tbody>
767
  {% for item in order.cart %}
768
  {% set ppb = item.pieces_per_box|default(1)|int %}
769
- {% set boxes = (item.quantity / ppb)|round(0, 'floor')|int %}
770
  {% set remainder = item.quantity % ppb %}
771
  <tr>
772
  <td>{{ loop.index }}</td>
773
- <td style="text-align: left; font-weight: 500;">
774
- {{ item.name }}
775
- <span class="qty-info">
776
- {% if ppb > 1 and boxes > 0 %}
777
- {{ boxes }} кор.{% if remainder > 0 %} {{ remainder }} шт.{% endif %}
778
- {% else %}
779
- {{ item.quantity }} шт.
780
- {% endif %}
781
- </span>
782
- </td>
783
  <td class="img-cell"><img src="{{ item.photo_url }}" alt="img"></td>
784
- <td style="font-weight: bold;">{{ item.quantity }}</td>
785
- <td class="no-print">
786
- <div class="action-btns">
787
- <button class="edit-btn" onclick="updateItem('{{ item.product_id }}', -1)"><i class="fas fa-minus" style="font-size:0.7rem;"></i></button>
788
- <button class="edit-btn" onclick="updateItem('{{ item.product_id }}', 1)"><i class="fas fa-plus" style="font-size:0.7rem;"></i></button>
789
- <button class="edit-btn delete-btn" onclick="updateItem('{{ item.product_id }}', 0, true)"><i class="fas fa-trash"></i></button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
790
  </div>
791
  </td>
792
  <td>{{ item.price }}</td>
@@ -794,7 +821,7 @@ ORDER_TEMPLATE = '''
794
  </tr>
795
  {% endfor %}
796
  <tr class="total-row">
797
- <td colspan="6" style="text-align: right; padding-right: 20px;">Итого:</td>
798
  <td>{{ order.total_price }} {{ currency_code }}</td>
799
  </tr>
800
  </tbody>
@@ -837,6 +864,30 @@ ORDER_TEMPLATE = '''
837
  document.getElementById('loadingOverlay').style.display = 'none';
838
  });
839
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
840
  </script>
841
  </body>
842
  </html>
@@ -1196,6 +1247,7 @@ def edit_order(order_id):
1196
  req_data = request.get_json()
1197
  product_id = req_data.get('product_id')
1198
  change = req_data.get('change', 0)
 
1199
  remove = req_data.get('remove', False)
1200
 
1201
  for item in order['cart']:
@@ -1203,7 +1255,11 @@ def edit_order(order_id):
1203
  if remove:
1204
  order['cart'].remove(item)
1205
  else:
1206
- item['quantity'] += change
 
 
 
 
1207
  if item['quantity'] <= 0:
1208
  order['cart'].remove(item)
1209
  break
@@ -1367,4 +1423,4 @@ if __name__ == '__main__':
1367
  threading.Thread(target=periodic_backup, daemon=True).start()
1368
 
1369
  port = int(os.environ.get('PORT', 7860))
1370
- app.run(host='0.0.0.0', port=port)
 
204
  .quantity-control { display: flex; align-items: center; background: var(--bg); border-radius: 8px; overflow: hidden; border: 1px solid var(--border); }
205
  .quantity-control button { border: none; background: transparent; width: 32px; height: 32px; font-size: 1.1rem; cursor: pointer; color: var(--primary); display: flex; align-items: center; justify-content: center; transition: background 0.2s; }
206
  .quantity-control button:active { background: #e0e0e0; }
207
+ .quantity-control input { width: 36px; height: 32px; border: none; text-align: center; background: transparent; font-weight: 600; font-size: 0.95rem; color: var(--primary); outline: none; }
208
+ .quantity-control input[type="number"]::-webkit-inner-spin-button,
209
+ .quantity-control input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
210
+ .quantity-control input[type="number"] { -moz-appearance: textfield; }
211
  .box-btn { background: var(--primary); color: #fff; border: none; border-radius: 8px; padding: 0 10px; height: 32px; font-size: 0.8rem; font-weight: 600; cursor: pointer; transition: opacity 0.2s; }
212
  .box-btn:active { opacity: 0.8; }
213
 
 
235
  .cart-item-controls { display: flex; align-items: center; background: var(--surface); border-radius: 8px; border: 1px solid var(--border); overflow: hidden; }
236
  .cart-item-controls button { border: none; background: transparent; width: 30px; height: 30px; font-size: 1rem; cursor: pointer; color: var(--primary); }
237
  .cart-item-controls button:active { background: #e0e0e0; }
238
+ .cart-item-controls input { width: 35px; text-align: center; font-weight: 600; font-size: 0.9rem; border: none; background: transparent; color: var(--primary); outline: none; }
239
+ .cart-item-controls input[type="number"]::-webkit-inner-spin-button,
240
+ .cart-item-controls input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
241
+ .cart-item-controls input[type="number"] { -moz-appearance: textfield; }
242
  .cart-item-price { font-weight: 700; color: var(--primary); min-width: 70px; text-align: right; }
243
  .cart-item-delete { color: #ff7675; background: none; border: none; font-size: 1.1rem; cursor: pointer; padding: 5px; }
244
 
 
452
  ${addBoxBtn}
453
  <div class="quantity-control">
454
  <button onclick="updateCart('${p.product_id}', -1)"><i class="fas fa-minus" style="font-size:0.8rem;"></i></button>
455
+ <input type="number" id="qty-${p.product_id}" value="${qty}" onchange="manualUpdateCart('${p.product_id}', this.value)">
456
  <button onclick="updateCart('${p.product_id}', 1)"><i class="fas fa-plus" style="font-size:0.8rem;"></i></button>
457
  </div>
458
  </div>
 
505
  updateCartUI();
506
  }
507
 
508
+ function manualUpdateCart(productId, val) {
509
+ let num = parseInt(val);
510
+ if (isNaN(num) || num < 0) num = 0;
511
+ updateCart(productId, 0, num);
512
+ }
513
+
514
  function updateCartUI() {
515
  let total = 0;
516
  for (let id in cart) {
 
549
  <div style="display:flex; align-items:center; gap: 10px;">
550
  <div class="cart-item-controls">
551
  <button onclick="updateCart('${id}', -1)"><i class="fas fa-minus" style="font-size:0.8rem;"></i></button>
552
+ <input type="number" value="${item.quantity}" onchange="manualUpdateCart('${id}', this.value)">
553
  <button onclick="updateCart('${id}', 1)"><i class="fas fa-plus" style="font-size:0.8rem;"></i></button>
554
  </div>
555
  <button class="cart-item-delete" onclick="updateCart('${id}', 0, 0)"><i class="fas fa-trash-alt"></i></button>
 
704
  .total-row { background: #fafafa; font-weight: 800; }
705
  .total-row td { font-size: 1.1rem; border-bottom: none; }
706
 
707
+ .cart-item-controls { display: inline-flex; align-items: center; background: var(--surface); border-radius: 8px; border: 1px solid var(--border); overflow: hidden; margin-bottom: 5px; }
708
+ .cart-item-controls button { border: none; background: #f8f9fa; width: 30px; height: 30px; font-size: 1rem; cursor: pointer; color: var(--primary); transition: background 0.2s; }
709
+ .cart-item-controls button:active { background: #e0e0e0; }
710
+ .cart-item-controls input { width: 40px; text-align: center; font-weight: 600; font-size: 0.95rem; border: none; background: transparent; color: var(--primary); outline: none; }
711
+ .cart-item-controls input[type="number"]::-webkit-inner-spin-button,
712
+ .cart-item-controls input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
713
+ .cart-item-controls input[type="number"] { -moz-appearance: textfield; }
714
 
715
+ .screen-only { display: block; }
716
+ .print-only { display: none; }
 
 
717
 
718
  .action-bar { position: fixed; bottom: 0; left: 0; width: 100%; background: var(--surface); box-shadow: 0 -4px 20px rgba(0,0,0,0.08); padding: 15px 20px calc(15px + env(safe-area-inset-bottom)); display: flex; gap: 15px; z-index: 100; justify-content: center; border-top-left-radius: 20px; border-top-right-radius: 20px; }
719
  .action-bar-inner { display: flex; gap: 15px; width: 100%; max-width: 900px; }
 
731
  .table-responsive { border: none; overflow: visible; }
732
  table { min-width: 100%; }
733
  th, td { border: 1px solid #000; }
734
+ .action-bar, .screen-only { display: none !important; }
735
+ .print-only { display: block !important; }
736
  }
737
  @media (max-width: 600px) {
738
  .header h1 { font-size: 1.4rem; }
 
775
  <th style="text-align: left;">Наименование</th>
776
  <th>Фото</th>
777
  <th>Кол-во</th>
 
778
  <th>Цена</th>
779
  <th>Сумма</th>
780
  </tr>
 
782
  <tbody>
783
  {% for item in order.cart %}
784
  {% set ppb = item.pieces_per_box|default(1)|int %}
785
+ {% set boxes = item.quantity // ppb %}
786
  {% set remainder = item.quantity % ppb %}
787
  <tr>
788
  <td>{{ loop.index }}</td>
789
+ <td style="text-align: left; font-weight: 500;">{{ item.name }}</td>
 
 
 
 
 
 
 
 
 
790
  <td class="img-cell"><img src="{{ item.photo_url }}" alt="img"></td>
791
+ <td style="text-align: center;">
792
+ <div class="screen-only">
793
+ <div style="display:flex; flex-direction:column; align-items:center; gap:4px;">
794
+ <div style="display:flex; align-items:center; gap:8px;">
795
+ <div class="cart-item-controls">
796
+ <button onclick="updateItem('{{ item.product_id }}', -1)"><i class="fas fa-minus" style="font-size:0.7rem;"></i></button>
797
+ <input type="number" value="{{ item.quantity }}" onchange="manualUpdateOrder('{{ item.product_id }}', this.value)">
798
+ <button onclick="updateItem('{{ item.product_id }}', 1)"><i class="fas fa-plus" style="font-size:0.7rem;"></i></button>
799
+ </div>
800
+ <button onclick="updateItem('{{ item.product_id }}', 0, true)" style="color: #ff7675; background: none; border: none; font-size: 1.1rem; cursor: pointer; padding: 5px;"><i class="fas fa-trash-alt"></i></button>
801
+ </div>
802
+ <div style="font-size: 0.85rem; color: #00b894; font-weight: 600;">
803
+ {% if ppb > 1 and boxes > 0 %}
804
+ {{ boxes }} кор.{% if remainder > 0 %} {{ remainder }} шт.{% endif %}
805
+ {% else %}
806
+ {{ item.quantity }} шт.
807
+ {% endif %}
808
+ </div>
809
+ </div>
810
+ </div>
811
+ <div class="print-only" style="font-weight: bold;">
812
+ {% if ppb > 1 and boxes > 0 %}
813
+ {{ boxes }} кор.{% if remainder > 0 %} {{ remainder }} шт.{% endif %}
814
+ {% else %}
815
+ {{ item.quantity }} шт.
816
+ {% endif %}
817
  </div>
818
  </td>
819
  <td>{{ item.price }}</td>
 
821
  </tr>
822
  {% endfor %}
823
  <tr class="total-row">
824
+ <td colspan="5" style="text-align: right; padding-right: 20px;">Итого:</td>
825
  <td>{{ order.total_price }} {{ currency_code }}</td>
826
  </tr>
827
  </tbody>
 
864
  document.getElementById('loadingOverlay').style.display = 'none';
865
  });
866
  }
867
+
868
+ function manualUpdateOrder(productId, val) {
869
+ let num = parseInt(val);
870
+ if (isNaN(num) || num < 0) return;
871
+ document.getElementById('loadingOverlay').style.display = 'flex';
872
+ fetch(`/edit_order/{{ order.id }}`, {
873
+ method: 'POST',
874
+ headers: { 'Content-Type': 'application/json' },
875
+ body: JSON.stringify({ product_id: productId, exact_qty: num })
876
+ })
877
+ .then(r => r.json())
878
+ .then(data => {
879
+ if(data.success) {
880
+ window.location.reload();
881
+ } else {
882
+ alert('Ошибка обновления');
883
+ document.getElementById('loadingOverlay').style.display = 'none';
884
+ }
885
+ })
886
+ .catch(() => {
887
+ alert('Произошла ошибка');
888
+ document.getElementById('loadingOverlay').style.display = 'none';
889
+ });
890
+ }
891
  </script>
892
  </body>
893
  </html>
 
1247
  req_data = request.get_json()
1248
  product_id = req_data.get('product_id')
1249
  change = req_data.get('change', 0)
1250
+ exact_qty = req_data.get('exact_qty')
1251
  remove = req_data.get('remove', False)
1252
 
1253
  for item in order['cart']:
 
1255
  if remove:
1256
  order['cart'].remove(item)
1257
  else:
1258
+ if exact_qty is not None:
1259
+ item['quantity'] = int(exact_qty)
1260
+ else:
1261
+ item['quantity'] += change
1262
+
1263
  if item['quantity'] <= 0:
1264
  order['cart'].remove(item)
1265
  break
 
1423
  threading.Thread(target=periodic_backup, daemon=True).start()
1424
 
1425
  port = int(os.environ.get('PORT', 7860))
1426
+ app.run(host='0.0.0.0', port=port)