Spaces:
Running
Running
Update cafe.html
Browse files
cafe.html
CHANGED
|
@@ -121,7 +121,6 @@
|
|
| 121 |
|
| 122 |
.arch-shape { border-radius: 50% 50% 1rem 1rem / 35% 35% 1rem 1rem; }
|
| 123 |
|
| 124 |
-
/* Chat Markdown */
|
| 125 |
.chat-markdown { line-height: 1.85; word-wrap: break-word; overflow-wrap: break-word; }
|
| 126 |
.chat-markdown > * + * { margin-top: 0.6em; }
|
| 127 |
.chat-markdown h1, .chat-markdown h2, .chat-markdown h3,
|
|
@@ -189,7 +188,6 @@
|
|
| 189 |
.chat-markdown tr:last-child td { border-bottom: none; }
|
| 190 |
.chat-markdown img { max-width: 100%; border-radius: 10px; border: 2px solid rgba(201, 169, 97, 0.3); }
|
| 191 |
|
| 192 |
-
/* Typing dots */
|
| 193 |
.typing-dots span {
|
| 194 |
display: inline-block; width: 6px; height: 6px;
|
| 195 |
border-radius: 50%; background: #c9a961;
|
|
@@ -202,7 +200,6 @@
|
|
| 202 |
30% { transform: translateY(-8px); opacity: 1; }
|
| 203 |
}
|
| 204 |
|
| 205 |
-
/* Buttons */
|
| 206 |
.btn-primary {
|
| 207 |
background: linear-gradient(135deg, #c9a961 0%, #9c7d3a 100%);
|
| 208 |
color: #1a0d07; font-weight: 800;
|
|
@@ -240,7 +237,6 @@
|
|
| 240 |
transform: translateY(-1px);
|
| 241 |
}
|
| 242 |
|
| 243 |
-
/* Drop zone */
|
| 244 |
.drop-zone {
|
| 245 |
position: relative;
|
| 246 |
border: 2px dashed rgba(201, 169, 97, 0.3);
|
|
@@ -259,7 +255,7 @@
|
|
| 259 |
pointer-events: none;
|
| 260 |
}
|
| 261 |
|
| 262 |
-
/*
|
| 263 |
.order-card {
|
| 264 |
background: linear-gradient(135deg, rgba(45, 24, 16, 0.6), rgba(26, 13, 7, 0.5));
|
| 265 |
border: 1px solid rgba(201, 169, 97, 0.2);
|
|
@@ -270,6 +266,28 @@
|
|
| 270 |
box-shadow: 0 12px 30px -10px rgba(139, 30, 63, 0.3);
|
| 271 |
transform: translateY(-2px);
|
| 272 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 273 |
|
| 274 |
.menu-row { transition: all 0.3s ease; }
|
| 275 |
.menu-row:hover { background: rgba(201, 169, 97, 0.05); }
|
|
@@ -280,7 +298,6 @@
|
|
| 280 |
box-shadow: 0 0 0 3px rgba(201, 169, 97, 0.15);
|
| 281 |
}
|
| 282 |
|
| 283 |
-
/* Checkbox */
|
| 284 |
input[type="checkbox"] {
|
| 285 |
appearance: none; width: 18px; height: 18px;
|
| 286 |
border: 2px solid rgba(201, 169, 97, 0.4);
|
|
@@ -342,7 +359,6 @@
|
|
| 342 |
|
| 343 |
button, .no-select { -webkit-user-select: none; user-select: none; }
|
| 344 |
|
| 345 |
-
/* ============ MAIN LAYOUT ============ */
|
| 346 |
.app-wrapper {
|
| 347 |
display: flex;
|
| 348 |
flex-direction: column;
|
|
@@ -351,8 +367,6 @@
|
|
| 351 |
overflow: hidden;
|
| 352 |
}
|
| 353 |
|
| 354 |
-
/* ============ CHAT COLUMN HEIGHT CONTROL ============ */
|
| 355 |
-
/* چت هرگز بزرگتر از viewport نمیشود و اسکرول داخلی دارد */
|
| 356 |
.chat-column {
|
| 357 |
display: flex;
|
| 358 |
flex-direction: column;
|
|
@@ -375,7 +389,6 @@
|
|
| 375 |
flex-shrink: 0;
|
| 376 |
}
|
| 377 |
|
| 378 |
-
/* Desktop: ستون چت کل ارتفاع main را میگیرد */
|
| 379 |
@media (min-width: 1024px) {
|
| 380 |
.main-grid {
|
| 381 |
overflow: hidden !important;
|
|
@@ -392,14 +405,12 @@
|
|
| 392 |
}
|
| 393 |
}
|
| 394 |
|
| 395 |
-
/* Tablet & Mobile: main scroll میکند، چت ارتفاع مشخص */
|
| 396 |
@media (max-width: 1023px) {
|
| 397 |
.main-grid {
|
| 398 |
overflow-y: auto;
|
| 399 |
overflow-x: hidden;
|
| 400 |
}
|
| 401 |
.chat-column {
|
| 402 |
-
/* ارتفاع کنترلشده: حداکثر 65vh ولی نه کمتر از 400px */
|
| 403 |
height: 65vh;
|
| 404 |
height: calc(var(--vh, 1vh) * 65);
|
| 405 |
min-height: 380px;
|
|
@@ -408,7 +419,6 @@
|
|
| 408 |
}
|
| 409 |
}
|
| 410 |
|
| 411 |
-
/* Small Mobile */
|
| 412 |
@media (max-width: 480px) {
|
| 413 |
.chat-column {
|
| 414 |
height: 60vh;
|
|
@@ -418,7 +428,6 @@
|
|
| 418 |
}
|
| 419 |
}
|
| 420 |
|
| 421 |
-
/* Landscape mobile */
|
| 422 |
@media (max-height: 500px) and (orientation: landscape) {
|
| 423 |
.chat-column {
|
| 424 |
height: 75vh !important;
|
|
@@ -426,7 +435,6 @@
|
|
| 426 |
}
|
| 427 |
}
|
| 428 |
|
| 429 |
-
/* iPad Portrait */
|
| 430 |
@media (min-width: 768px) and (max-width: 1023px) {
|
| 431 |
.chat-column {
|
| 432 |
height: 70vh;
|
|
@@ -486,7 +494,7 @@
|
|
| 486 |
<!-- Main grid -->
|
| 487 |
<main class="main-grid flex-1 min-h-0 w-full mx-auto p-3 md:p-5 lg:p-6 grid grid-cols-1 lg:grid-cols-12 gap-3 md:gap-5 lg:gap-6 z-10 relative max-w-7xl">
|
| 488 |
|
| 489 |
-
<!-- Right column
|
| 490 |
<section class="left-column lg:col-span-7 flex flex-col gap-3 md:gap-5 lg:gap-6 min-h-0">
|
| 491 |
|
| 492 |
<!-- Live orders -->
|
|
@@ -505,7 +513,7 @@
|
|
| 505 |
سفارشات جدید آشپزخانه
|
| 506 |
<span class="w-2 h-2 rounded-full bg-rug-light animate-pulse flex-shrink-0"></span>
|
| 507 |
</h2>
|
| 508 |
-
<p class="text-[9px] md:text-[10px] text-cream/50 mt-0.5 truncate">
|
| 509 |
</div>
|
| 510 |
</div>
|
| 511 |
<button onclick="fetchActiveOrders()" class="btn-ghost text-[9px] md:text-[10px] flex items-center gap-1 px-2 md:px-3 py-1.5 rounded-lg md:rounded-xl flex-shrink-0">
|
|
@@ -649,7 +657,6 @@
|
|
| 649 |
<div class="chat-column glass-card-azure rounded-2xl md:rounded-3xl shadow-xl relative">
|
| 650 |
<div class="absolute inset-0 bg-arch opacity-15 pointer-events-none"></div>
|
| 651 |
|
| 652 |
-
<!-- Chat header -->
|
| 653 |
<div class="chat-header-box relative px-3.5 md:px-5 py-2.5 md:py-3 border-b border-turk/25 flex items-center gap-2.5 bg-gradient-to-l from-azure-950/60 to-azure-900/40">
|
| 654 |
<div class="w-9 h-9 md:w-10 md:h-10 rounded-xl bg-gradient-to-br from-turk/30 to-azure-700/30 border border-turk/40 flex items-center justify-center shadow-mosque flex-shrink-0">
|
| 655 |
<svg class="w-5 h-5 md:w-6 md:h-6 text-turk-glow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
|
|
@@ -666,7 +673,6 @@
|
|
| 666 |
</div>
|
| 667 |
</div>
|
| 668 |
|
| 669 |
-
<!-- Chat messages (SCROLLABLE - this is the key fix) -->
|
| 670 |
<div id="chatMessages" class="chat-messages-container p-3 md:p-4 space-y-3 relative">
|
| 671 |
<div class="flex gap-2 md:gap-2.5 max-w-[88%]">
|
| 672 |
<div class="w-7 h-7 md:w-8 md:h-8 rounded-xl bg-gradient-to-br from-turk/20 to-azure-700/20 border border-turk/30 flex items-center justify-center flex-shrink-0">
|
|
@@ -678,7 +684,6 @@
|
|
| 678 |
</div>
|
| 679 |
</div>
|
| 680 |
|
| 681 |
-
<!-- Chat loader -->
|
| 682 |
<div id="chatLoader" class="chat-loader-box hidden relative px-3 py-2 md:px-4 md:py-2.5 flex items-center justify-between bg-azure-950/70 text-[9px] md:text-[10px] text-turk-light font-semibold border-t border-turk/20">
|
| 683 |
<div class="flex items-center gap-2">
|
| 684 |
<div class="typing-dots flex gap-1">
|
|
@@ -691,7 +696,6 @@
|
|
| 691 |
</button>
|
| 692 |
</div>
|
| 693 |
|
| 694 |
-
<!-- Chat input -->
|
| 695 |
<form id="chatForm" onsubmit="sendAdminMessage(event)" class="chat-input-box relative p-2 md:p-3 border-t border-turk/20 bg-bazaar-950/60 flex gap-2 safe-bottom">
|
| 696 |
<input type="text" id="chatInput" placeholder="تغییر وضعیت یا ویرایش منو..." autocomplete="off"
|
| 697 |
class="flex-1 min-w-0 bg-azure-950/60 border border-azure-700/40 text-xs md:text-sm text-cream placeholder-ochre/40 rounded-lg md:rounded-xl px-3 md:px-4 py-2 md:py-3 focus:outline-none focus:border-ochre/60 transition-all duration-300">
|
|
@@ -705,7 +709,6 @@
|
|
| 705 |
</section>
|
| 706 |
</main>
|
| 707 |
|
| 708 |
-
<!-- Footer -->
|
| 709 |
<footer class="flex-shrink-0 border-t border-ochre/15 py-2.5 md:py-3 text-center text-[9px] md:text-[10px] text-cream/40 bg-bazaar-950/60 backdrop-blur safe-bottom">
|
| 710 |
طراحی و توسعه توسط الگوریتم داده نسترن | با الهام از فرهنگ تبریز © ۲۰۲۶
|
| 711 |
</footer>
|
|
@@ -721,7 +724,6 @@
|
|
| 721 |
window.addEventListener('resize', setVh);
|
| 722 |
window.addEventListener('orientationchange', () => setTimeout(setVh, 100));
|
| 723 |
|
| 724 |
-
// ============ AUTO SCROLL HELPER ============
|
| 725 |
function scrollChatToBottom(smooth = true) {
|
| 726 |
const chatScroll = document.getElementById('chatMessages');
|
| 727 |
if (chatScroll) {
|
|
@@ -733,13 +735,11 @@
|
|
| 733 |
}
|
| 734 |
}
|
| 735 |
|
| 736 |
-
// Auto scroll on resize (keyboard open/close)
|
| 737 |
window.addEventListener('resize', () => {
|
| 738 |
setVh();
|
| 739 |
setTimeout(scrollChatToBottom, 150);
|
| 740 |
});
|
| 741 |
|
| 742 |
-
// ============ MARKED CONFIG ============
|
| 743 |
marked.setOptions({ sanitize: true, breaks: true });
|
| 744 |
|
| 745 |
let chatHistory = [
|
|
@@ -752,11 +752,9 @@
|
|
| 752 |
fetchActiveOrders();
|
| 753 |
fetchCurrentMenu();
|
| 754 |
setInterval(fetchActiveOrders, 10000);
|
| 755 |
-
// Initial scroll to bottom
|
| 756 |
setTimeout(scrollChatToBottom, 100);
|
| 757 |
});
|
| 758 |
|
| 759 |
-
// Mobile keyboard handling
|
| 760 |
const chatInput = document.getElementById('chatInput');
|
| 761 |
if (chatInput) {
|
| 762 |
chatInput.addEventListener('focus', () => {
|
|
@@ -765,7 +763,7 @@
|
|
| 765 |
});
|
| 766 |
}
|
| 767 |
|
| 768 |
-
// ============ ORDER FUNCTIONS ============
|
| 769 |
async function fetchActiveOrders() {
|
| 770 |
const container = document.getElementById('ordersContainer');
|
| 771 |
try {
|
|
@@ -784,10 +782,47 @@
|
|
| 784 |
`;
|
| 785 |
return;
|
| 786 |
}
|
| 787 |
-
|
|
|
|
|
|
|
| 788 |
orders.forEach(order => {
|
| 789 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 790 |
order.items.forEach(item => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 791 |
itemsHtml += `
|
| 792 |
<div class="flex items-center justify-between text-[10px] md:text-[11px] bg-bazaar-950/60 px-2.5 py-1.5 md:px-3 md:py-2 rounded-lg border border-ochre/20">
|
| 793 |
<span class="text-cream font-bold flex items-center gap-2 min-w-0">
|
|
@@ -798,33 +833,65 @@
|
|
| 798 |
</div>
|
| 799 |
`;
|
| 800 |
});
|
| 801 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 802 |
const cardHtml = `
|
| 803 |
-
<div class="order-card rounded-xl md:rounded-2xl p-3 md:p-4 flex flex-col md:flex-row justify-between items-start md:items-center gap-2.5 md:gap-3">
|
| 804 |
<div class="flex-1 space-y-2 w-full min-w-0">
|
| 805 |
<div class="flex items-center justify-between md:justify-start gap-2 md:gap-3 w-full flex-wrap">
|
| 806 |
<span class="badge-table text-[10px] md:text-xs font-bold px-2.5 md:px-3 py-1 rounded-lg flex items-center gap-1.5 flex-shrink-0">
|
| 807 |
<svg class="w-3 h-3 md:w-3.5 md:h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
| 808 |
<path stroke-linecap="round" stroke-linejoin="round" d="M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z"/>
|
| 809 |
</svg>
|
| 810 |
-
میز ${
|
| 811 |
-
</span>
|
| 812 |
-
<span class="text-[9px] md:text-[10px] text-turk-light/70 font-medium flex items-center gap-1 flex-shrink-0">
|
| 813 |
-
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
| 814 |
-
<path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
| 815 |
-
</svg>
|
| 816 |
-
${timeString}
|
| 817 |
</span>
|
|
|
|
|
|
|
| 818 |
</div>
|
| 819 |
<div class="grid grid-cols-1 sm:grid-cols-2 gap-1 md:gap-1.5 mt-1.5 md:mt-2">
|
| 820 |
${itemsHtml}
|
| 821 |
</div>
|
| 822 |
</div>
|
| 823 |
-
<button onclick=
|
| 824 |
<svg class="w-3.5 h-3.5 md:w-4 md:h-4 transition-transform group-hover:scale-110" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
| 825 |
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
|
| 826 |
</svg>
|
| 827 |
-
تحویل نهایی شد
|
| 828 |
</button>
|
| 829 |
</div>
|
| 830 |
`;
|
|
@@ -838,18 +905,35 @@
|
|
| 838 |
}
|
| 839 |
}
|
| 840 |
|
| 841 |
-
|
|
|
|
|
|
|
| 842 |
try {
|
| 843 |
-
|
| 844 |
-
|
| 845 |
-
|
| 846 |
-
|
| 847 |
-
|
| 848 |
-
|
| 849 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 850 |
fetchActiveOrders();
|
| 851 |
} else {
|
| 852 |
-
alert(
|
|
|
|
| 853 |
}
|
| 854 |
} catch (err) {
|
| 855 |
alert("خطای شبکه: " + err.message);
|
|
@@ -1219,7 +1303,6 @@
|
|
| 1219 |
}
|
| 1220 |
|
| 1221 |
container.insertAdjacentHTML('beforeend', html);
|
| 1222 |
-
// Always scroll to bottom after adding message
|
| 1223 |
scrollChatToBottom(true);
|
| 1224 |
return bubbleId;
|
| 1225 |
}
|
|
|
|
| 121 |
|
| 122 |
.arch-shape { border-radius: 50% 50% 1rem 1rem / 35% 35% 1rem 1rem; }
|
| 123 |
|
|
|
|
| 124 |
.chat-markdown { line-height: 1.85; word-wrap: break-word; overflow-wrap: break-word; }
|
| 125 |
.chat-markdown > * + * { margin-top: 0.6em; }
|
| 126 |
.chat-markdown h1, .chat-markdown h2, .chat-markdown h3,
|
|
|
|
| 188 |
.chat-markdown tr:last-child td { border-bottom: none; }
|
| 189 |
.chat-markdown img { max-width: 100%; border-radius: 10px; border: 2px solid rgba(201, 169, 97, 0.3); }
|
| 190 |
|
|
|
|
| 191 |
.typing-dots span {
|
| 192 |
display: inline-block; width: 6px; height: 6px;
|
| 193 |
border-radius: 50%; background: #c9a961;
|
|
|
|
| 200 |
30% { transform: translateY(-8px); opacity: 1; }
|
| 201 |
}
|
| 202 |
|
|
|
|
| 203 |
.btn-primary {
|
| 204 |
background: linear-gradient(135deg, #c9a961 0%, #9c7d3a 100%);
|
| 205 |
color: #1a0d07; font-weight: 800;
|
|
|
|
| 237 |
transform: translateY(-1px);
|
| 238 |
}
|
| 239 |
|
|
|
|
| 240 |
.drop-zone {
|
| 241 |
position: relative;
|
| 242 |
border: 2px dashed rgba(201, 169, 97, 0.3);
|
|
|
|
| 255 |
pointer-events: none;
|
| 256 |
}
|
| 257 |
|
| 258 |
+
/* کارت سفارش - با افکت ویژه برای سفارشات چندگانه */
|
| 259 |
.order-card {
|
| 260 |
background: linear-gradient(135deg, rgba(45, 24, 16, 0.6), rgba(26, 13, 7, 0.5));
|
| 261 |
border: 1px solid rgba(201, 169, 97, 0.2);
|
|
|
|
| 266 |
box-shadow: 0 12px 30px -10px rgba(139, 30, 63, 0.3);
|
| 267 |
transform: translateY(-2px);
|
| 268 |
}
|
| 269 |
+
.order-card.multi-order {
|
| 270 |
+
border: 1px solid rgba(194, 61, 95, 0.5);
|
| 271 |
+
background: linear-gradient(135deg, rgba(90, 16, 40, 0.25), rgba(26, 13, 7, 0.5));
|
| 272 |
+
}
|
| 273 |
+
.order-card.multi-order::before {
|
| 274 |
+
content: '';
|
| 275 |
+
position: absolute;
|
| 276 |
+
top: -1px; left: -1px; right: -1px; bottom: -1px;
|
| 277 |
+
border-radius: inherit;
|
| 278 |
+
background: linear-gradient(135deg, rgba(201, 169, 97, 0.3), transparent);
|
| 279 |
+
z-index: -1;
|
| 280 |
+
pointer-events: none;
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
/* Badge برای تعداد سفارشها */
|
| 284 |
+
.orders-count-badge {
|
| 285 |
+
background: linear-gradient(135deg, #8b1e3f, #5a1028);
|
| 286 |
+
color: #f5e6d3;
|
| 287 |
+
border: 1px solid rgba(201, 169, 97, 0.5);
|
| 288 |
+
font-family: 'Lalezar', serif;
|
| 289 |
+
animation: pulseGlow 2s ease-in-out infinite;
|
| 290 |
+
}
|
| 291 |
|
| 292 |
.menu-row { transition: all 0.3s ease; }
|
| 293 |
.menu-row:hover { background: rgba(201, 169, 97, 0.05); }
|
|
|
|
| 298 |
box-shadow: 0 0 0 3px rgba(201, 169, 97, 0.15);
|
| 299 |
}
|
| 300 |
|
|
|
|
| 301 |
input[type="checkbox"] {
|
| 302 |
appearance: none; width: 18px; height: 18px;
|
| 303 |
border: 2px solid rgba(201, 169, 97, 0.4);
|
|
|
|
| 359 |
|
| 360 |
button, .no-select { -webkit-user-select: none; user-select: none; }
|
| 361 |
|
|
|
|
| 362 |
.app-wrapper {
|
| 363 |
display: flex;
|
| 364 |
flex-direction: column;
|
|
|
|
| 367 |
overflow: hidden;
|
| 368 |
}
|
| 369 |
|
|
|
|
|
|
|
| 370 |
.chat-column {
|
| 371 |
display: flex;
|
| 372 |
flex-direction: column;
|
|
|
|
| 389 |
flex-shrink: 0;
|
| 390 |
}
|
| 391 |
|
|
|
|
| 392 |
@media (min-width: 1024px) {
|
| 393 |
.main-grid {
|
| 394 |
overflow: hidden !important;
|
|
|
|
| 405 |
}
|
| 406 |
}
|
| 407 |
|
|
|
|
| 408 |
@media (max-width: 1023px) {
|
| 409 |
.main-grid {
|
| 410 |
overflow-y: auto;
|
| 411 |
overflow-x: hidden;
|
| 412 |
}
|
| 413 |
.chat-column {
|
|
|
|
| 414 |
height: 65vh;
|
| 415 |
height: calc(var(--vh, 1vh) * 65);
|
| 416 |
min-height: 380px;
|
|
|
|
| 419 |
}
|
| 420 |
}
|
| 421 |
|
|
|
|
| 422 |
@media (max-width: 480px) {
|
| 423 |
.chat-column {
|
| 424 |
height: 60vh;
|
|
|
|
| 428 |
}
|
| 429 |
}
|
| 430 |
|
|
|
|
| 431 |
@media (max-height: 500px) and (orientation: landscape) {
|
| 432 |
.chat-column {
|
| 433 |
height: 75vh !important;
|
|
|
|
| 435 |
}
|
| 436 |
}
|
| 437 |
|
|
|
|
| 438 |
@media (min-width: 768px) and (max-width: 1023px) {
|
| 439 |
.chat-column {
|
| 440 |
height: 70vh;
|
|
|
|
| 494 |
<!-- Main grid -->
|
| 495 |
<main class="main-grid flex-1 min-h-0 w-full mx-auto p-3 md:p-5 lg:p-6 grid grid-cols-1 lg:grid-cols-12 gap-3 md:gap-5 lg:gap-6 z-10 relative max-w-7xl">
|
| 496 |
|
| 497 |
+
<!-- Right column -->
|
| 498 |
<section class="left-column lg:col-span-7 flex flex-col gap-3 md:gap-5 lg:gap-6 min-h-0">
|
| 499 |
|
| 500 |
<!-- Live orders -->
|
|
|
|
| 513 |
سفارشات جدید آشپزخانه
|
| 514 |
<span class="w-2 h-2 rounded-full bg-rug-light animate-pulse flex-shrink-0"></span>
|
| 515 |
</h2>
|
| 516 |
+
<p class="text-[9px] md:text-[10px] text-cream/50 mt-0.5 truncate">گروهبندی شده بر اساس میز (ادغام خودکار)</p>
|
| 517 |
</div>
|
| 518 |
</div>
|
| 519 |
<button onclick="fetchActiveOrders()" class="btn-ghost text-[9px] md:text-[10px] flex items-center gap-1 px-2 md:px-3 py-1.5 rounded-lg md:rounded-xl flex-shrink-0">
|
|
|
|
| 657 |
<div class="chat-column glass-card-azure rounded-2xl md:rounded-3xl shadow-xl relative">
|
| 658 |
<div class="absolute inset-0 bg-arch opacity-15 pointer-events-none"></div>
|
| 659 |
|
|
|
|
| 660 |
<div class="chat-header-box relative px-3.5 md:px-5 py-2.5 md:py-3 border-b border-turk/25 flex items-center gap-2.5 bg-gradient-to-l from-azure-950/60 to-azure-900/40">
|
| 661 |
<div class="w-9 h-9 md:w-10 md:h-10 rounded-xl bg-gradient-to-br from-turk/30 to-azure-700/30 border border-turk/40 flex items-center justify-center shadow-mosque flex-shrink-0">
|
| 662 |
<svg class="w-5 h-5 md:w-6 md:h-6 text-turk-glow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
|
|
|
|
| 673 |
</div>
|
| 674 |
</div>
|
| 675 |
|
|
|
|
| 676 |
<div id="chatMessages" class="chat-messages-container p-3 md:p-4 space-y-3 relative">
|
| 677 |
<div class="flex gap-2 md:gap-2.5 max-w-[88%]">
|
| 678 |
<div class="w-7 h-7 md:w-8 md:h-8 rounded-xl bg-gradient-to-br from-turk/20 to-azure-700/20 border border-turk/30 flex items-center justify-center flex-shrink-0">
|
|
|
|
| 684 |
</div>
|
| 685 |
</div>
|
| 686 |
|
|
|
|
| 687 |
<div id="chatLoader" class="chat-loader-box hidden relative px-3 py-2 md:px-4 md:py-2.5 flex items-center justify-between bg-azure-950/70 text-[9px] md:text-[10px] text-turk-light font-semibold border-t border-turk/20">
|
| 688 |
<div class="flex items-center gap-2">
|
| 689 |
<div class="typing-dots flex gap-1">
|
|
|
|
| 696 |
</button>
|
| 697 |
</div>
|
| 698 |
|
|
|
|
| 699 |
<form id="chatForm" onsubmit="sendAdminMessage(event)" class="chat-input-box relative p-2 md:p-3 border-t border-turk/20 bg-bazaar-950/60 flex gap-2 safe-bottom">
|
| 700 |
<input type="text" id="chatInput" placeholder="تغییر وضعیت یا ویرایش منو..." autocomplete="off"
|
| 701 |
class="flex-1 min-w-0 bg-azure-950/60 border border-azure-700/40 text-xs md:text-sm text-cream placeholder-ochre/40 rounded-lg md:rounded-xl px-3 md:px-4 py-2 md:py-3 focus:outline-none focus:border-ochre/60 transition-all duration-300">
|
|
|
|
| 709 |
</section>
|
| 710 |
</main>
|
| 711 |
|
|
|
|
| 712 |
<footer class="flex-shrink-0 border-t border-ochre/15 py-2.5 md:py-3 text-center text-[9px] md:text-[10px] text-cream/40 bg-bazaar-950/60 backdrop-blur safe-bottom">
|
| 713 |
طراحی و توسعه توسط الگوریتم داده نسترن | با الهام از فرهنگ تبریز © ۲۰۲۶
|
| 714 |
</footer>
|
|
|
|
| 724 |
window.addEventListener('resize', setVh);
|
| 725 |
window.addEventListener('orientationchange', () => setTimeout(setVh, 100));
|
| 726 |
|
|
|
|
| 727 |
function scrollChatToBottom(smooth = true) {
|
| 728 |
const chatScroll = document.getElementById('chatMessages');
|
| 729 |
if (chatScroll) {
|
|
|
|
| 735 |
}
|
| 736 |
}
|
| 737 |
|
|
|
|
| 738 |
window.addEventListener('resize', () => {
|
| 739 |
setVh();
|
| 740 |
setTimeout(scrollChatToBottom, 150);
|
| 741 |
});
|
| 742 |
|
|
|
|
| 743 |
marked.setOptions({ sanitize: true, breaks: true });
|
| 744 |
|
| 745 |
let chatHistory = [
|
|
|
|
| 752 |
fetchActiveOrders();
|
| 753 |
fetchCurrentMenu();
|
| 754 |
setInterval(fetchActiveOrders, 10000);
|
|
|
|
| 755 |
setTimeout(scrollChatToBottom, 100);
|
| 756 |
});
|
| 757 |
|
|
|
|
| 758 |
const chatInput = document.getElementById('chatInput');
|
| 759 |
if (chatInput) {
|
| 760 |
chatInput.addEventListener('focus', () => {
|
|
|
|
| 763 |
});
|
| 764 |
}
|
| 765 |
|
| 766 |
+
// ============ ORDER FUNCTIONS - با ادغام سفارشات هر میز ============
|
| 767 |
async function fetchActiveOrders() {
|
| 768 |
const container = document.getElementById('ordersContainer');
|
| 769 |
try {
|
|
|
|
| 782 |
`;
|
| 783 |
return;
|
| 784 |
}
|
| 785 |
+
|
| 786 |
+
// ✅ گروهبندی سفارشات بر اساس میز
|
| 787 |
+
const tableGroups = {};
|
| 788 |
orders.forEach(order => {
|
| 789 |
+
const tableKey = String(order.table);
|
| 790 |
+
if (!tableGroups[tableKey]) {
|
| 791 |
+
tableGroups[tableKey] = {
|
| 792 |
+
table: order.table,
|
| 793 |
+
orderIds: [],
|
| 794 |
+
items: {}, // name -> {name, quantity}
|
| 795 |
+
timestamps: [],
|
| 796 |
+
totalItemCount: 0
|
| 797 |
+
};
|
| 798 |
+
}
|
| 799 |
+
const group = tableGroups[tableKey];
|
| 800 |
+
group.orderIds.push(order.id);
|
| 801 |
+
group.timestamps.push(order.timestamp);
|
| 802 |
+
group.totalItemCount += order.items.reduce((sum, it) => sum + it.quantity, 0);
|
| 803 |
+
|
| 804 |
+
// ✅ ادغام آیتمهای تکراری با جمع تعداد
|
| 805 |
order.items.forEach(item => {
|
| 806 |
+
if (group.items[item.name]) {
|
| 807 |
+
group.items[item.name].quantity += item.quantity;
|
| 808 |
+
} else {
|
| 809 |
+
group.items[item.name] = { name: item.name, quantity: item.quantity };
|
| 810 |
+
}
|
| 811 |
+
});
|
| 812 |
+
});
|
| 813 |
+
|
| 814 |
+
container.innerHTML = '';
|
| 815 |
+
// مرتبسازی بر اساس جدیدترین timestamp هر گروه
|
| 816 |
+
const sortedGroups = Object.values(tableGroups).sort((a, b) => {
|
| 817 |
+
const aMax = Math.max(...a.timestamps);
|
| 818 |
+
const bMax = Math.max(...b.timestamps);
|
| 819 |
+
return bMax - aMax;
|
| 820 |
+
});
|
| 821 |
+
|
| 822 |
+
sortedGroups.forEach(group => {
|
| 823 |
+
const itemsArray = Object.values(group.items);
|
| 824 |
+
let itemsHtml = '';
|
| 825 |
+
itemsArray.forEach(item => {
|
| 826 |
itemsHtml += `
|
| 827 |
<div class="flex items-center justify-between text-[10px] md:text-[11px] bg-bazaar-950/60 px-2.5 py-1.5 md:px-3 md:py-2 rounded-lg border border-ochre/20">
|
| 828 |
<span class="text-cream font-bold flex items-center gap-2 min-w-0">
|
|
|
|
| 833 |
</div>
|
| 834 |
`;
|
| 835 |
});
|
| 836 |
+
|
| 837 |
+
// محاسبه زمانها
|
| 838 |
+
const firstTime = new Date(Math.min(...group.timestamps) * 1000).toLocaleTimeString('fa-IR', { hour: '2-digit', minute: '2-digit' });
|
| 839 |
+
const lastTime = new Date(Math.max(...group.timestamps) * 1000).toLocaleTimeString('fa-IR', { hour: '2-digit', minute: '2-digit' });
|
| 840 |
+
const orderCount = group.orderIds.length;
|
| 841 |
+
const isMulti = orderCount > 1;
|
| 842 |
+
|
| 843 |
+
// نمایش زمان
|
| 844 |
+
let timeDisplay = '';
|
| 845 |
+
if (isMulti) {
|
| 846 |
+
timeDisplay = `<span class="text-[9px] md:text-[10px] text-turk-light/70 font-medium flex items-center gap-1 flex-shrink-0">
|
| 847 |
+
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
| 848 |
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
| 849 |
+
</svg>
|
| 850 |
+
${firstTime} → ${lastTime}
|
| 851 |
+
</span>`;
|
| 852 |
+
} else {
|
| 853 |
+
timeDisplay = `<span class="text-[9px] md:text-[10px] text-turk-light/70 font-medium flex items-center gap-1 flex-shrink-0">
|
| 854 |
+
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
| 855 |
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
| 856 |
+
</svg>
|
| 857 |
+
${lastTime}
|
| 858 |
+
</span>`;
|
| 859 |
+
}
|
| 860 |
+
|
| 861 |
+
// Badge برای سفارشات چندگانه
|
| 862 |
+
const multiBadge = isMulti ? `
|
| 863 |
+
<span class="orders-count-badge text-[10px] md:text-[11px] px-2 py-0.5 rounded-md flex items-center gap-1 flex-shrink-0">
|
| 864 |
+
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
| 865 |
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4"/>
|
| 866 |
+
</svg>
|
| 867 |
+
${orderCount} سفارش
|
| 868 |
+
</span>
|
| 869 |
+
` : '';
|
| 870 |
+
|
| 871 |
+
const orderIdsJson = JSON.stringify(group.orderIds).replace(/"/g, '"');
|
| 872 |
+
|
| 873 |
const cardHtml = `
|
| 874 |
+
<div class="order-card ${isMulti ? 'multi-order' : ''} relative rounded-xl md:rounded-2xl p-3 md:p-4 flex flex-col md:flex-row justify-between items-start md:items-center gap-2.5 md:gap-3">
|
| 875 |
<div class="flex-1 space-y-2 w-full min-w-0">
|
| 876 |
<div class="flex items-center justify-between md:justify-start gap-2 md:gap-3 w-full flex-wrap">
|
| 877 |
<span class="badge-table text-[10px] md:text-xs font-bold px-2.5 md:px-3 py-1 rounded-lg flex items-center gap-1.5 flex-shrink-0">
|
| 878 |
<svg class="w-3 h-3 md:w-3.5 md:h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
| 879 |
<path stroke-linecap="round" stroke-linejoin="round" d="M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z"/>
|
| 880 |
</svg>
|
| 881 |
+
میز ${group.table}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 882 |
</span>
|
| 883 |
+
${multiBadge}
|
| 884 |
+
${timeDisplay}
|
| 885 |
</div>
|
| 886 |
<div class="grid grid-cols-1 sm:grid-cols-2 gap-1 md:gap-1.5 mt-1.5 md:mt-2">
|
| 887 |
${itemsHtml}
|
| 888 |
</div>
|
| 889 |
</div>
|
| 890 |
+
<button onclick='completeOrdersForTable(${orderIdsJson})' class="w-full md:w-auto btn-ghost hover:bg-emerald-dark/40 hover:border-emerald-light/50 hover:text-emerald-light px-3 md:px-4 py-2 md:py-2.5 rounded-lg md:rounded-xl text-[9px] md:text-[10px] font-bold flex items-center justify-center gap-1.5 flex-shrink-0 group">
|
| 891 |
<svg class="w-3.5 h-3.5 md:w-4 md:h-4 transition-transform group-hover:scale-110" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
| 892 |
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
|
| 893 |
</svg>
|
| 894 |
+
تحویل نهایی ${isMulti ? `(${orderCount} سفارش)` : 'شد'}
|
| 895 |
</button>
|
| 896 |
</div>
|
| 897 |
`;
|
|
|
|
| 905 |
}
|
| 906 |
}
|
| 907 |
|
| 908 |
+
// ✅ تکمیل همه سفارشهای یک میز (چندگانه)
|
| 909 |
+
async function completeOrdersForTable(orderIds) {
|
| 910 |
+
if (!Array.isArray(orderIds) || orderIds.length === 0) return;
|
| 911 |
try {
|
| 912 |
+
// انجام sequential همه درخواستها
|
| 913 |
+
let successCount = 0;
|
| 914 |
+
let failCount = 0;
|
| 915 |
+
for (const orderId of orderIds) {
|
| 916 |
+
try {
|
| 917 |
+
const response = await fetch('/api/admin/complete_order', {
|
| 918 |
+
method: 'POST',
|
| 919 |
+
headers: { 'Content-Type': 'application/json' },
|
| 920 |
+
body: JSON.stringify({ order_id: orderId })
|
| 921 |
+
});
|
| 922 |
+
const result = await response.json();
|
| 923 |
+
if (response.ok && result.success) {
|
| 924 |
+
successCount++;
|
| 925 |
+
} else {
|
| 926 |
+
failCount++;
|
| 927 |
+
}
|
| 928 |
+
} catch (e) {
|
| 929 |
+
failCount++;
|
| 930 |
+
}
|
| 931 |
+
}
|
| 932 |
+
if (failCount === 0) {
|
| 933 |
fetchActiveOrders();
|
| 934 |
} else {
|
| 935 |
+
alert(`${successCount} سفارش تکمیل شد. ${failCount} خطا رخ داد.`);
|
| 936 |
+
fetchActiveOrders();
|
| 937 |
}
|
| 938 |
} catch (err) {
|
| 939 |
alert("خطای شبکه: " + err.message);
|
|
|
|
| 1303 |
}
|
| 1304 |
|
| 1305 |
container.insertAdjacentHTML('beforeend', html);
|
|
|
|
| 1306 |
scrollChatToBottom(true);
|
| 1307 |
return bubbleId;
|
| 1308 |
}
|