humanvprojectceo commited on
Commit
8e11847
·
verified ·
1 Parent(s): 15c0e5a

Update cafe.html

Browse files
Files changed (1) hide show
  1. cafe.html +215 -171
cafe.html CHANGED
@@ -3,12 +3,12 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Cafe AI - پنل مدیریت کافه</title>
7
- <!-- لود واژه‌نامه و فوت فارسی زیبا -->
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
  <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;700&display=swap" rel="stylesheet">
11
- <!-- لود کتابخانه Tailwind CSS برای استایل‌دهی مدرن -->
12
  <script src="https://cdn.tailwindcss.com"></script>
13
  <script>
14
  tailwind.config = {
@@ -18,12 +18,12 @@
18
  sans: ['Vazirmatn', 'sans-serif'],
19
  },
20
  colors: {
21
- cafeDark: '#09090b', /* مشکی بسیار تیره */
22
  cafeCard: '#18181b', /* خاکستری تیره برای کارت‌ها */
23
- cafeBorder: '#27272a', /* رنگ حاشیه‌ها */
24
- cafeGold: '#d4af37', /* رنگ طلایی شاخص */
25
- cafeGoldHover: '#f3cd5c', /* طلایی روشن‌تر */
26
- cafeAccent: '#f59e0b' /* کهربایی */
27
  }
28
  }
29
  }
@@ -34,29 +34,26 @@
34
  background-color: #09090b;
35
  color: #f4f4f5;
36
  }
37
- /* کاستومایز کردن اسکرول‌بار برای هماهنگی با تم تاریک */
38
  ::-webkit-scrollbar {
39
- width: 6px;
40
  }
41
  ::-webkit-scrollbar-track {
42
  background: #18181b;
43
  }
44
  ::-webkit-scrollbar-thumb {
45
  background: #3f3f46;
46
- border-radius: 3px;
47
- }
48
- ::-webkit-scrollbar-thumb:hover {
49
- background: #52525b;
50
  }
51
  </style>
52
  </head>
53
- <body class="min-h-screen flex flex-col font-sans selection:bg-amber-500 selection:text-black">
54
 
55
- <!-- هدر اصلی پنل مدیریت -->
56
- <header class="border-b border-cafeBorder bg-cafeCard/80 backdrop-blur sticky top-0 z-50 px-4 py-3 md:px-8">
57
  <div class="max-w-7xl mx-auto flex items-center justify-between">
58
  <div class="flex items-center gap-3">
59
- <!-- لوگوی اختصاصی فنجان قهوه هوشمند (SVG) -->
60
  <svg class="w-8 h-8 text-cafeGold" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
61
  <path d="M17 8h1a4 4 0 1 1 0 8h-1" />
62
  <path d="M3 8h14v9a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4Z" />
@@ -65,119 +62,118 @@
65
  <line x1="14" y1="2" x2="14" y2="4" />
66
  </svg>
67
  <div>
68
- <h1 class="text-lg font-bold tracking-wide text-white flex items-center gap-2">
69
- پنل مدیریت <span class="text-cafeGold">Cafe AI</span>
70
  </h1>
71
- <p class="text-[10px] text-zinc-400">سیستم نظارت بر سفارشات و هوش مصنوعی نیلا</p>
72
  </div>
73
  </div>
74
 
75
- <div class="flex items-center gap-4">
76
- <span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
77
- <span class="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-pulse"></span>
78
- سیستم فعال است
79
  </span>
80
  </div>
81
  </div>
82
  </header>
83
 
84
- <!-- بدنه اصلی چیدمان دو ستونه -->
85
  <main class="flex-1 max-w-7xl w-full mx-auto p-4 md:p-6 lg:p-8 grid grid-cols-1 lg:grid-cols-12 gap-6">
86
 
87
- <!-- ستون سمت راست: مدیریت سفارشات فعال و بارگذاری منو (عرض: ۷ از ۱۲) -->
88
  <section class="lg:col-span-7 flex flex-col gap-6">
89
 
90
- <!-- بخش سفارش‌های زنده -->
91
- <div class="bg-cafeCard border border-cafeBorder rounded-xl p-5 shadow-2xl">
92
  <div class="flex items-center justify-between mb-4 border-b border-cafeBorder pb-3">
93
- <h2 class="text-base font-bold text-white flex items-center gap-2">
94
  <svg class="w-5 h-5 text-cafeGold" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
95
  <path stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01" />
96
  </svg>
97
- سفارشات جاری آشپزخانه
98
  </h2>
99
- <button onclick="fetchActiveOrders()" class="text-xs text-zinc-400 hover:text-cafeGold flex items-center gap-1 transition-all">
100
- <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
101
  <path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 1121.21 15H15" />
102
  </svg>
103
- بروزرسانی دستی
104
  </button>
105
  </div>
106
 
107
- <!-- لیست سفارشات -->
108
- <div id="ordersContainer" class="space-y-4 max-h-[400px] overflow-y-auto pr-1">
109
- <!-- حالت بارگذاری اولیه یا خالی بودن -->
110
- <div class="text-center py-12 text-zinc-500">
111
- در حال بارگذاری سفارشات جاری...
112
  </div>
113
  </div>
114
  </div>
115
 
116
- <!-- بخش بارگذاری و استخراج منو -->
117
- <div class="bg-cafeCard border border-cafeBorder rounded-xl p-5 shadow-2xl">
118
- <h2 class="text-base font-bold text-white mb-4 flex items-center gap-2 border-b border-cafeBorder pb-3">
119
  <svg class="w-5 h-5 text-cafeGold" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
120
  <path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
121
  </svg>
122
- بارگذاری و به‌روزرسانی هوشمند منو
123
  </h2>
124
 
125
- <p class="text-xs text-zinc-400 mb-4 leading-relaxed">
126
- تصویر منو یا فایل لیست قیمت‌ها را آپلود کنید. دستیار هوشمند نیلا، آیتم‌ها، قیمت‌ها و توضیحات را استخراج کرده و جهت تایید نهایی به شما نمایش میدهد.
127
  </p>
128
 
129
- <!-- باکس آپلود فایل -->
130
- <div class="border-2 border-dashed border-cafeBorder hover:border-cafeGold/50 rounded-lg p-6 text-center cursor-pointer transition-all bg-cafeDark/30" onclick="document.getElementById('menuFileInput').click()">
131
  <input type="file" id="menuFileInput" class="hidden" accept="image/*,application/pdf" onchange="uploadMenuFile(event)">
132
- <div class="flex flex-col items-center gap-2">
133
- <svg class="w-8 h-8 text-zinc-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
134
  <path stroke-linecap="round" stroke-linejoin="round" d="M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z" />
135
  </svg>
136
- <span class="text-sm text-zinc-300">انتخاب تصویر منو یا فایل متنی</span>
137
- <span class="text-[10px] text-zinc-500">فرمت‌های مجاز: تصاویر (PNG, JPG) یا PDF</span>
138
  </div>
139
  </div>
140
 
141
- <!-- اسپینر در حال بارگذاری تحلیل مدل -->
142
- <div id="uploadLoader" class="hidden mt-4 text-center py-6 bg-cafeDark/50 rounded-lg border border-cafeBorder">
143
- <div class="inline-block animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-cafeGold mb-2"></div>
144
- <p class="text-xs text-cafeGold">نیلا در حال پردازش سند و استخراج ساختار منو است. لطفاً شکیبا باشید...</p>
145
  </div>
146
 
147
- <!-- ویرایشگر منوی استخراج شده -->
148
- <div id="menuEditorContainer" class="hidden mt-6 space-y-4 border-t border-cafeBorder pt-4">
149
- <h3 class="text-sm font-bold text-white flex items-center gap-2 text-amber-400">
150
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
151
  <path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
152
  </svg>
153
- بازبینی و ویرایش منوی پیشنهادی هوش مصنوعی
154
  </h3>
155
 
156
- <div class="overflow-x-auto max-h-[300px] border border-cafeBorder rounded-lg">
157
- <table class="min-w-full divide-y divide-cafeBorder bg-cafeDark/40 text-xs">
158
  <thead class="bg-cafeCard">
159
  <tr>
160
- <th class="px-3 py-2 text-right font-medium text-zinc-400">نام آیتم</th>
161
- <th class="px-3 py-2 text-right font-medium text-zinc-400">توضیحات/ترکیبات</th>
162
  <th class="px-3 py-2 text-right font-medium text-zinc-400 w-24">قیمت (تومان)</th>
163
- <th class="px-3 py-2 text-center font-medium text-zinc-400 w-16">عملیات</th>
164
  </tr>
165
  </thead>
166
  <tbody id="menuEditorTableBody" class="divide-y divide-cafeBorder">
167
- <!-- سطرها داینامیک اضافه میشن -->
168
  </tbody>
169
  </table>
170
  </div>
171
 
172
  <div class="flex justify-end gap-2">
173
- <button onclick="addEmptyMenuRow()" class="px-3 py-1.5 border border-cafeBorder hover:border-zinc-500 rounded text-xs text-zinc-300 transition-all">
174
- افزودن سطر جدید
175
  </button>
176
- <button onclick="saveAndPublishMenu()" class="px-4 py-1.5 bg-emerald-600 hover:bg-emerald-500 rounded text-xs font-bold text-white transition-all flex items-center gap-1.5">
177
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
178
  <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
179
  </svg>
180
- تایید نهایی و به‌روزرسانی زنده منو
181
  </button>
182
  </div>
183
  </div>
@@ -185,13 +181,12 @@
185
  </div>
186
  </section>
187
 
188
- <!-- ستون سمت چپ: چت همکار (ادمین) با نیلا (عرض: ۵ از ۱۲) -->
189
- <section class="lg:col-span-5 flex flex-col bg-cafeCard border border-cafeBorder rounded-xl shadow-2xl h-[650px] overflow-hidden">
190
 
191
- <!-- سربرگ چت -->
192
- <div class="px-5 py-4 border-b border-cafeBorder flex items-center justify-between bg-cafeDark/30">
193
  <div class="flex items-center gap-3">
194
- <!-- آواتار هوش مصنوعی نیلا مخصوص ادمین -->
195
  <div class="w-9 h-9 rounded-full bg-cafeGold/10 border border-cafeGold/30 flex items-center justify-center">
196
  <svg class="w-5 h-5 text-cafeGold" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
197
  <path d="M12 2a10 10 0 0 1 10 10c0 5.523-4.477 10-10 10S2 17.523 2 12A10 10 0 0 1 12 2z"/>
@@ -199,13 +194,13 @@
199
  </svg>
200
  </div>
201
  <div>
202
- <h3 class="text-sm font-bold text-white">دستیار هوشمند کافه (Nila)</h3>
203
- <p class="text-[9px] text-emerald-400">اتصال پایدار با مدل gemini-3.1-flash-lite</p>
204
  </div>
205
  </div>
206
  </div>
207
 
208
- <!-- بدنه پیام‌های چت -->
209
  <div id="chatMessages" class="flex-1 overflow-y-auto p-4 space-y-4">
210
  <!-- پیام خوش آمدگویی پیش‌فرض -->
211
  <div class="flex gap-2.5 max-w-[85%]">
@@ -215,26 +210,32 @@
215
  <path d="M12 8v4l3 3"/>
216
  </svg>
217
  </div>
218
- <div class="bg-cafeDark/60 border border-cafeBorder text-zinc-200 text-xs rounded-2xl rounded-tr-none px-3.5 py-2.5 leading-relaxed">
219
- سلام همکار گرامی! من نیلا هستم، دستیار هوشمند شما. می‌توانید از همین‌جا با من گفتگو کنید و مواردی مثل ناموجود کردن آیتم‌ها (مثلا: "کیک شکلاتی تموم شد") یا فعال‌سازی مجدد آن‌ها را اعلام کنید تا بلافاصله روی سیستم و منوی مشتریان اعمال کنم.
220
  </div>
221
  </div>
222
  </div>
223
 
224
- <!-- لودر تایپ هوش مصنوعی -->
225
- <div id="chatLoader" class="hidden px-4 py-2 flex items-center gap-2 bg-cafeDark/30 text-xs text-zinc-400 border-t border-cafeBorder/50">
226
- <div class="flex space-x-1 space-x-reverse">
227
- <span class="w-1.5 h-1.5 bg-cafeGold rounded-full animate-bounce" style="animation-delay: 0.1s"></span>
228
- <span class="w-1.5 h-1.5 bg-cafeGold rounded-full animate-bounce" style="animation-delay: 0.2s"></span>
229
- <span class="w-1.5 h-1.5 bg-cafeGold rounded-full animate-bounce" style="animation-delay: 0.3s"></span>
 
 
 
230
  </div>
231
- <span>نیلا در حال تفکر...</span>
 
 
 
232
  </div>
233
 
234
- <!-- بخش ورودی پیام چت -->
235
- <form id="chatForm" onsubmit="sendAdminMessage(event)" class="p-3 border-t border-cafeBorder bg-cafeDark/50 flex gap-2">
236
- <input type="text" id="chatInput" placeholder="پیامی برای مدیریت منو بنویسید..." autocomplete="off" class="flex-1 bg-cafeCard border border-cafeBorder text-xs text-zinc-200 placeholder-zinc-500 rounded-lg px-3 py-2.5 focus:outline-none focus:border-cafeGold/60 transition-all">
237
- <button type="submit" class="bg-cafeGold hover:bg-cafeGoldHover text-zinc-950 font-bold px-4 py-2 rounded-lg text-xs transition-all flex items-center justify-center flex-shrink-0">
238
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
239
  <path stroke-linecap="round" stroke-linejoin="round" d="M14 5l7 7m0 0l-7 7m7-7H3" />
240
  </svg>
@@ -245,26 +246,26 @@
245
 
246
  </main>
247
 
248
- <!-- فوتر پایین پنل -->
249
- <footer class="border-t border-cafeBorder py-4 text-center text-[10px] text-zinc-600 bg-cafeDark">
250
  طراحی و توسعه توسط الگوریتم داده نسترن | کلیه حقوق محفوظ است © ۲۰۲۶
251
  </footer>
252
 
253
- <!-- منطق جاوا اسکریپت و پردازش‌های API -->
254
  <script>
255
- // آرشیو پیام‌های چت جاری با نیلا
256
  let chatHistory = [
257
- { role: 'model', content: 'سلام همکار گرامی! من نیلا هستم، دستیار هوشمند شما در مدیریت کافه AI. چطور میتونم کمکتون کنم؟' }
258
  ];
 
 
259
 
260
- // پس از لود شدن کامل صفحه کارهای اولیه را انجام می‌دهیم
261
  window.addEventListener('DOMContentLoaded', () => {
262
  fetchActiveOrders();
263
- // بروزرسانی خودکار سفارشات هر ۱۰ ثانیه
264
  setInterval(fetchActiveOrders, 10000);
265
  });
266
 
267
- // --- مدیریت سفارشات جاری ---
268
 
269
  async function fetchActiveOrders() {
270
  const container = document.getElementById('ordersContainer');
@@ -275,11 +276,11 @@
275
  if (response.ok) {
276
  if (orders.length === 0) {
277
  container.innerHTML = `
278
- <div class="text-center py-16 text-zinc-500 border border-dashed border-cafeBorder rounded-xl bg-cafeDark/20">
279
- <svg class="w-10 h-10 text-zinc-600 mx-auto mb-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
280
  <path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
281
  </svg>
282
- در حال حاضر هیچ سفارش معلق و فعالی ثبت نشده است.
283
  </div>
284
  `;
285
  return;
@@ -287,46 +288,44 @@
287
 
288
  container.innerHTML = '';
289
  orders.forEach(order => {
290
- // تولید آیتم‌های لیست سفارش
291
  let itemsHtml = '';
292
  order.items.forEach(item => {
293
  itemsHtml += `
294
- <div class="flex items-center justify-between text-xs bg-cafeDark/50 px-3 py-2 rounded border border-cafeBorder/40">
295
- <span class="text-zinc-200 font-bold">${item.name}</span>
296
- <span class="text-cafeGold bg-cafeGold/10 px-2 py-0.5 rounded-full font-bold">تعداد: ${item.quantity}</span>
297
  </div>
298
  `;
299
  });
300
 
301
- // تبدیل زمان ثبت شده یونیکس به ساعت محلی ساده
302
- const orderTime = new Date(order.timestamp * 1000).toLocaleTimeString('fa-IR', { hour: '2-digit', minute: '2-digit' });
303
 
304
  const cardHtml = `
305
- <div class="border border-cafeBorder hover:border-amber-500/30 rounded-xl p-4 bg-cafeDark/40 transition-all flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
306
- <div class="flex-1 space-y-2">
307
- <div class="flex items-center gap-3">
308
- <span class="text-sm font-bold text-white bg-cafeGold/10 border border-cafeGold/30 px-3 py-1 rounded-lg">میز ${order.table}</span>
309
- <span class="text-[10px] text-zinc-500">ساعت ثبت سفارش: ${orderTime}</span>
310
  </div>
311
- <div class="grid grid-cols-1 sm:grid-cols-2 gap-2 mt-2">
312
  ${itemsHtml}
313
  </div>
314
  </div>
315
- <button onclick="completeOrder(${order.id})" class="w-full md:w-auto px-4 py-2.5 bg-zinc-800 hover:bg-emerald-700 text-zinc-200 hover:text-white rounded-lg text-xs font-bold transition-all flex items-center justify-center gap-2 border border-zinc-700 hover:border-emerald-600 flex-shrink-0 group">
316
- <svg class="w-4 h-4 text-zinc-400 group-hover:text-white transition-colors" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
317
  <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
318
  </svg>
319
- آماده و تحویل داده شد
320
  </button>
321
  </div>
322
  `;
323
  container.insertAdjacentHTML('beforeend', cardHtml);
324
  });
325
  } else {
326
- container.innerHTML = `<div class="text-center py-6 text-rose-500 text-xs">بروز خطا در بازیابی اطلاعات سفارشات از سرور.</div>`;
327
  }
328
  } catch (err) {
329
- container.innerHTML = `<div class="text-center py-6 text-rose-500 text-xs">خطای اتصال به سرور: ${err.message}</div>`;
330
  }
331
  }
332
 
@@ -340,64 +339,110 @@
340
 
341
  const result = await response.json();
342
  if (response.ok && result.success) {
343
- // بروزرسانی آنی لیست پس از ثبت اتمام سفارش
344
  fetchActiveOrders();
345
  } else {
346
- alert(result.error || "خطایی در تغییر وضعیت سفارش رخ داد.");
347
  }
348
  } catch (err) {
349
- alert("خطای شبکه: " + err.message);
350
  }
351
  }
352
 
353
 
354
- // --- چت ادمین با هوش مصنوعی نیلا ---
355
 
356
  async function sendAdminMessage(e) {
357
  e.preventDefault();
 
 
358
  const input = document.getElementById('chatInput');
359
- const messageText = input.value.trim();
360
- if (!messageText) return;
361
 
362
- // نمایش پیام ادمین در صفحه چت
363
- appendChatMessage('user', messageText);
364
  input.value = '';
365
 
366
- // افزودن به سوابق گفتگو جهت ارسال به مدل
367
- chatHistory.push({ role: 'user', content: messageText });
368
 
369
- // نمایش افکت در حال تفکر نیلا
370
- const loader = document.getElementById('chatLoader');
371
- loader.classList.remove('hidden');
 
372
 
373
  try {
374
  const response = await fetch('/api/admin/chat', {
375
  method: 'POST',
376
  headers: { 'Content-Type': 'application/json' },
377
- body: JSON.stringify({ messages: chatHistory })
 
378
  });
379
 
380
  const data = await response.json();
381
- loader.classList.add('hidden');
 
382
 
383
  if (response.ok && data.success) {
384
- appendChatMessage('model', data.response);
385
- chatHistory.push({ role: 'model', content: data.response });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  } else {
387
- appendChatMessage('model', data.error || 'خطایی در تولید پاسخ پیش آمد. لطفاً اتصال سرور و کلید API را ارزیابی نمایید.');
388
  }
389
  } catch (err) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  loader.classList.add('hidden');
391
- appendChatMessage('model', 'خطا در ارتباط با سرور رخ داده است: ' + err.message);
 
392
  }
393
  }
394
 
395
  function appendChatMessage(role, content) {
396
  const container = document.getElementById('chatMessages');
 
397
 
398
- let messageHtml = '';
399
  if (role === 'user') {
400
- messageHtml = `
401
  <div class="flex justify-end gap-2.5 max-w-[85%] mr-auto">
402
  <div class="bg-amber-500/10 border border-amber-500/20 text-zinc-100 text-xs rounded-2xl rounded-tl-none px-3.5 py-2.5 leading-relaxed">
403
  ${content}
@@ -405,7 +450,7 @@
405
  </div>
406
  `;
407
  } else {
408
- messageHtml = `
409
  <div class="flex gap-2.5 max-w-[85%]">
410
  <div class="w-7 h-7 rounded-full bg-cafeGold/10 border border-cafeGold/30 flex items-center justify-center flex-shrink-0">
411
  <svg class="w-4 h-4 text-cafeGold" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@@ -413,30 +458,30 @@
413
  <path d="M12 8v4l3 3"/>
414
  </svg>
415
  </div>
416
- <div class="bg-cafeDark/60 border border-cafeBorder text-zinc-200 text-xs rounded-2xl rounded-tr-none px-3.5 py-2.5 leading-relaxed">
417
  ${content}
418
  </div>
419
  </div>
420
  `;
421
  }
422
 
423
- container.insertAdjacentHTML('beforeend', messageHtml);
424
- // اسکرول اتوماتیک به انتهای چت باکس
425
  container.scrollTop = container.scrollHeight;
 
426
  }
427
 
428
 
429
- // --- بارگذاری تصویر منو و ویرایش هوشمند منو ---
430
 
431
  async function uploadMenuFile(e) {
432
  const file = e.target.files[0];
433
  if (!file) return;
434
 
435
  const loader = document.getElementById('uploadLoader');
436
- const editorContainer = document.getElementById('menuEditorContainer');
437
 
438
  loader.classList.remove('hidden');
439
- editorContainer.classList.add('hidden');
440
 
441
  const formData = new FormData();
442
  formData.append('file', file);
@@ -452,13 +497,13 @@
452
 
453
  if (response.ok && data.success) {
454
  renderMenuEditor(data.extracted_menu);
455
- editorContainer.classList.remove('hidden');
456
  } else {
457
- alert(data.error || 'استخراج منو ناموفق بود.');
458
  }
459
  } catch (err) {
460
  loader.classList.add('hidden');
461
- alert('خطا در بارگذاری فایل: ' + err.message);
462
  }
463
  }
464
 
@@ -468,18 +513,18 @@
468
 
469
  menuItems.forEach((item, index) => {
470
  const row = `
471
- <tr data-index="${index}" class="hover:bg-cafeCard/40">
472
  <td class="px-2 py-2">
473
- <input type="text" class="menu-name w-full bg-cafeCard border border-cafeBorder rounded px-2 py-1 text-zinc-200 focus:border-cafeGold/40 focus:outline-none" value="${item.name || ''}">
474
  </td>
475
  <td class="px-2 py-2">
476
- <input type="text" class="menu-desc w-full bg-cafeCard border border-cafeBorder rounded px-2 py-1 text-zinc-200 focus:border-cafeGold/40 focus:outline-none" value="${item.description || ''}">
477
  </td>
478
  <td class="px-2 py-2">
479
- <input type="text" class="menu-price w-full bg-cafeCard border border-cafeBorder rounded px-2 py-1 text-zinc-200 focus:border-cafeGold/40 focus:outline-none" value="${item.price || ''}">
480
  </td>
481
  <td class="px-2 py-2 text-center">
482
- <button onclick="removeMenuRow(this)" class="p-1 hover:text-rose-500 text-zinc-500 transition-colors">
483
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
484
  <path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
485
  </svg>
@@ -494,18 +539,18 @@
494
  function addEmptyMenuRow() {
495
  const tbody = document.getElementById('menuEditorTableBody');
496
  const row = `
497
- <tr class="hover:bg-cafeCard/40">
498
  <td class="px-2 py-2">
499
- <input type="text" class="menu-name w-full bg-cafeCard border border-cafeBorder rounded px-2 py-1 text-zinc-200 focus:border-cafeGold/40 focus:outline-none" placeholder="مثال: لاته">
500
  </td>
501
  <td class="px-2 py-2">
502
- <input type="text" class="menu-desc w-full bg-cafeCard border border-cafeBorder rounded px-2 py-1 text-zinc-200 focus:border-cafeGold/40 focus:outline-none" placeholder="شیر داغ، قهوه...">
503
  </td>
504
  <td class="px-2 py-2">
505
- <input type="text" class="menu-price w-full bg-cafeCard border border-cafeBorder rounded px-2 py-1 text-zinc-200 focus:border-cafeGold/40 focus:outline-none" placeholder="۷۰,۰۰۰">
506
  </td>
507
  <td class="px-2 py-2 text-center">
508
- <button onclick="removeMenuRow(this)" class="p-1 hover:text-rose-500 text-zinc-500 transition-colors">
509
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
510
  <path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
511
  </svg>
@@ -523,25 +568,25 @@
523
  async function saveAndPublishMenu() {
524
  const tbody = document.getElementById('menuEditorTableBody');
525
  const rows = tbody.querySelectorAll('tr');
526
- const updatedMenu = [];
527
 
528
  rows.forEach(row => {
529
  const name = row.querySelector('.menu-name').value.trim();
530
  const description = row.querySelector('.menu-desc').value.trim();
531
  const price = row.querySelector('.menu-price').value.trim();
532
-
533
  if (name) {
534
- updatedMenu.push({
535
  name: name,
536
  description: description,
537
  price: price,
538
- available: true // به طور پیش‌فرض آیتم‌های جدید را موجود ثبت می‌کنیم
539
  });
540
  }
541
  });
542
 
543
- if (updatedMenu.length === 0) {
544
- alert("امکان انتشار منوی خالی وجود ندارد. حداقل یک سطر با نام معتبر ثبت کنید.");
545
  return;
546
  }
547
 
@@ -549,20 +594,19 @@
549
  const response = await fetch('/api/admin/save_menu', {
550
  method: 'POST',
551
  headers: { 'Content-Type': 'application/json' },
552
- body: JSON.stringify({ menu: updatedMenu })
553
  });
554
 
555
  const data = await response.json();
556
  if (response.ok && data.success) {
557
- alert("منوی جدید ثبت و در لحظه برای تمامی مشتریان و دستیار نیلا فعال شد!");
558
  document.getElementById('menuEditorContainer').classList.add('hidden');
559
- // به نیلا در گفتگو اطلاع می‌دهیم منو تغییر کرده است
560
- appendChatMessage('model', 'منوی جدید سیستم با موفقیت به سیستم مرکزی فرستاده و اعمال شد. از این پس منوی مشتریان را از روی پایگاه‌داده جدید پردازش خواهم کرد.');
561
  } else {
562
- alert(data.error || 'خطا در ثبت منو.');
563
  }
564
  } catch (err) {
565
- alert('خطای ارتباط با سرور: ' + err.message);
566
  }
567
  }
568
  </script>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Cafe AI - پنل پیشرفته مدیریت کافه</title>
7
+ <!-- بارگذاری قلم فارسی وزیر متین -->
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
  <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;700&display=swap" rel="stylesheet">
11
+ <!-- بارگذاری فریمورک سی‌اس‌اس Tailwind برای استایل‌دهی مدرن -->
12
  <script src="https://cdn.tailwindcss.com"></script>
13
  <script>
14
  tailwind.config = {
 
18
  sans: ['Vazirmatn', 'sans-serif'],
19
  },
20
  colors: {
21
+ cafeDark: '#09090b', /* مشکی مطلق برای پس‌زمینه */
22
  cafeCard: '#18181b', /* خاکستری تیره برای کارت‌ها */
23
+ cafeBorder: '#27272a', /* خطوط راهنما */
24
+ cafeGold: '#d4af37', /* طلایی سنتی کافه */
25
+ cafeGoldHover: '#f3cd5c', /* طلایی روشن */
26
+ cafeRed: '#ef4444' /* زنگ خطر و حذف */
27
  }
28
  }
29
  }
 
34
  background-color: #09090b;
35
  color: #f4f4f5;
36
  }
37
+ /* تنظیمات اسکرول‌بار اختصاصی و باریک برای پنل مدیریت */
38
  ::-webkit-scrollbar {
39
+ width: 4px;
40
  }
41
  ::-webkit-scrollbar-track {
42
  background: #18181b;
43
  }
44
  ::-webkit-scrollbar-thumb {
45
  background: #3f3f46;
46
+ border-radius: 2px;
 
 
 
47
  }
48
  </style>
49
  </head>
50
+ <body class="min-h-screen flex flex-col font-sans selection:bg-amber-500 selection:text-black overflow-x-hidden">
51
 
52
+ <!-- بخش سربرگ (Header) پنل مدیریت -->
53
+ <header class="border-b border-cafeBorder bg-cafeCard/70 backdrop-blur sticky top-0 z-50 px-4 py-3 md:px-8">
54
  <div class="max-w-7xl mx-auto flex items-center justify-between">
55
  <div class="flex items-center gap-3">
56
+ <!-- لوگوی وکتور فنجان قهوه هوشمند -->
57
  <svg class="w-8 h-8 text-cafeGold" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
58
  <path d="M17 8h1a4 4 0 1 1 0 8h-1" />
59
  <path d="M3 8h14v9a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4Z" />
 
62
  <line x1="14" y1="2" x2="14" y2="4" />
63
  </svg>
64
  <div>
65
+ <h1 class="text-base font-bold text-white flex items-center gap-2">
66
+ پنل مدیریت ادمین <span class="text-cafeGold">Cafe AI</span>
67
  </h1>
68
+ <p class="text-[9px] text-zinc-500">نظارت بر سفارشات آشپزخانه و تنظیم منو با هوش مصنوعی نیلا</p>
69
  </div>
70
  </div>
71
 
72
+ <div class="flex items-center gap-3">
73
+ <span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg text-[10px] font-medium bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
74
+ <span class="w-1 h-1 rounded-full bg-emerald-400 animate-pulse"></span>
75
+ سیستم مانیتورینگ زنده
76
  </span>
77
  </div>
78
  </div>
79
  </header>
80
 
81
+ <!-- چیدمان گرید دو ستونه کلی -->
82
  <main class="flex-1 max-w-7xl w-full mx-auto p-4 md:p-6 lg:p-8 grid grid-cols-1 lg:grid-cols-12 gap-6">
83
 
84
+ <!-- ستون سمت راست: لیست سفارشات فعال + ماژول آپلود منو (۷ از ۱۲) -->
85
  <section class="lg:col-span-7 flex flex-col gap-6">
86
 
87
+ <!-- باکس سفارشات در حال انتظار در آشپزخانه -->
88
+ <div class="bg-cafeCard border border-cafeBorder rounded-2xl p-5 shadow-xl">
89
  <div class="flex items-center justify-between mb-4 border-b border-cafeBorder pb-3">
90
+ <h2 class="text-sm font-bold text-white flex items-center gap-2">
91
  <svg class="w-5 h-5 text-cafeGold" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
92
  <path stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01" />
93
  </svg>
94
+ سفارشات جدید و معلق آشپزخانه
95
  </h2>
96
+ <button onclick="fetchActiveOrders()" class="text-[10px] text-zinc-400 hover:text-cafeGold flex items-center gap-1 transition-all">
97
+ <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
98
  <path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 1121.21 15H15" />
99
  </svg>
100
+ بروزرسانی وضعیت
101
  </button>
102
  </div>
103
 
104
+ <!-- ظرف دربرگیرنده کارت‌های سفارش زنده -->
105
+ <div id="ordersContainer" class="space-y-4 max-h-[350px] overflow-y-auto pr-1">
106
+ <div class="text-center py-12 text-xs text-zinc-500">
107
+ در حال بارگذاری لیست سفارشات جاری آشپزخانه...
 
108
  </div>
109
  </div>
110
  </div>
111
 
112
+ <!-- بخش بارگذاری تصویر منو و استخراج هوشمند توسط هوش مصنوعی -->
113
+ <div class="bg-cafeCard border border-cafeBorder rounded-2xl p-5 shadow-xl space-y-4">
114
+ <h2 class="text-sm font-bold text-white flex items-center gap-2 border-b border-cafeBorder pb-3">
115
  <svg class="w-5 h-5 text-cafeGold" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
116
  <path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
117
  </svg>
118
+ استخراج منوی فیزیکی با هوش مصنوعی
119
  </h2>
120
 
121
+ <p class="text-[11px] text-zinc-400 leading-relaxed">
122
+ با بارگذاری تصویر منو یا فاکتور قیمت‌های کافه، دستیار هوشمند نیلا به صورت خودکار تمام عنوان‌ها، توضیحات و قیمت‌ها را برای شما استخراج می‌کند تا پس از بازبینی و ویرایش آن را ثبت نهایی کنید.
123
  </p>
124
 
125
+ <!-- باکس رها کردن فایل جهت آپلود -->
126
+ <div class="border-2 border-dashed border-cafeBorder hover:border-cafeGold/40 rounded-xl p-6 text-center cursor-pointer transition-all bg-cafeDark/20" onclick="document.getElementById('menuFileInput').click()">
127
  <input type="file" id="menuFileInput" class="hidden" accept="image/*,application/pdf" onchange="uploadMenuFile(event)">
128
+ <div class="flex flex-col items-center gap-2.5">
129
+ <svg class="w-8 h-8 text-zinc-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
130
  <path stroke-linecap="round" stroke-linejoin="round" d="M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z" />
131
  </svg>
132
+ <span class="text-xs text-zinc-300">تصویر یا سند منو را جهت پردازش انتخاب کنید</span>
133
+ <span class="text-[9px] text-zinc-500">پشتیبانی از فرمت‌های تصویری و PDF متنی</span>
134
  </div>
135
  </div>
136
 
137
+ <!-- افکت بارگذاری در زمان استخراج تصویر منو توسط مدل -->
138
+ <div id="uploadLoader" class="hidden text-center py-6 bg-cafeDark/40 rounded-xl border border-cafeBorder">
139
+ <div class="inline-block animate-spin rounded-full h-7 w-7 border-t-2 border-b-2 border-cafeGold mb-2"></div>
140
+ <p class="text-[11px] text-cafeGold">نیلا در حال تحلیل بصری و استخراج محتوای منو است. فرآیند ممکن است چند لحظه طول بکشد...</p>
141
  </div>
142
 
143
+ <!-- ویرایشگر اقلام استخراج شده منو -->
144
+ <div id="menuEditorContainer" class="hidden space-y-4 border-t border-cafeBorder pt-4 transition-all">
145
+ <h3 class="text-xs font-bold text-amber-400 flex items-center gap-1.5">
146
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
147
  <path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
148
  </svg>
149
+ آیتم‌های استخراج شده جهت ویرای�� و انتشار
150
  </h3>
151
 
152
+ <div class="overflow-x-auto max-h-[250px] border border-cafeBorder rounded-xl">
153
+ <table class="min-w-full divide-y divide-cafeBorder bg-cafeDark/30 text-[11px]">
154
  <thead class="bg-cafeCard">
155
  <tr>
156
+ <th class="px-3 py-2 text-right font-medium text-zinc-400">نام محصول</th>
157
+ <th class="px-3 py-2 text-right font-medium text-zinc-400">توضیحات و ترکیبات</th>
158
  <th class="px-3 py-2 text-right font-medium text-zinc-400 w-24">قیمت (تومان)</th>
159
+ <th class="px-3 py-2 text-center font-medium text-zinc-400 w-16">حذف</th>
160
  </tr>
161
  </thead>
162
  <tbody id="menuEditorTableBody" class="divide-y divide-cafeBorder">
163
+ <!-- اقلام داینامیک اضافه خواهند شد -->
164
  </tbody>
165
  </table>
166
  </div>
167
 
168
  <div class="flex justify-end gap-2">
169
+ <button onclick="addEmptyMenuRow()" class="px-3 py-1.5 border border-cafeBorder hover:border-zinc-500 rounded-lg text-[10px] text-zinc-300 transition-all">
170
+ افزودن محصول جدید
171
  </button>
172
+ <button onclick="saveAndPublishMenu()" class="px-4 py-1.5 bg-emerald-600 hover:bg-emerald-500 rounded-lg text-[11px] font-bold text-white transition-all flex items-center gap-1.5">
173
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
174
  <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
175
  </svg>
176
+ انتشار منوی نهایی و همگام‌سازی زنده
177
  </button>
178
  </div>
179
  </div>
 
181
  </div>
182
  </section>
183
 
184
+ <!-- ستون سمت چپ: چت همکار با هوش مصنوعی نیلا (۵ از ۱۲) -->
185
+ <section class="lg:col-span-5 flex flex-col bg-cafeCard border border-cafeBorder rounded-2xl shadow-xl h-[630px] overflow-hidden">
186
 
187
+ <!-- هدر چت ادمین -->
188
+ <div class="px-5 py-4 border-b border-cafeBorder flex items-center justify-between bg-cafeDark/20">
189
  <div class="flex items-center gap-3">
 
190
  <div class="w-9 h-9 rounded-full bg-cafeGold/10 border border-cafeGold/30 flex items-center justify-center">
191
  <svg class="w-5 h-5 text-cafeGold" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
192
  <path d="M12 2a10 10 0 0 1 10 10c0 5.523-4.477 10-10 10S2 17.523 2 12A10 10 0 0 1 12 2z"/>
 
194
  </svg>
195
  </div>
196
  <div>
197
+ <h3 class="text-xs font-bold text-white">دستیار هوشمند ادمین (Nila)</h3>
198
+ <p class="text-[9px] text-zinc-500">مدیریت موجودی منو از طریق مکالمه زنده</p>
199
  </div>
200
  </div>
201
  </div>
202
 
203
+ <!-- بخش نمایش پیام‌های چت -->
204
  <div id="chatMessages" class="flex-1 overflow-y-auto p-4 space-y-4">
205
  <!-- پیام خوش آمدگویی پیش‌فرض -->
206
  <div class="flex gap-2.5 max-w-[85%]">
 
210
  <path d="M12 8v4l3 3"/>
211
  </svg>
212
  </div>
213
+ <div class="bg-cafeDark/50 border border-cafeBorder text-zinc-200 text-xs rounded-2xl rounded-tr-none px-3.5 py-2.5 leading-relaxed">
214
+ سلام ادمین محترم! من نیلا هستم، آماده تغییر موجودی اقلام منو از طریق گفتگو. برای مثال کافیست بنویسید: "کروسان ساده تموم شد" یا "لاته رو موجود کن" تا سریعاً تغییرات روی پنل کاربری مشتریان نیز اعمال گردد.
215
  </div>
216
  </div>
217
  </div>
218
 
219
+ <!-- کنترلر استریمینگ و تایپ هوش مصنوعی -->
220
+ <div id="chatLoader" class="hidden px-4 py-2 flex items-center justify-between bg-cafeDark/30 text-[10px] text-zinc-400 border-t border-cafeBorder/50">
221
+ <div class="flex items-center gap-2">
222
+ <div class="flex space-x-1 space-x-reverse">
223
+ <span class="w-1.5 h-1.5 bg-cafeGold rounded-full animate-bounce" style="animation-delay: 0.1s"></span>
224
+ <span class="w-1.5 h-1.5 bg-cafeGold rounded-full animate-bounce" style="animation-delay: 0.2s"></span>
225
+ <span class="w-1.5 h-1.5 bg-cafeGold rounded-full animate-bounce" style="animation-delay: 0.3s"></span>
226
+ </div>
227
+ <span>نیلا در حال پردازش دستور شماست...</span>
228
  </div>
229
+
230
+ <button onclick="stopAdminChat()" class="px-2.5 py-1 bg-rose-950/40 border border-rose-800/40 hover:bg-rose-900/60 rounded text-[9px] text-rose-400 font-bold transition-all">
231
+ توقف پردازش
232
+ </button>
233
  </div>
234
 
235
+ <!-- بخش ورودی پیام ادمین -->
236
+ <form id="chatForm" onsubmit="sendAdminMessage(event)" class="p-3 border-t border-cafeBorder bg-cafeDark/40 flex gap-2">
237
+ <input type="text" id="chatInput" placeholder="پیامی برای مدیریت موجودی بنویسید..." autocomplete="off" class="flex-1 bg-cafeCard border border-cafeBorder text-xs text-zinc-200 placeholder-zinc-500 rounded-lg px-3.5 py-2.5 focus:outline-none focus:border-cafeGold/50 transition-all">
238
+ <button type="submit" id="sendBtn" class="bg-cafeGold hover:bg-cafeGoldHover text-zinc-950 font-bold px-4 py-2.5 rounded-lg text-xs transition-all flex items-center justify-center flex-shrink-0">
239
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
240
  <path stroke-linecap="round" stroke-linejoin="round" d="M14 5l7 7m0 0l-7 7m7-7H3" />
241
  </svg>
 
246
 
247
  </main>
248
 
249
+ <!-- فوتر پایانی سایت -->
250
+ <footer class="border-t border-cafeBorder py-4 text-center text-[10px] text-zinc-600 bg-cafeDark/80">
251
  طراحی و توسعه توسط الگوریتم داده نسترن | کلیه حقوق محفوظ است © ۲۰۲۶
252
  </footer>
253
 
254
+ <!-- منطق جاوا اسکریپت برنامه ادمین -->
255
  <script>
 
256
  let chatHistory = [
257
+ { role: 'model', content: 'سلام ادمین محترم! من نیلا هستم، آماده تغییر موجودی اقلام منو از طریق گفتگو. برای مثال کافیست بنویسید: "کروسان ساده تموم شد" یا اته رو موجود کن" تا سریعاً تغییرات روی پنل کاربری مشتریان نیز اعمال گردد.' }
258
  ];
259
+ let abortController = null;
260
+ let isGenerating = false;
261
 
 
262
  window.addEventListener('DOMContentLoaded', () => {
263
  fetchActiveOrders();
264
+ // بروزرسانی اتوماتیک سفارشات در دوره‌های زمانی ۱۰ ثانیه‌ای
265
  setInterval(fetchActiveOrders, 10000);
266
  });
267
 
268
+ // --- مانیتورینگ سفارشات فعال ---
269
 
270
  async function fetchActiveOrders() {
271
  const container = document.getElementById('ordersContainer');
 
276
  if (response.ok) {
277
  if (orders.length === 0) {
278
  container.innerHTML = `
279
+ <div class="text-center py-16 text-zinc-500 border border-dashed border-cafeBorder rounded-xl bg-cafeDark/10">
280
+ <svg class="w-9 h-9 text-zinc-600 mx-auto mb-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
281
  <path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
282
  </svg>
283
+ در حال حاضر هیچ سفارش فعالی در صف انتظار نیست.
284
  </div>
285
  `;
286
  return;
 
288
 
289
  container.innerHTML = '';
290
  orders.forEach(order => {
 
291
  let itemsHtml = '';
292
  order.items.forEach(item => {
293
  itemsHtml += `
294
+ <div class="flex items-center justify-between text-[11px] bg-cafeDark/50 px-2.5 py-1.5 rounded border border-cafeBorder/40">
295
+ <span class="text-zinc-300 font-bold">${item.name}</span>
296
+ <span class="text-cafeGold bg-cafeGold/10 px-2 py-0.5 rounded font-bold">تعداد: ${item.quantity}</span>
297
  </div>
298
  `;
299
  });
300
 
301
+ const timeString = new Date(order.timestamp * 1000).toLocaleTimeString('fa-IR', { hour: '2-digit', minute: '2-digit' });
 
302
 
303
  const cardHtml = `
304
+ <div class="border border-cafeBorder hover:border-amber-500/20 rounded-xl p-4 bg-cafeDark/30 transition-all flex flex-col md:flex-row justify-between items-start md:items-center gap-3">
305
+ <div class="flex-1 space-y-2 w-full">
306
+ <div class="flex items-center justify-between md:justify-start gap-3 w-full">
307
+ <span class="text-xs font-bold text-white bg-cafeGold/10 border border-cafeGold/20 px-2.5 py-1 rounded-lg">میز شماره ${order.table}</span>
308
+ <span class="text-[9px] text-zinc-500">زمان ثبت: ${timeString}</span>
309
  </div>
310
+ <div class="grid grid-cols-1 sm:grid-cols-2 gap-1.5 mt-2">
311
  ${itemsHtml}
312
  </div>
313
  </div>
314
+ <button onclick="completeOrder(${order.id})" class="w-full md:w-auto px-3.5 py-2 bg-zinc-800 hover:bg-emerald-700 text-zinc-200 hover:text-white rounded-lg text-[10px] font-bold transition-all flex items-center justify-center gap-1.5 border border-zinc-700 hover:border-emerald-600 flex-shrink-0 group">
315
+ <svg class="w-3.5 h-3.5 text-zinc-400 group-hover:text-white transition-colors" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
316
  <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
317
  </svg>
318
+ تحویل نهایی و حذف سفارش
319
  </button>
320
  </div>
321
  `;
322
  container.insertAdjacentHTML('beforeend', cardHtml);
323
  });
324
  } else {
325
+ container.innerHTML = `<div class="text-center py-6 text-rose-500 text-xs">خطا در دریافت لیست سفارشات از پایگاه داده.</div>`;
326
  }
327
  } catch (err) {
328
+ container.innerHTML = `<div class="text-center py-6 text-rose-500 text-xs">قطع اتصال با سرور: ${err.message}</div>`;
329
  }
330
  }
331
 
 
339
 
340
  const result = await response.json();
341
  if (response.ok && result.success) {
 
342
  fetchActiveOrders();
343
  } else {
344
+ alert(result.error || "تغییر وضعیت سفارش با خطا مواجه شد.");
345
  }
346
  } catch (err) {
347
+ alert("خطای سیستم در برقراری ارتباط: " + err.message);
348
  }
349
  }
350
 
351
 
352
+ // --- مکالمه مدیریت با نیلا ---
353
 
354
  async function sendAdminMessage(e) {
355
  e.preventDefault();
356
+ if (isGenerating) return;
357
+
358
  const input = document.getElementById('chatInput');
359
+ const text = input.value.trim();
360
+ if (!text) return;
361
 
362
+ appendChatMessage('user', text);
 
363
  input.value = '';
364
 
365
+ chatHistory.push({ role: 'user', content: text });
 
366
 
367
+ isGenerating = true;
368
+ toggleChatLoading(true);
369
+
370
+ abortController = new AbortController();
371
 
372
  try {
373
  const response = await fetch('/api/admin/chat', {
374
  method: 'POST',
375
  headers: { 'Content-Type': 'application/json' },
376
+ body: JSON.stringify({ messages: chatHistory }),
377
+ signal: abortController.signal
378
  });
379
 
380
  const data = await response.json();
381
+ toggleChatLoading(false);
382
+ isGenerating = false;
383
 
384
  if (response.ok && data.success) {
385
+ // شبیه‌سازی لتر به لتر پاسخ هوش مصنوعی برای انیمیشن زیباتر
386
+ const botBubbleId = appendChatMessage('model', '');
387
+ const botBubble = document.getElementById(botBubbleId);
388
+ let i = 0;
389
+ const textResponse = data.response;
390
+
391
+ function typeText() {
392
+ if (i < textResponse.length && !abortController.signal.aborted) {
393
+ botBubble.innerText += textResponse.charAt(i);
394
+ i++;
395
+ document.getElementById('chatMessages').scrollTop = document.getElementById('chatMessages').scrollHeight;
396
+ setTimeout(typeText, 8);
397
+ } else {
398
+ chatHistory.push({ role: 'model', content: textResponse });
399
+ }
400
+ }
401
+ typeText();
402
+
403
  } else {
404
+ appendChatMessage('model', data.error || 'پاسخی از سمت دستیار هوشمند دریافت نشد.');
405
  }
406
  } catch (err) {
407
+ toggleChatLoading(false);
408
+ isGenerating = false;
409
+ if (err.name !== 'AbortError') {
410
+ appendChatMessage('model', 'خطا در شبکه رخ داده است: ' + err.message);
411
+ }
412
+ }
413
+ }
414
+
415
+ function stopAdminChat() {
416
+ if (abortController) {
417
+ abortController.abort();
418
+ }
419
+ toggleChatLoading(false);
420
+ isGenerating = false;
421
+ }
422
+
423
+ function toggleChatLoading(loading) {
424
+ const loader = document.getElementById('chatLoader');
425
+ const sendBtn = document.getElementById('sendBtn');
426
+ const input = document.getElementById('chatInput');
427
+
428
+ if (loading) {
429
+ loader.classList.remove('hidden');
430
+ sendBtn.disabled = true;
431
+ input.disabled = true;
432
+ } else {
433
  loader.classList.add('hidden');
434
+ sendBtn.disabled = false;
435
+ input.disabled = false;
436
  }
437
  }
438
 
439
  function appendChatMessage(role, content) {
440
  const container = document.getElementById('chatMessages');
441
+ const bubbleId = 'bubble-admin-' + Date.now();
442
 
443
+ let html = '';
444
  if (role === 'user') {
445
+ html = `
446
  <div class="flex justify-end gap-2.5 max-w-[85%] mr-auto">
447
  <div class="bg-amber-500/10 border border-amber-500/20 text-zinc-100 text-xs rounded-2xl rounded-tl-none px-3.5 py-2.5 leading-relaxed">
448
  ${content}
 
450
  </div>
451
  `;
452
  } else {
453
+ html = `
454
  <div class="flex gap-2.5 max-w-[85%]">
455
  <div class="w-7 h-7 rounded-full bg-cafeGold/10 border border-cafeGold/30 flex items-center justify-center flex-shrink-0">
456
  <svg class="w-4 h-4 text-cafeGold" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
 
458
  <path d="M12 8v4l3 3"/>
459
  </svg>
460
  </div>
461
+ <div id="${bubbleId}" class="bg-cafeDark/50 border border-cafeBorder text-zinc-200 text-xs rounded-2xl rounded-tr-none px-3.5 py-2.5 leading-relaxed">
462
  ${content}
463
  </div>
464
  </div>
465
  `;
466
  }
467
 
468
+ container.insertAdjacentHTML('beforeend', html);
 
469
  container.scrollTop = container.scrollHeight;
470
+ return bubbleId;
471
  }
472
 
473
 
474
+ // --- استخراج هوشمند و مدیریت فیزیکی منو ---
475
 
476
  async function uploadMenuFile(e) {
477
  const file = e.target.files[0];
478
  if (!file) return;
479
 
480
  const loader = document.getElementById('uploadLoader');
481
+ const editor = document.getElementById('menuEditorContainer');
482
 
483
  loader.classList.remove('hidden');
484
+ editor.classList.add('hidden');
485
 
486
  const formData = new FormData();
487
  formData.append('file', file);
 
497
 
498
  if (response.ok && data.success) {
499
  renderMenuEditor(data.extracted_menu);
500
+ editor.classList.remove('hidden');
501
  } else {
502
+ alert(data.error || 'عدم توانایی مدل در استخراج اقلام منو.');
503
  }
504
  } catch (err) {
505
  loader.classList.add('hidden');
506
+ alert('خطا در ارسال سند: ' + err.message);
507
  }
508
  }
509
 
 
513
 
514
  menuItems.forEach((item, index) => {
515
  const row = `
516
+ <tr class="hover:bg-cafeCard/30 transition-colors">
517
  <td class="px-2 py-2">
518
+ <input type="text" class="menu-name w-full bg-cafeCard border border-cafeBorder rounded px-2.5 py-1 text-zinc-200 focus:border-cafeGold/50 focus:outline-none" value="${item.name || ''}">
519
  </td>
520
  <td class="px-2 py-2">
521
+ <input type="text" class="menu-desc w-full bg-cafeCard border border-cafeBorder rounded px-2.5 py-1 text-zinc-200 focus:border-cafeGold/50 focus:outline-none" value="${item.description || ''}">
522
  </td>
523
  <td class="px-2 py-2">
524
+ <input type="text" class="menu-price w-full bg-cafeCard border border-cafeBorder rounded px-2.5 py-1 text-zinc-200 focus:border-cafeGold/50 focus:outline-none" value="${item.price || ''}">
525
  </td>
526
  <td class="px-2 py-2 text-center">
527
+ <button onclick="removeMenuRow(this)" class="p-1 text-zinc-500 hover:text-rose-500 transition-colors">
528
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
529
  <path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
530
  </svg>
 
539
  function addEmptyMenuRow() {
540
  const tbody = document.getElementById('menuEditorTableBody');
541
  const row = `
542
+ <tr class="hover:bg-cafeCard/30 transition-colors">
543
  <td class="px-2 py-2">
544
+ <input type="text" class="menu-name w-full bg-cafeCard border border-cafeBorder rounded px-2.5 py-1 text-zinc-200 focus:border-cafeGold/50 focus:outline-none" placeholder="نام محصول">
545
  </td>
546
  <td class="px-2 py-2">
547
+ <input type="text" class="menu-desc w-full bg-cafeCard border border-cafeBorder rounded px-2.5 py-1 text-zinc-200 focus:border-cafeGold/50 focus:outline-none" placeholder="توضیحات کوتاه">
548
  </td>
549
  <td class="px-2 py-2">
550
+ <input type="text" class="menu-price w-full bg-cafeCard border border-cafeBorder rounded px-2.5 py-1 text-zinc-200 focus:border-cafeGold/50 focus:outline-none" placeholder="مثال: ۵۰,۰۰۰">
551
  </td>
552
  <td class="px-2 py-2 text-center">
553
+ <button onclick="removeMenuRow(this)" class="p-1 text-zinc-500 hover:text-rose-500 transition-colors">
554
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
555
  <path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
556
  </svg>
 
568
  async function saveAndPublishMenu() {
569
  const tbody = document.getElementById('menuEditorTableBody');
570
  const rows = tbody.querySelectorAll('tr');
571
+ const menuData = [];
572
 
573
  rows.forEach(row => {
574
  const name = row.querySelector('.menu-name').value.trim();
575
  const description = row.querySelector('.menu-desc').value.trim();
576
  const price = row.querySelector('.menu-price').value.trim();
577
+
578
  if (name) {
579
+ menuData.push({
580
  name: name,
581
  description: description,
582
  price: price,
583
+ available: true
584
  });
585
  }
586
  });
587
 
588
+ if (menuData.length === 0) {
589
+ alert("منوی وارد شده نمی‌تواند کاملاً خالی باشد.");
590
  return;
591
  }
592
 
 
594
  const response = await fetch('/api/admin/save_menu', {
595
  method: 'POST',
596
  headers: { 'Content-Type': 'application/json' },
597
+ body: JSON.stringify({ menu: menuData })
598
  });
599
 
600
  const data = await response.json();
601
  if (response.ok && data.success) {
602
+ alert("منوی جدید با موفقیت ذخیره و در سیستم مرکزی فعال شد!");
603
  document.getElementById('menuEditorContainer').classList.add('hidden');
604
+ appendChatMessage('model', 'منوی جدید سیستم با موفقیت به سیستم مرکزی فرستاده و اعمال شد. منوی مشتریان را از روی پایگاه‌داده جدید پردازش خواهم کرد.');
 
605
  } else {
606
+ alert(data.error || 'خطا در ذخیره‌سازی منو.');
607
  }
608
  } catch (err) {
609
+ alert('خطا در ارتباط با سرور جهت ذخیره منو: ' + err.message);
610
  }
611
  }
612
  </script>