Update app.py
#1
by DeepLearning101 - opened
app.py
CHANGED
|
@@ -52,7 +52,7 @@ def check_url_action(request: gr.Request):
|
|
| 52 |
|
| 53 |
|
| 54 |
# ==========================================
|
| 55 |
-
# 模組 1:訂位與通知管理 (包含 No-Show 切換)
|
| 56 |
# ==========================================
|
| 57 |
|
| 58 |
def get_bookings():
|
|
@@ -138,6 +138,17 @@ def toggle_no_show(booking_id, is_noshow=True):
|
|
| 138 |
except Exception as e:
|
| 139 |
return f"❌ 錯誤: {str(e)}"
|
| 140 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
def render_booking_cards():
|
| 142 |
df = get_bookings()
|
| 143 |
count_html = f"<div style='color:#bbb; margin-bottom:10px; text-align:right; font-size:14px;'>📊 共 <span style='color:#fff; font-weight:bold;'>{len(df)}</span> 筆資料</div>"
|
|
@@ -154,6 +165,7 @@ def render_booking_cards():
|
|
| 154 |
elif '取消' in status: status_bg = "#e74c3c"; status_tx = "#fff"; border_color = "#e74c3c"
|
| 155 |
elif '已發' in status: status_bg = "#f1c40f"; status_tx = "#000"; border_color = "#f1c40f"
|
| 156 |
elif 'No-Show' in status: status_bg = "#000"; status_tx = "#e74c3c"; border_color = "#e74c3c"
|
|
|
|
| 157 |
|
| 158 |
line_badge = "<span style='background:#00B900; color:white; padding:2px 6px; border-radius:4px; font-size:0.7em; margin-left:8px;'>LINE綁定</span>" if has_line else ""
|
| 159 |
|
|
@@ -324,19 +336,37 @@ with gr.Blocks(title="Cié Cié Admin", css=custom_css, theme=gr.themes.Monochro
|
|
| 324 |
# --- 分頁 1:訂位與通知管理 ---
|
| 325 |
with gr.TabItem("🍷 訂位與通知管理"):
|
| 326 |
with gr.Column(elem_id="op-panel"):
|
| 327 |
-
gr.Markdown("### 🚀
|
|
|
|
|
|
|
| 328 |
with gr.Row():
|
| 329 |
-
id_input = gr.Number(label="輸入訂單 ID", precision=0, scale=
|
| 330 |
-
|
| 331 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 332 |
noshow_btn = gr.Button("🚫 標記 No-Show", variant="stop", scale=1)
|
| 333 |
revert_noshow_btn = gr.Button("✅ 撤銷 No-Show", scale=1)
|
| 334 |
refresh_btn = gr.Button("🔄 刷新列表", scale=1)
|
|
|
|
| 335 |
log_output = gr.Textbox(label="執行結果日誌", lines=1)
|
| 336 |
|
| 337 |
booking_display = gr.HTML(elem_id="booking_display")
|
| 338 |
|
| 339 |
-
# 按鈕事件
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 340 |
refresh_btn.click(render_booking_cards, outputs=booking_display)
|
| 341 |
send_btn.click(send_confirmation_hybrid, inputs=id_input, outputs=log_output).then(render_booking_cards, outputs=booking_display)
|
| 342 |
noshow_btn.click(toggle_no_show, inputs=[id_input, gr.State(True)], outputs=log_output).then(render_booking_cards, outputs=booking_display)
|
|
|
|
| 52 |
|
| 53 |
|
| 54 |
# ==========================================
|
| 55 |
+
# 模組 1:訂位與通知管理 (包含 No-Show 切換與手動狀態)
|
| 56 |
# ==========================================
|
| 57 |
|
| 58 |
def get_bookings():
|
|
|
|
| 138 |
except Exception as e:
|
| 139 |
return f"❌ 錯誤: {str(e)}"
|
| 140 |
|
| 141 |
+
# 🌟 新增:手動強制更新狀態 🌟
|
| 142 |
+
def update_booking_status(booking_id, new_status):
|
| 143 |
+
if not booking_id: return "❌ 請輸入訂單 ID"
|
| 144 |
+
if not new_status: return "⚠️ 請選擇要更改的新狀態"
|
| 145 |
+
try:
|
| 146 |
+
res = supabase.table("bookings").update({"status": new_status}).eq("id", booking_id).execute()
|
| 147 |
+
if not res.data: raise Exception("找不到該筆訂單或權限不足")
|
| 148 |
+
return f"✅ 訂單 {booking_id} 狀態已成功更新為:【{new_status}】"
|
| 149 |
+
except Exception as e:
|
| 150 |
+
return f"❌ 狀態更新失敗: {str(e)}"
|
| 151 |
+
|
| 152 |
def render_booking_cards():
|
| 153 |
df = get_bookings()
|
| 154 |
count_html = f"<div style='color:#bbb; margin-bottom:10px; text-align:right; font-size:14px;'>📊 共 <span style='color:#fff; font-weight:bold;'>{len(df)}</span> 筆資料</div>"
|
|
|
|
| 165 |
elif '取消' in status: status_bg = "#e74c3c"; status_tx = "#fff"; border_color = "#e74c3c"
|
| 166 |
elif '已發' in status: status_bg = "#f1c40f"; status_tx = "#000"; border_color = "#f1c40f"
|
| 167 |
elif 'No-Show' in status: status_bg = "#000"; status_tx = "#e74c3c"; border_color = "#e74c3c"
|
| 168 |
+
elif '付款' in status: status_bg = "#3498db"; status_tx = "#fff"; border_color = "#3498db"
|
| 169 |
|
| 170 |
line_badge = "<span style='background:#00B900; color:white; padding:2px 6px; border-radius:4px; font-size:0.7em; margin-left:8px;'>LINE綁定</span>" if has_line else ""
|
| 171 |
|
|
|
|
| 336 |
# --- 分頁 1:訂位與通知管理 ---
|
| 337 |
with gr.TabItem("🍷 訂位與通知管理"):
|
| 338 |
with gr.Column(elem_id="op-panel"):
|
| 339 |
+
gr.Markdown("### 🚀 訂單操作控制台")
|
| 340 |
+
|
| 341 |
+
# 第一排:ID 輸入與狀態變更選單
|
| 342 |
with gr.Row():
|
| 343 |
+
id_input = gr.Number(label="輸入訂單 ID", precision=0, scale=1)
|
| 344 |
+
new_status_dropdown = gr.Dropdown(
|
| 345 |
+
label="手動選擇新狀態",
|
| 346 |
+
choices=["待處理", "待處理 (已付訂金)", "待付款", "已發確認信", "顧客已確認", "顧客已取消", "No-Show", "已完成 (結案)"],
|
| 347 |
+
scale=1
|
| 348 |
+
)
|
| 349 |
+
|
| 350 |
+
# 第二排:各式操作按鈕
|
| 351 |
+
with gr.Row():
|
| 352 |
+
send_btn = gr.Button("🚀 發信/LINE", variant="primary", scale=1)
|
| 353 |
+
update_status_btn = gr.Button("💾 變更狀態", variant="secondary", scale=1)
|
| 354 |
noshow_btn = gr.Button("🚫 標記 No-Show", variant="stop", scale=1)
|
| 355 |
revert_noshow_btn = gr.Button("✅ 撤銷 No-Show", scale=1)
|
| 356 |
refresh_btn = gr.Button("🔄 刷新列表", scale=1)
|
| 357 |
+
|
| 358 |
log_output = gr.Textbox(label="執行結果日誌", lines=1)
|
| 359 |
|
| 360 |
booking_display = gr.HTML(elem_id="booking_display")
|
| 361 |
|
| 362 |
+
# 🌟 新增:手動更新狀態的按鈕事件 🌟
|
| 363 |
+
update_status_btn.click(
|
| 364 |
+
update_booking_status,
|
| 365 |
+
inputs=[id_input, new_status_dropdown],
|
| 366 |
+
outputs=log_output
|
| 367 |
+
).then(render_booking_cards, outputs=booking_display)
|
| 368 |
+
|
| 369 |
+
# 其餘按鈕事件
|
| 370 |
refresh_btn.click(render_booking_cards, outputs=booking_display)
|
| 371 |
send_btn.click(send_confirmation_hybrid, inputs=id_input, outputs=log_output).then(render_booking_cards, outputs=booking_display)
|
| 372 |
noshow_btn.click(toggle_no_show, inputs=[id_input, gr.State(True)], outputs=log_output).then(render_booking_cards, outputs=booking_display)
|