DeepLearning101 commited on
Commit
d8955c7
·
verified ·
1 Parent(s): bc34808

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +28 -20
app.py CHANGED
@@ -36,16 +36,38 @@ def get_date_options():
36
 
37
  def update_time_slots(date_str):
38
  if not date_str: return gr.update(choices=[]), "請先選擇日期"
 
39
  try:
40
  clean_date_str = date_str.split(" ")[0]
41
  date_obj = datetime.strptime(clean_date_str, "%Y-%m-%d")
42
  weekday = date_obj.weekday()
43
  except: return gr.update(choices=[]), "日期格式錯誤"
44
 
 
45
  slots = ["18:30", "19:00", "19:30", "20:00", "20:30",
46
  "21:00", "21:30", "22:00", "22:30", "23:00", "23:30", "00:00", "00:30", "01:00", "01:30"]
47
  if weekday == 4 or weekday == 5: slots.extend(["02:00", "02:30"])
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  clean_date = date_str.split(" ")[0]
50
  daily_limit = SPECIAL_DAYS.get(clean_date, DEFAULT_LIMIT)
51
 
@@ -56,6 +78,7 @@ def update_time_slots(date_str):
56
  status_msg = f"✨ {date_str} (剩餘座位: {remaining} 位)"
57
  except: status_msg = f"✨ {date_str}"
58
 
 
59
  return gr.update(choices=slots, value=slots[0] if slots else None), status_msg
60
 
61
  # --- [新增] 初始化 UI 的函式 (解決日期過期問題) ---
@@ -64,20 +87,16 @@ def init_ui():
64
  當網頁載入時執行:
65
  1. 重新計算日期列表 (確保今天是真的今天)
66
  2. 自動選擇第一天 (今天)
67
- 3. 根據今天,自動更新時段和剩餘座位
68
  """
69
- # 1. 取得最新的日期列表
70
  fresh_dates = get_date_options()
71
  default_date = fresh_dates[0]
72
-
73
- # 2. 根據「今天」去計算時段 (呼叫既有的邏輯)
74
  time_update, status_msg = update_time_slots(default_date)
75
 
76
- # 3. 回傳三個元件的更新
77
  return (
78
- gr.update(choices=fresh_dates, value=default_date), # 更新日期選單
79
- time_update, # 更新時段選單
80
- status_msg # 更新狀態文字
81
  )
82
 
83
  # --- 4. 核心邏輯 (抓 ID 與 處理訂位) ---
@@ -136,20 +155,17 @@ def check_confirmation(request: gr.Request):
136
  action = request.query_params.get('action')
137
  bid = request.query_params.get('id')
138
 
139
- # 目標官網首頁
140
  OFFICIAL_SITE = "https://ciecietaipei.github.io/index.html"
141
 
142
  if action == 'confirm' and bid:
143
  try:
144
  supabase.table("bookings").update({"status": "顧客已確認"}).eq("id", bid).execute()
145
- # 回傳目標網址
146
  return f"{OFFICIAL_SITE}?status=confirmed"
147
  except: pass
148
 
149
  elif action == 'cancel' and bid:
150
  try:
151
  supabase.table("bookings").update({"status": "顧客已取消"}).eq("id", bid).execute()
152
- # 回傳目標網址
153
  return f"{OFFICIAL_SITE}?status=canceled"
154
  except: pass
155
 
@@ -158,21 +174,15 @@ def check_confirmation(request: gr.Request):
158
  # --- 6. 介面 ---
159
  theme = gr.themes.Soft(primary_hue="amber", neutral_hue="zinc").set(body_background_fill="#0F0F0F", block_background_fill="#1a1a1a", block_border_width="1px", block_border_color="#333", input_background_fill="#262626", input_border_color="#444", body_text_color="#E0E0E0", block_title_text_color="#d4af37", button_primary_background_fill="#d4af37", button_primary_text_color="#000000")
160
 
161
- # CSS 隱藏技巧
162
  custom_css = "footer {display: none !important;} .gradio-container, .block, .row, .column { overflow: visible !important; } .options, .wrap .options { background-color: #262626 !important; border: 1px solid #d4af37 !important; z-index: 10000 !important; box-shadow: 0 5px 15px rgba(0,0,0,0.5); } .item:hover, .options .item:hover { background-color: #d4af37 !important; color: black !important; } .legal-footer { text-align: center; margin-top: 15px; padding-top: 15px; border-top: 1px solid #333; color: #666; font-size: 0.75rem; } #hidden_box { display: none !important; }"
163
 
164
  with gr.Blocks(theme=theme, css=custom_css, title="Booking") as demo:
165
- # 接收 LINE ID 的盒子 (CSS 隱藏)
166
  line_id_box = gr.Textbox(visible=True, elem_id="hidden_box", label="LINE ID")
167
-
168
- # 接收轉址 URL 的盒子 (隱藏)
169
  redirect_url_box = gr.Textbox(visible=False)
170
 
171
- # 載入時觸發
172
  demo.load(get_line_id_from_url, None, line_id_box)
173
  demo.load(check_confirmation, None, redirect_url_box)
174
 
175
- # 關鍵:當 redirect_url_box 有值時,執行 JS 轉址
176
  redirect_url_box.change(
177
  fn=None,
178
  inputs=redirect_url_box,
@@ -183,7 +193,6 @@ with gr.Blocks(theme=theme, css=custom_css, title="Booking") as demo:
183
  with gr.Row():
184
  with gr.Column():
185
  gr.Markdown("### 📅 預約資訊 Booking Info")
186
- # 這裡的 choices 初始值會被下方的 load 覆蓋,所以留空也沒關係,但為了邏輯正確我先拿掉 get_date_options() 的調用
187
  booking_date = gr.Dropdown(label="選擇日期 Select Date", interactive=True)
188
  pax_count = gr.Slider(minimum=1, maximum=10, value=2, step=1, label="用餐人數 Guest Count")
189
  with gr.Column():
@@ -191,8 +200,7 @@ with gr.Blocks(theme=theme, css=custom_css, title="Booking") as demo:
191
  status_box = gr.Markdown("請先選擇日期...", visible=True)
192
  time_slot = gr.Dropdown(choices=[], label="可用時段 Available Time", interactive=True)
193
 
194
- # 🔥🔥🔥 這裡是最關鍵的修正! 🔥🔥🔥
195
- # 當頁面載入時,執行 init_ui,這會重新計算日期,並更新 1.日期選單 2.時段選單 3.狀態文字
196
  demo.load(init_ui, None, [booking_date, time_slot, status_box])
197
 
198
  gr.HTML("<div style='height: 10px'></div>")
 
36
 
37
  def update_time_slots(date_str):
38
  if not date_str: return gr.update(choices=[]), "請先選擇日期"
39
+
40
  try:
41
  clean_date_str = date_str.split(" ")[0]
42
  date_obj = datetime.strptime(clean_date_str, "%Y-%m-%d")
43
  weekday = date_obj.weekday()
44
  except: return gr.update(choices=[]), "日期格式錯誤"
45
 
46
+ # 預設的所有時段
47
  slots = ["18:30", "19:00", "19:30", "20:00", "20:30",
48
  "21:00", "21:30", "22:00", "22:30", "23:00", "23:30", "00:00", "00:30", "01:00", "01:30"]
49
  if weekday == 4 or weekday == 5: slots.extend(["02:00", "02:30"])
50
 
51
+ # 🔥🔥🔥 新增:時間過濾邏輯 🔥🔥🔥
52
+ now = datetime.now(TAIPEI_TZ)
53
+ # 只有當選擇的日期是「今天」時,才需要過濾過去的時間
54
+ if date_obj.date() == now.date():
55
+ current_time_str = now.strftime("%H:%M") # 取得現在時間字串 (例如 "22:15")
56
+ valid_slots = []
57
+ for s in slots:
58
+ h = int(s.split(":")[0]) # 取得時段的小時數
59
+
60
+ # 判斷邏輯:
61
+ # 1. 凌晨時段 (00:00 - 05:00):這屬於「跨日」,相對於今天的晚餐時段來說是未來,所以保留。
62
+ # 2. 晚間時段 (18:00+):必須比「現在時間」晚,才保留。
63
+ if h < 5:
64
+ valid_slots.append(s)
65
+ elif s > current_time_str:
66
+ valid_slots.append(s)
67
+
68
+ slots = valid_slots # 更新清單
69
+
70
+ # 計算剩餘座位 (維持原樣)
71
  clean_date = date_str.split(" ")[0]
72
  daily_limit = SPECIAL_DAYS.get(clean_date, DEFAULT_LIMIT)
73
 
 
78
  status_msg = f"✨ {date_str} (剩餘座位: {remaining} 位)"
79
  except: status_msg = f"✨ {date_str}"
80
 
81
+ # 如果所有時段都過期了 (slots 為空),value 給 None
82
  return gr.update(choices=slots, value=slots[0] if slots else None), status_msg
83
 
84
  # --- [新增] 初始化 UI 的函式 (解決日期過期問題) ---
 
87
  當網頁載入時執行:
88
  1. 重新計算日期列表 (確保今天是真的今天)
89
  2. 自動選擇第一天 (今天)
90
+ 3. 根據今天,自動更新時段和剩餘座位 (此時會自動觸發上方的時間過濾)
91
  """
 
92
  fresh_dates = get_date_options()
93
  default_date = fresh_dates[0]
 
 
94
  time_update, status_msg = update_time_slots(default_date)
95
 
 
96
  return (
97
+ gr.update(choices=fresh_dates, value=default_date),
98
+ time_update,
99
+ status_msg
100
  )
101
 
102
  # --- 4. 核心邏輯 (抓 ID 與 處理訂位) ---
 
155
  action = request.query_params.get('action')
156
  bid = request.query_params.get('id')
157
 
 
158
  OFFICIAL_SITE = "https://ciecietaipei.github.io/index.html"
159
 
160
  if action == 'confirm' and bid:
161
  try:
162
  supabase.table("bookings").update({"status": "顧客已確認"}).eq("id", bid).execute()
 
163
  return f"{OFFICIAL_SITE}?status=confirmed"
164
  except: pass
165
 
166
  elif action == 'cancel' and bid:
167
  try:
168
  supabase.table("bookings").update({"status": "顧客已取消"}).eq("id", bid).execute()
 
169
  return f"{OFFICIAL_SITE}?status=canceled"
170
  except: pass
171
 
 
174
  # --- 6. 介面 ---
175
  theme = gr.themes.Soft(primary_hue="amber", neutral_hue="zinc").set(body_background_fill="#0F0F0F", block_background_fill="#1a1a1a", block_border_width="1px", block_border_color="#333", input_background_fill="#262626", input_border_color="#444", body_text_color="#E0E0E0", block_title_text_color="#d4af37", button_primary_background_fill="#d4af37", button_primary_text_color="#000000")
176
 
 
177
  custom_css = "footer {display: none !important;} .gradio-container, .block, .row, .column { overflow: visible !important; } .options, .wrap .options { background-color: #262626 !important; border: 1px solid #d4af37 !important; z-index: 10000 !important; box-shadow: 0 5px 15px rgba(0,0,0,0.5); } .item:hover, .options .item:hover { background-color: #d4af37 !important; color: black !important; } .legal-footer { text-align: center; margin-top: 15px; padding-top: 15px; border-top: 1px solid #333; color: #666; font-size: 0.75rem; } #hidden_box { display: none !important; }"
178
 
179
  with gr.Blocks(theme=theme, css=custom_css, title="Booking") as demo:
 
180
  line_id_box = gr.Textbox(visible=True, elem_id="hidden_box", label="LINE ID")
 
 
181
  redirect_url_box = gr.Textbox(visible=False)
182
 
 
183
  demo.load(get_line_id_from_url, None, line_id_box)
184
  demo.load(check_confirmation, None, redirect_url_box)
185
 
 
186
  redirect_url_box.change(
187
  fn=None,
188
  inputs=redirect_url_box,
 
193
  with gr.Row():
194
  with gr.Column():
195
  gr.Markdown("### 📅 預約資訊 Booking Info")
 
196
  booking_date = gr.Dropdown(label="選擇日期 Select Date", interactive=True)
197
  pax_count = gr.Slider(minimum=1, maximum=10, value=2, step=1, label="用餐人數 Guest Count")
198
  with gr.Column():
 
200
  status_box = gr.Markdown("請先選擇日期...", visible=True)
201
  time_slot = gr.Dropdown(choices=[], label="可用時段 Available Time", interactive=True)
202
 
203
+ # 載入時初始化 UI (包含日期與時間過濾)
 
204
  demo.load(init_ui, None, [booking_date, time_slot, status_box])
205
 
206
  gr.HTML("<div style='height: 10px'></div>")