DeepLearning101 commited on
Commit
f0da861
·
verified ·
1 Parent(s): 307d97e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +76 -61
app.py CHANGED
@@ -29,12 +29,12 @@ def get_bookings():
29
  except:
30
  return pd.DataFrame()
31
 
32
- # 🔥🔥🔥 5.0 修正版:邏輯統一,不再分流,保證發送 🔥🔥🔥
33
  def send_confirmation_hybrid(booking_id):
34
- if not booking_id: return "❌ 錯誤:未讀取到 ID"
 
35
 
36
  try:
37
- # 1. 撈資料
38
  res = supabase.table("bookings").select("*").eq("id", booking_id).execute()
39
  if not res.data: return "❌ 找不到訂單"
40
  booking = res.data[0]
@@ -49,16 +49,13 @@ def send_confirmation_hybrid(booking_id):
49
 
50
  log_msg = f"🆔 {booking_id}: "
51
 
52
- # 2. 準備內容 (不管發送有沒有成功,內容先準備好)
53
- # 如果狀態包含「確認」,就準備「提醒信」的內容
54
- # 否則,準備「確認信」的內容
55
  is_reminder = "確認" in current_status
56
 
57
  if is_reminder:
58
- # --- 🅰️ 提醒信內容 (Reminder) ---
59
  action_label = "提醒"
60
  mail_subject = f"🔔 訂位提醒: {booking['date']} - Cié Cié Taipei"
61
-
62
  line_text = (
63
  f"🔔 訂位提醒\n\n"
64
  f"{booking['name']} 您好,期待今晚與您相見!\n\n"
@@ -67,29 +64,26 @@ def send_confirmation_hybrid(booking_id):
67
  f"👥 人數:{booking['pax']} 位\n\n"
68
  f"座位已為您準備好,若需變更請聯繫我們。"
69
  )
70
-
71
  mail_html = f"""
72
- <div style="background:#1a1a1a; color:#d4af37; padding:20px; border-radius:8px; font-family:sans-serif; border:1px solid #333;">
73
- <h2 style="text-align:center; border-bottom:1px solid #444; padding-bottom:15px;">Cié Cié Taipei</h2>
74
- <p style="color:#eee; font-size:16px;"><strong>{booking['name']}</strong> 您好,期待您的光臨!</p>
75
- <div style="background:#2a2a2a; padding:15px; border-radius:8px; margin:20px 0; border-left:4px solid #f1c40f;">
76
- <ul style="color:#ddd; padding-left:20px; line-height:1.8;">
77
- <li>📅 日期:<strong style="color:#fff;">{booking['date']}</strong></li>
78
- <li>⏰ 時間:<strong style="color:#fff;">{booking['time']}</strong></li>
79
- <li>👥 人數:<strong style="color:#fff;">{booking['pax']} 位</strong></li>
80
  </ul>
81
  </div>
82
  <div style="text-align:center; margin-top:30px;">
83
- <span style="color:#888; font-size:14px;">這是一封行前提醒。</span><br><br>
84
- <a href="{cancel_link}" style="display:inline-block; border:1px solid #555; color:#aaa; padding:10px 20px; text-decoration:none; border-radius:50px; font-size:12px;">若無法前來,請點此取消</a>
85
  </div>
86
  </div>
87
  """
88
  else:
89
- # --- 🅱️ 確認信內容 (Confirmation) ---
90
  action_label = "確認"
91
  mail_subject = f"訂位確認: {booking['date']} - Cié Cié Taipei"
92
-
93
  line_text = (
94
  f"✅ 訂位確認\n\n"
95
  f"{booking['name']} 您好,已收到您的預約。\n\n"
@@ -98,28 +92,25 @@ def send_confirmation_hybrid(booking_id):
98
  f"👥 人數:{booking['pax']} 位\n\n"
99
  f"請務必查收 Email 並點擊「確認出席」,謝謝!"
100
  )
101
-
102
  mail_html = f"""
103
- <div style="background:#1a1a1a; color:#d4af37; padding:20px; border-radius:8px; font-family:sans-serif; border:1px solid #333;">
104
- <h2 style="text-align:center; border-bottom:1px solid #444; padding-bottom:15px;">Cié Cié Taipei</h2>
105
- <p style="color:#eee; font-size:16px;"><strong>{booking['name']}</strong> 您好,請確認您的訂位:</p>
106
- <div style="background:#2a2a2a; padding:15px; border-radius:8px; margin:20px 0; border-left:4px solid #2ecc71;">
107
- <ul style="color:#ddd; padding-left:20px; line-height:1.8;">
108
- <li>📅 日期:<strong style="color:#fff;">{booking['date']}</strong></li>
109
- <li>⏰ 時間:<strong style="color:#fff;">{booking['time']}</strong></li>
110
- <li>👥 人數:<strong style="color:#fff;">{booking['pax']} 位</strong></li>
111
  </ul>
112
  </div>
113
  <div style="text-align:center; margin-top:30px;">
114
- <a href="{confirm_link}" style="display:inline-block; background:#d4af37; color:#000; padding:12px 30px; text-decoration:none; border-radius:50px; font-weight:bold; margin-right:10px;">✅ 確認出席 (Confirm)</a>
115
- <a href="{cancel_link}" style="display:inline-block; border:1px solid #555; color:#aaa; padding:11px 29px; text-decoration:none; border-radius:50px;">🚫 取消 (Cancel)</a>
116
  </div>
117
  </div>
118
  """
119
 
120
- # 3. 🔥🔥🔥 關鍵:不管上面是走哪條路,這裡統一執行發送,絕對不跳過 🔥🔥🔥
121
-
122
- # 發送 Email
123
  if email and "@" in email and GAS_MAIL_URL:
124
  try:
125
  requests.post(GAS_MAIL_URL, json={"to": email, "subject": mail_subject, "htmlBody": mail_html, "name": "Cié Cié Taipei"})
@@ -128,7 +119,6 @@ def send_confirmation_hybrid(booking_id):
128
  else:
129
  log_msg += "⚠️ 無Email "
130
 
131
- # 發送 LINE
132
  if user_id and len(str(user_id)) > 5 and LINE_ACCESS_TOKEN:
133
  try:
134
  requests.post("https://api.line.me/v2/bot/message/push",
@@ -139,16 +129,14 @@ def send_confirmation_hybrid(booking_id):
139
  else:
140
  log_msg += "⚠️ 無LINE ID "
141
 
142
- # 4. 更新資料庫 (只有確認信才更新狀態,提醒信不更新)
143
  if not is_reminder:
144
  supabase.table("bookings").update({"status": "已發確認信"}).eq("id", booking_id).execute()
145
 
146
  return log_msg
147
 
148
- except Exception as e:
149
- return f"🔥 嚴重錯誤: {str(e)}"
150
 
151
- # --- 介面渲染 (保持您要的樣式) ---
152
  def render_booking_cards():
153
  df = get_bookings()
154
  count_html = f"<div style='color:#bbb; margin-bottom:20px; text-align:right; font-size:16px; padding: 0 10px;'>📊 共找到 <span style='color:#fff; font-weight:bold;'>{len(df)}</span> 筆資料</div>"
@@ -257,31 +245,15 @@ def check_login(user, password):
257
  }
258
  else: return {error_msg: "<span style='color: red'>❌ 帳號或密碼錯誤</span>"}
259
 
260
- # --- JS 邏輯 ---
261
- js_logic = """
262
- function() {
263
- window.cardAction = function(id) {
264
- let idInput = document.querySelector('#hidden_id_input input');
265
- if (idInput) {
266
- idInput.value = id;
267
- idInput.dispatchEvent(new Event('input', { bubbles: true }));
268
- }
269
- setTimeout(() => {
270
- const sendBtn = document.querySelector('#hidden_send_btn');
271
- if (sendBtn) sendBtn.click();
272
- }, 150);
273
- }
274
- }
275
- """
276
 
277
- # --- CSS (確保按鈕可被點擊) ---
278
  custom_css = """
279
  body, .gradio-container { background-color: #0F0F0F; color: #fff; }
280
  #booking_display { height: auto !important; max-height: none !important; overflow: visible !important; margin-bottom: 50px; }
281
  button:active { transform: scale(0.96); }
282
  #header-panel { background: #1a1a1a; padding: 15px; margin-bottom: 20px; border-radius: 10px; }
283
 
284
- /* 絕對定位移出畫面,確保 JS 抓得到 */
285
  #hidden_ops {
286
  position: absolute !important;
287
  left: -9999px !important;
@@ -292,8 +264,52 @@ button:active { transform: scale(0.96); }
292
  }
293
  """
294
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  # --- 介面 ---
296
  with gr.Blocks(title="Admin") as demo:
 
 
 
 
297
  with gr.Group(visible=True) as login_row:
298
  gr.Markdown("# 🔒 Login")
299
  with gr.Row():
@@ -309,7 +325,7 @@ with gr.Blocks(title="Admin") as demo:
309
 
310
  booking_display = gr.HTML(elem_id="booking_display")
311
 
312
- # 🔥 確保 visible=True
313
  with gr.Column(visible=True, elem_id="hidden_ops"):
314
  hidden_id_input = gr.Number(elem_id="hidden_id_input", precision=0)
315
  hidden_send_btn = gr.Button("Send", elem_id="hidden_send_btn")
@@ -321,7 +337,6 @@ with gr.Blocks(title="Admin") as demo:
321
  )
322
  refresh_btn.click(render_booking_cards, outputs=booking_display)
323
 
324
- # 發送事件
325
  hidden_send_btn.click(
326
  send_confirmation_hybrid,
327
  inputs=hidden_id_input,
@@ -331,7 +346,7 @@ with gr.Blocks(title="Admin") as demo:
331
  outputs=booking_display
332
  )
333
 
334
- demo.launch(css=custom_css, js=js_logic)
335
 
336
  if __name__ == "__main__":
337
  demo.launch()
 
29
  except:
30
  return pd.DataFrame()
31
 
32
+ # 🔥🔥🔥 後端發送邏輯 (暴力發送) 🔥🔥🔥
33
  def send_confirmation_hybrid(booking_id):
34
+ print(f"收到後端請求,ID: {booking_id}") # Server log
35
+ if not booking_id: return "❌ 錯誤:未讀取到 ID (Backend received None)"
36
 
37
  try:
 
38
  res = supabase.table("bookings").select("*").eq("id", booking_id).execute()
39
  if not res.data: return "❌ 找不到訂單"
40
  booking = res.data[0]
 
49
 
50
  log_msg = f"🆔 {booking_id}: "
51
 
52
+ # 判斷內容
 
 
53
  is_reminder = "確認" in current_status
54
 
55
  if is_reminder:
56
+ # 提醒信
57
  action_label = "提醒"
58
  mail_subject = f"🔔 訂位提醒: {booking['date']} - Cié Cié Taipei"
 
59
  line_text = (
60
  f"🔔 訂位提醒\n\n"
61
  f"{booking['name']} 您好,期待今晚與您相見!\n\n"
 
64
  f"👥 人數:{booking['pax']} 位\n\n"
65
  f"座位已為您準備好,若需變更請聯繫我們。"
66
  )
 
67
  mail_html = f"""
68
+ <div style="background:#1a1a1a; color:#d4af37; padding:20px; border-radius:8px;">
69
+ <h2 style="text-align:center; border-bottom:1px solid #444;">Cié Cié Taipei</h2>
70
+ <p style="color:#eee;"><strong>{booking['name']}</strong> 您好,期待您的光臨!這是一封行前提醒。</p>
71
+ <div style="background:#2a2a2a; padding:15px; margin:20px 0; border-left:4px solid #f1c40f;">
72
+ <ul style="color:#ddd;">
73
+ <li>📅 日期:{booking['date']}</li>
74
+ <li>⏰ 時間:{booking['time']}</li>
75
+ <li>👥 人數:{booking['pax']} 位</li>
76
  </ul>
77
  </div>
78
  <div style="text-align:center; margin-top:30px;">
79
+ <a href="{cancel_link}" style="color:#aaa;">若無法前來,請點此取消</a>
 
80
  </div>
81
  </div>
82
  """
83
  else:
84
+ # 確認信
85
  action_label = "確認"
86
  mail_subject = f"訂位確認: {booking['date']} - Cié Cié Taipei"
 
87
  line_text = (
88
  f"✅ 訂位確認\n\n"
89
  f"{booking['name']} 您好,已收到您的預約。\n\n"
 
92
  f"👥 人數:{booking['pax']} 位\n\n"
93
  f"請務必查收 Email 並點擊「確認出席」,謝謝!"
94
  )
 
95
  mail_html = f"""
96
+ <div style="background:#1a1a1a; color:#d4af37; padding:20px; border-radius:8px;">
97
+ <h2 style="text-align:center; border-bottom:1px solid #444;">Cié Cié Taipei</h2>
98
+ <p style="color:#eee;"><strong>{booking['name']}</strong> 您好,請確認您的訂位:</p>
99
+ <div style="background:#2a2a2a; padding:15px; margin:20px 0; border-left:4px solid #2ecc71;">
100
+ <ul style="color:#ddd;">
101
+ <li>📅 日期:{booking['date']}</li>
102
+ <li>⏰ 時間:{booking['time']}</li>
103
+ <li>👥 人數:{booking['pax']} 位</li>
104
  </ul>
105
  </div>
106
  <div style="text-align:center; margin-top:30px;">
107
+ <a href="{confirm_link}" style="background:#d4af37; color:#000; padding:12px 30px; text-decoration:none; border-radius:50px; font-weight:bold;">✅ 確認出席</a>
108
+ <a href="{cancel_link}" style="color:#aaa; margin-left:20px;">取消</a>
109
  </div>
110
  </div>
111
  """
112
 
113
+ # 執行發送
 
 
114
  if email and "@" in email and GAS_MAIL_URL:
115
  try:
116
  requests.post(GAS_MAIL_URL, json={"to": email, "subject": mail_subject, "htmlBody": mail_html, "name": "Cié Cié Taipei"})
 
119
  else:
120
  log_msg += "⚠️ 無Email "
121
 
 
122
  if user_id and len(str(user_id)) > 5 and LINE_ACCESS_TOKEN:
123
  try:
124
  requests.post("https://api.line.me/v2/bot/message/push",
 
129
  else:
130
  log_msg += "⚠️ 無LINE ID "
131
 
 
132
  if not is_reminder:
133
  supabase.table("bookings").update({"status": "已發確認信"}).eq("id", booking_id).execute()
134
 
135
  return log_msg
136
 
137
+ except Exception as e: return f"🔥 嚴重錯誤: {str(e)}"
 
138
 
139
+ # --- 卡片渲染 ---
140
  def render_booking_cards():
141
  df = get_bookings()
142
  count_html = f"<div style='color:#bbb; margin-bottom:20px; text-align:right; font-size:16px; padding: 0 10px;'>📊 共找到 <span style='color:#fff; font-weight:bold;'>{len(df)}</span> 筆資料</div>"
 
245
  }
246
  else: return {error_msg: "<span style='color: red'>❌ 帳號或密碼錯誤</span>"}
247
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
 
249
+ # --- CSS ---
250
  custom_css = """
251
  body, .gradio-container { background-color: #0F0F0F; color: #fff; }
252
  #booking_display { height: auto !important; max-height: none !important; overflow: visible !important; margin-bottom: 50px; }
253
  button:active { transform: scale(0.96); }
254
  #header-panel { background: #1a1a1a; padding: 15px; margin-bottom: 20px; border-radius: 10px; }
255
 
256
+ /* 🔥 隱藏操作區:用 CSS 把元件移出畫面,確保 JS 仍然可以存取 */
257
  #hidden_ops {
258
  position: absolute !important;
259
  left: -9999px !important;
 
264
  }
265
  """
266
 
267
+ # 🔥🔥🔥 暴力注入 JS:直接寫在 HTML 裡,確保 cardAction 絕對全域可用 🔥🔥🔥
268
+ # 這段代碼會被直接渲染到網頁頂部,解決 ReferenceError
269
+ GLOBAL_JS = """
270
+ <script>
271
+ console.log("✨ ���位系統腳本已載入 (v5.1)");
272
+
273
+ // 直接定義在 window 物件上,保證全域可見
274
+ window.cardAction = function(id) {
275
+ console.log("👉 按下 ID:", id);
276
+
277
+ // 1. 找輸入框 (相容 input 和 textarea)
278
+ let idInput = document.querySelector('#hidden_id_input input');
279
+
280
+ if (idInput) {
281
+ console.log("✅ 找到隱藏輸入框,寫入 ID...");
282
+ // 強制寫入值
283
+ idInput.value = id;
284
+ // 觸發 React/Gradio 的更新事件
285
+ let event = new Event('input', { bubbles: true });
286
+ idInput.dispatchEvent(event);
287
+
288
+ // 2. 觸發按鈕
289
+ setTimeout(() => {
290
+ let sendBtn = document.querySelector('#hidden_send_btn');
291
+ if (sendBtn) {
292
+ console.log("🚀 觸發發送按鈕...");
293
+ sendBtn.click();
294
+ } else {
295
+ console.error("❌ 找不到發送按鈕 (#hidden_send_btn)");
296
+ alert("系統錯誤:找不到發送按鈕,請重新整理頁面");
297
+ }
298
+ }, 200); // 延遲 200ms 確保數值已更新
299
+ } else {
300
+ console.error("❌ 找不到隱藏輸入框 (#hidden_id_input)");
301
+ alert("系統錯誤:找不到輸入框,請重新整理頁面");
302
+ }
303
+ }
304
+ </script>
305
+ """
306
+
307
  # --- 介面 ---
308
  with gr.Blocks(title="Admin") as demo:
309
+
310
+ # 注入 JS 腳本 (直接放在最上面)
311
+ gr.HTML(GLOBAL_JS)
312
+
313
  with gr.Group(visible=True) as login_row:
314
  gr.Markdown("# 🔒 Login")
315
  with gr.Row():
 
325
 
326
  booking_display = gr.HTML(elem_id="booking_display")
327
 
328
+ # 🔥 隱藏操作區:visible=True 但被 CSS 移出畫面
329
  with gr.Column(visible=True, elem_id="hidden_ops"):
330
  hidden_id_input = gr.Number(elem_id="hidden_id_input", precision=0)
331
  hidden_send_btn = gr.Button("Send", elem_id="hidden_send_btn")
 
337
  )
338
  refresh_btn.click(render_booking_cards, outputs=booking_display)
339
 
 
340
  hidden_send_btn.click(
341
  send_confirmation_hybrid,
342
  inputs=hidden_id_input,
 
346
  outputs=booking_display
347
  )
348
 
349
+ demo.launch(css=custom_css)
350
 
351
  if __name__ == "__main__":
352
  demo.launch()