DeepLearning101 commited on
Commit
195fc4c
·
verified ·
1 Parent(s): 2c2e91f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +32 -36
app.py CHANGED
@@ -305,7 +305,7 @@ def get_menu_items():
305
  try:
306
  res = supabase.table("menu_items").select("*").order("category").order("created_at").execute()
307
  if not res.data:
308
- return pd.DataFrame(columns=['餐點名稱', '價格', '分類', '供應時段', '可外帶', '預付規則', '狀態', '照片連結'])
309
 
310
  df = pd.DataFrame(res.data)
311
 
@@ -314,13 +314,15 @@ def get_menu_items():
314
  df['require_prepay'] = df['require_prepay'].apply(lambda x: "🔥 需預付" if x else "一般")
315
  df['is_active'] = df['is_active'].apply(lambda x: "🟢 販售中" if x else "🔴 已下架")
316
  df['has_image'] = df.get('image_url', pd.Series()).apply(lambda x: "🔗 有" if pd.notnull(x) and str(x).strip() else "無")
 
 
317
 
318
- display_df = df[['name', 'price', 'category', 'available_times', 'allow_takeout', 'require_prepay', 'is_active', 'has_image']]
319
- display_df.columns = ['餐點名稱', '價格', '分類', '供應時段', '可外帶', '預付規則', '狀態', '照片連結']
320
  return display_df
321
  except Exception as e:
322
  print("Fetch menu error:", e)
323
- return pd.DataFrame(columns=['餐點名稱', '價格', '分類', '供應時段', '可外帶', '預付規則', '狀態', '照片連結'])
324
 
325
  def update_menu_dropdown():
326
  try:
@@ -330,15 +332,15 @@ def update_menu_dropdown():
330
  return gr.update(choices=choices)
331
  except: return gr.update(choices=[])
332
 
333
- # --- 新增:將選擇的餐點資料載入到左側表單 ---
334
  def load_menu_data(selected_string):
335
  if not selected_string:
336
- return "", "", 0, "main", ["晚餐 (18:30-21:30)", "宵夜 (21:30後)"], False, True, "", ""
337
 
338
  item_id = selected_string.split(" | ")[-1].strip()
339
  try:
340
  res = supabase.table("menu_items").select("*").eq("id", item_id).execute()
341
- if not res.data: return "", "", 0, "main", ["晚餐 (18:30-21:30)", "宵夜 (21:30後)"], False, True, "", ""
342
 
343
  item = res.data[0]
344
  times = item.get("available_times", [])
@@ -348,6 +350,7 @@ def load_menu_data(selected_string):
348
  item.get("name", ""),
349
  item.get("description", ""),
350
  item.get("price", 0),
 
351
  item.get("category", "main"),
352
  times,
353
  item.get("require_prepay", False),
@@ -356,35 +359,35 @@ def load_menu_data(selected_string):
356
  item_id # 將 ID 存入隱藏狀態中
357
  )
358
  except:
359
- return "", "", 0, "main", ["晚餐 (18:30-21:30)", "宵夜 (21:30後)"], False, True, "", ""
360
 
361
- def add_menu_item(name, desc, price, category, available_times, require_prepay, allow_takeout, image_url_input):
362
- # 🌟 修改這裡:把 not price 改成 price is None,這樣 0 元就能順利過關!
363
  if not name or price is None: return "⚠️ 名稱與價格為必填", get_menu_items()
364
  if not available_times: return "⚠️ 請至少選擇一個供應時段", get_menu_items()
365
  final_image_url = image_url_input.strip() if image_url_input and str(image_url_input).strip() else None
366
 
367
  try:
368
  data = {
369
- "name": name, "description": desc, "price": int(price), "category": category,
370
- "available_times": available_times, "allow_takeout": allow_takeout,
 
371
  "require_prepay": require_prepay, "is_active": True, "image_url": final_image_url
372
  }
373
  supabase.table("menu_items").insert(data).execute()
374
  return f"✅ 成功新增上架:{name}", get_menu_items()
375
  except Exception as e: return f"❌ 錯誤: {str(e)}", get_menu_items()
376
 
377
- # --- 新增:儲存修改邏輯 ---
378
- def update_menu_item(item_id, name, desc, price, category, available_times, require_prepay, allow_takeout, image_url_input):
379
  if not item_id: return "⚠️ 請先從右側選擇並「載入編輯」一項餐點", get_menu_items()
380
- # 🌟 修改這裡:同樣把 not price 改成 price is None
381
  if not name or price is None: return "⚠️ 名稱與價格為必填", get_menu_items()
382
  final_image_url = image_url_input.strip() if image_url_input and str(image_url_input).strip() else None
383
 
384
  try:
385
  data = {
386
- "name": name, "description": desc, "price": int(price), "category": category,
387
- "available_times": available_times, "allow_takeout": allow_takeout,
 
388
  "require_prepay": require_prepay, "image_url": final_image_url
389
  }
390
  supabase.table("menu_items").update(data).eq("id", item_id).execute()
@@ -436,7 +439,6 @@ with gr.Blocks(title="Cié Cié Admin", css=custom_css, theme=gr.themes.Monochro
436
  with gr.Column(elem_id="op-panel"):
437
  gr.Markdown("### 🚀 訂單操作控制台")
438
 
439
- # 第一排:ID 輸入與狀態變更選單
440
  with gr.Row():
441
  id_input = gr.Number(label="輸入訂單 ID", precision=0, scale=1)
442
  new_status_dropdown = gr.Dropdown(
@@ -445,11 +447,10 @@ with gr.Blocks(title="Cié Cié Admin", css=custom_css, theme=gr.themes.Monochro
445
  scale=1
446
  )
447
 
448
- # 第二排:各式操作按鈕
449
  with gr.Row():
450
  send_btn = gr.Button("🚀 發信/LINE", variant="primary", scale=1)
451
  update_status_btn = gr.Button("💾 變更狀態", variant="secondary", scale=1)
452
- check_lp_btn = gr.Button("🔍 查 LINE Pay", variant="secondary", scale=1)
453
  noshow_btn = gr.Button("🚫 標記 No-Show", variant="stop", scale=1)
454
  revert_noshow_btn = gr.Button("✅ 撤銷 No-Show", scale=1)
455
  refresh_btn = gr.Button("🔄 刷新列表", scale=1)
@@ -458,16 +459,8 @@ with gr.Blocks(title="Cié Cié Admin", css=custom_css, theme=gr.themes.Monochro
458
 
459
  booking_display = gr.HTML(elem_id="booking_display")
460
 
461
- # 🌟 新增:手動更新狀態的按鈕事件 🌟
462
- update_status_btn.click(
463
- update_booking_status,
464
- inputs=[id_input, new_status_dropdown],
465
- outputs=log_output
466
- ).then(render_booking_cards, outputs=booking_display)
467
-
468
  check_lp_btn.click(check_linepay_status, inputs=[id_input], outputs=log_output)
469
-
470
- # 其餘按鈕事件
471
  refresh_btn.click(render_booking_cards, outputs=booking_display)
472
  send_btn.click(send_confirmation_hybrid, inputs=id_input, outputs=log_output).then(render_booking_cards, outputs=booking_display)
473
  noshow_btn.click(toggle_no_show, inputs=[id_input, gr.State(True)], outputs=log_output).then(render_booking_cards, outputs=booking_display)
@@ -485,7 +478,12 @@ with gr.Blocks(title="Cié Cié Admin", css=custom_css, theme=gr.themes.Monochro
485
  with gr.Column(scale=1):
486
  m_name = gr.Textbox(label="餐點名稱 *")
487
  m_desc = gr.Textbox(label="餐點描述 (選填)")
488
- m_price = gr.Number(label="價格 (TWD) *", precision=0)
 
 
 
 
 
489
  m_cat = gr.Dropdown(choices=["main", "snack", "drink", "other"], label="分類", value="main")
490
  m_image_url = gr.Textbox(label="餐點照片網址 (選填)", placeholder="例如: https://ciecietaipei.github.io/assets/steak.jpg")
491
  m_times = gr.CheckboxGroup(
@@ -516,27 +514,25 @@ with gr.Blocks(title="Cié Cié Admin", css=custom_css, theme=gr.themes.Monochro
516
  m_set_inactive = gr.Button("🔴 下架", scale=1)
517
  m_toggle_log = gr.Textbox(label="操作狀態", interactive=False)
518
 
519
- # 事件綁定:載入編輯資料
520
  m_load_btn.click(
521
  load_menu_data,
522
  inputs=[m_toggle_dropdown],
523
- outputs=[m_name, m_desc, m_price, m_cat, m_times, m_prepay, m_takeout, m_image_url, m_edit_id]
524
  ).then(lambda: "✅ 已載入至左側表單,修改後請點擊「儲存修改」", outputs=m_toggle_log)
525
 
526
- # 事件綁定:新增 / 儲存修改
527
  m_add_btn.click(
528
  add_menu_item,
529
- inputs=[m_name, m_desc, m_price, m_cat, m_times, m_prepay, m_takeout, m_image_url],
530
  outputs=[m_form_log, menu_df]
531
  ).then(update_menu_dropdown, outputs=m_toggle_dropdown)
532
 
533
  m_update_btn.click(
534
  update_menu_item,
535
- inputs=[m_edit_id, m_name, m_desc, m_price, m_cat, m_times, m_prepay, m_takeout, m_image_url],
536
  outputs=[m_form_log, menu_df]
537
  ).then(update_menu_dropdown, outputs=m_toggle_dropdown)
538
 
539
- # 事件綁定:刷新與上下架
540
  m_refresh_btn.click(get_menu_items, outputs=menu_df).then(update_menu_dropdown, outputs=m_toggle_dropdown)
541
  m_set_active.click(toggle_menu_item, inputs=[m_toggle_dropdown, gr.State(True)], outputs=[m_toggle_log, menu_df]).then(update_menu_dropdown, outputs=m_toggle_dropdown)
542
  m_set_inactive.click(toggle_menu_item, inputs=[m_toggle_dropdown, gr.State(False)], outputs=[m_toggle_log, menu_df]).then(update_menu_dropdown, outputs=m_toggle_dropdown)
 
305
  try:
306
  res = supabase.table("menu_items").select("*").order("category").order("created_at").execute()
307
  if not res.data:
308
+ return pd.DataFrame(columns=['餐點名稱', '價格', '限量', '分類', '供應時段', '可外帶', '預付規則', '狀態', '照片連結'])
309
 
310
  df = pd.DataFrame(res.data)
311
 
 
314
  df['require_prepay'] = df['require_prepay'].apply(lambda x: "🔥 需預付" if x else "一般")
315
  df['is_active'] = df['is_active'].apply(lambda x: "🟢 販售中" if x else "🔴 已下架")
316
  df['has_image'] = df.get('image_url', pd.Series()).apply(lambda x: "🔗 有" if pd.notnull(x) and str(x).strip() else "無")
317
+ # 顯示限量 (999 顯示為無限制)
318
+ df['daily_limit_display'] = df.get('daily_limit', pd.Series(999)).apply(lambda x: "無限制" if x >= 999 else f"剩 {x} 份")
319
 
320
+ display_df = df[['name', 'price', 'daily_limit_display', 'category', 'available_times', 'allow_takeout', 'require_prepay', 'is_active', 'has_image']]
321
+ display_df.columns = ['餐點名稱', '價格', '限量', '分類', '供應時段', '可外帶', '預付規則', '狀態', '照片連結']
322
  return display_df
323
  except Exception as e:
324
  print("Fetch menu error:", e)
325
+ return pd.DataFrame(columns=['餐點名稱', '價格', '限量', '分類', '供應時段', '可外帶', '預付規則', '狀態', '照片連結'])
326
 
327
  def update_menu_dropdown():
328
  try:
 
332
  return gr.update(choices=choices)
333
  except: return gr.update(choices=[])
334
 
335
+ # --- 將選擇的餐點資料載入到左側表單 (加入限量讀取) ---
336
  def load_menu_data(selected_string):
337
  if not selected_string:
338
+ return "", "", 0, 999, "main", ["晚餐 (18:30-21:30)", "宵夜 (21:30後)"], False, True, "", ""
339
 
340
  item_id = selected_string.split(" | ")[-1].strip()
341
  try:
342
  res = supabase.table("menu_items").select("*").eq("id", item_id).execute()
343
+ if not res.data: return "", "", 0, 999, "main", ["晚餐 (18:30-21:30)", "宵夜 (21:30後)"], False, True, "", ""
344
 
345
  item = res.data[0]
346
  times = item.get("available_times", [])
 
350
  item.get("name", ""),
351
  item.get("description", ""),
352
  item.get("price", 0),
353
+ item.get("daily_limit", 999), # 🌟 讀取限量,預設 999
354
  item.get("category", "main"),
355
  times,
356
  item.get("require_prepay", False),
 
359
  item_id # 將 ID 存入隱藏狀態中
360
  )
361
  except:
362
+ return "", "", 0, 999, "main", ["晚餐 (18:30-21:30)", "宵夜 (21:30後)"], False, True, "", ""
363
 
364
+ def add_menu_item(name, desc, price, limit, category, available_times, require_prepay, allow_takeout, image_url_input):
 
365
  if not name or price is None: return "⚠️ 名稱與價格為必填", get_menu_items()
366
  if not available_times: return "⚠️ 請至少選擇一個供應時段", get_menu_items()
367
  final_image_url = image_url_input.strip() if image_url_input and str(image_url_input).strip() else None
368
 
369
  try:
370
  data = {
371
+ "name": name, "description": desc, "price": int(price),
372
+ "daily_limit": int(limit) if limit else 999, # 🌟 儲存限量
373
+ "category": category, "available_times": available_times, "allow_takeout": allow_takeout,
374
  "require_prepay": require_prepay, "is_active": True, "image_url": final_image_url
375
  }
376
  supabase.table("menu_items").insert(data).execute()
377
  return f"✅ 成功新增上架:{name}", get_menu_items()
378
  except Exception as e: return f"❌ 錯誤: {str(e)}", get_menu_items()
379
 
380
+ # --- 儲存修改邏輯 ---
381
+ def update_menu_item(item_id, name, desc, price, limit, category, available_times, require_prepay, allow_takeout, image_url_input):
382
  if not item_id: return "⚠️ 請先從右側選擇並「載入編輯」一項餐點", get_menu_items()
 
383
  if not name or price is None: return "⚠️ 名稱與價格為必填", get_menu_items()
384
  final_image_url = image_url_input.strip() if image_url_input and str(image_url_input).strip() else None
385
 
386
  try:
387
  data = {
388
+ "name": name, "description": desc, "price": int(price),
389
+ "daily_limit": int(limit) if limit else 999, # 🌟 儲存限量修改
390
+ "category": category, "available_times": available_times, "allow_takeout": allow_takeout,
391
  "require_prepay": require_prepay, "image_url": final_image_url
392
  }
393
  supabase.table("menu_items").update(data).eq("id", item_id).execute()
 
439
  with gr.Column(elem_id="op-panel"):
440
  gr.Markdown("### 🚀 訂單操作控制台")
441
 
 
442
  with gr.Row():
443
  id_input = gr.Number(label="輸入訂單 ID", precision=0, scale=1)
444
  new_status_dropdown = gr.Dropdown(
 
447
  scale=1
448
  )
449
 
 
450
  with gr.Row():
451
  send_btn = gr.Button("🚀 發信/LINE", variant="primary", scale=1)
452
  update_status_btn = gr.Button("💾 變更狀態", variant="secondary", scale=1)
453
+ check_lp_btn = gr.Button("🔍 查 LINE Pay (自動救援)", variant="secondary", scale=1)
454
  noshow_btn = gr.Button("🚫 標記 No-Show", variant="stop", scale=1)
455
  revert_noshow_btn = gr.Button("✅ 撤銷 No-Show", scale=1)
456
  refresh_btn = gr.Button("🔄 刷新列表", scale=1)
 
459
 
460
  booking_display = gr.HTML(elem_id="booking_display")
461
 
462
+ update_status_btn.click(update_booking_status, inputs=[id_input, new_status_dropdown], outputs=log_output).then(render_booking_cards, outputs=booking_display)
 
 
 
 
 
 
463
  check_lp_btn.click(check_linepay_status, inputs=[id_input], outputs=log_output)
 
 
464
  refresh_btn.click(render_booking_cards, outputs=booking_display)
465
  send_btn.click(send_confirmation_hybrid, inputs=id_input, outputs=log_output).then(render_booking_cards, outputs=booking_display)
466
  noshow_btn.click(toggle_no_show, inputs=[id_input, gr.State(True)], outputs=log_output).then(render_booking_cards, outputs=booking_display)
 
478
  with gr.Column(scale=1):
479
  m_name = gr.Textbox(label="餐點名稱 *")
480
  m_desc = gr.Textbox(label="餐點描述 (選填)")
481
+
482
+ with gr.Row():
483
+ m_price = gr.Number(label="價格 (TWD) *", precision=0)
484
+ # 🌟 這裡就是新加入的「每日限量」輸入框 🌟
485
+ m_limit = gr.Number(label="每日限量 (999代表無限制)", value=999, precision=0)
486
+
487
  m_cat = gr.Dropdown(choices=["main", "snack", "drink", "other"], label="分類", value="main")
488
  m_image_url = gr.Textbox(label="餐點照片網址 (選填)", placeholder="例如: https://ciecietaipei.github.io/assets/steak.jpg")
489
  m_times = gr.CheckboxGroup(
 
514
  m_set_inactive = gr.Button("🔴 下架", scale=1)
515
  m_toggle_log = gr.Textbox(label="操作狀態", interactive=False)
516
 
517
+ # 🌟 注意這裡:按鈕綁定的陣列中,已經幫您把 m_limit 都完美補進去了 🌟
518
  m_load_btn.click(
519
  load_menu_data,
520
  inputs=[m_toggle_dropdown],
521
+ outputs=[m_name, m_desc, m_price, m_limit, m_cat, m_times, m_prepay, m_takeout, m_image_url, m_edit_id]
522
  ).then(lambda: "✅ 已載入至左側表單,修改後請點擊「儲存修改」", outputs=m_toggle_log)
523
 
 
524
  m_add_btn.click(
525
  add_menu_item,
526
+ inputs=[m_name, m_desc, m_price, m_limit, m_cat, m_times, m_prepay, m_takeout, m_image_url],
527
  outputs=[m_form_log, menu_df]
528
  ).then(update_menu_dropdown, outputs=m_toggle_dropdown)
529
 
530
  m_update_btn.click(
531
  update_menu_item,
532
+ inputs=[m_edit_id, m_name, m_desc, m_price, m_limit, m_cat, m_times, m_prepay, m_takeout, m_image_url],
533
  outputs=[m_form_log, menu_df]
534
  ).then(update_menu_dropdown, outputs=m_toggle_dropdown)
535
 
 
536
  m_refresh_btn.click(get_menu_items, outputs=menu_df).then(update_menu_dropdown, outputs=m_toggle_dropdown)
537
  m_set_active.click(toggle_menu_item, inputs=[m_toggle_dropdown, gr.State(True)], outputs=[m_toggle_log, menu_df]).then(update_menu_dropdown, outputs=m_toggle_dropdown)
538
  m_set_inactive.click(toggle_menu_item, inputs=[m_toggle_dropdown, gr.State(False)], outputs=[m_toggle_log, menu_df]).then(update_menu_dropdown, outputs=m_toggle_dropdown)