Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -25,6 +25,7 @@ SPECIAL_DAYS = {
|
|
| 25 |
# --- 3. 輔助函式 ---
|
| 26 |
def get_date_options():
|
| 27 |
options = []
|
|
|
|
| 28 |
today = datetime.now(TAIPEI_TZ)
|
| 29 |
weekdays = ["(一)", "(二)", "(三)", "(四)", "(五)", "(六)", "(日)"]
|
| 30 |
for i in range(30):
|
|
@@ -57,6 +58,28 @@ def update_time_slots(date_str):
|
|
| 57 |
|
| 58 |
return gr.update(choices=slots, value=slots[0] if slots else None), status_msg
|
| 59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
# --- 4. 核心邏輯 (抓 ID 與 處理訂位) ---
|
| 61 |
def get_line_id_from_url(request: gr.Request):
|
| 62 |
if request:
|
|
@@ -108,7 +131,6 @@ def handle_booking(name, tel, email, date_str, time, pax, remarks, line_id):
|
|
| 108 |
except Exception as e: return f"❌ 系統錯誤: {str(e)}"
|
| 109 |
|
| 110 |
# --- 5. Webhook (確認/取消 + 回傳轉址 URL) ---
|
| 111 |
-
# ⚠️ 改動:這裡只回傳「純網址字串」,不回傳 script 標籤
|
| 112 |
def check_confirmation(request: gr.Request):
|
| 113 |
if not request: return ""
|
| 114 |
action = request.query_params.get('action')
|
|
@@ -136,21 +158,21 @@ def check_confirmation(request: gr.Request):
|
|
| 136 |
# --- 6. 介面 ---
|
| 137 |
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")
|
| 138 |
|
| 139 |
-
# CSS 隱藏技巧
|
| 140 |
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; }"
|
| 141 |
|
| 142 |
with gr.Blocks(theme=theme, css=custom_css, title="Booking") as demo:
|
| 143 |
# 接收 LINE ID 的盒子 (CSS 隱藏)
|
| 144 |
line_id_box = gr.Textbox(visible=True, elem_id="hidden_box", label="LINE ID")
|
| 145 |
|
| 146 |
-
#
|
| 147 |
redirect_url_box = gr.Textbox(visible=False)
|
| 148 |
|
| 149 |
# 載入時觸發
|
| 150 |
demo.load(get_line_id_from_url, None, line_id_box)
|
| 151 |
demo.load(check_confirmation, None, redirect_url_box)
|
| 152 |
|
| 153 |
-
#
|
| 154 |
redirect_url_box.change(
|
| 155 |
fn=None,
|
| 156 |
inputs=redirect_url_box,
|
|
@@ -161,13 +183,18 @@ with gr.Blocks(theme=theme, css=custom_css, title="Booking") as demo:
|
|
| 161 |
with gr.Row():
|
| 162 |
with gr.Column():
|
| 163 |
gr.Markdown("### 📅 預約資訊 Booking Info")
|
| 164 |
-
|
|
|
|
| 165 |
pax_count = gr.Slider(minimum=1, maximum=10, value=2, step=1, label="用餐人數 Guest Count")
|
| 166 |
with gr.Column():
|
| 167 |
gr.Markdown("### 🕰️ 選擇時段 Time Slot")
|
| 168 |
status_box = gr.Markdown("請先選擇日期...", visible=True)
|
| 169 |
time_slot = gr.Dropdown(choices=[], label="可用時段 Available Time", interactive=True)
|
| 170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
gr.HTML("<div style='height: 10px'></div>")
|
| 172 |
gr.Markdown("### 👤 聯絡人資料 Contact,收到確認 E-Mail 並點擊 確認出席 才算訂位成功")
|
| 173 |
with gr.Group():
|
|
|
|
| 25 |
# --- 3. 輔助函式 ---
|
| 26 |
def get_date_options():
|
| 27 |
options = []
|
| 28 |
+
# 這裡的 TAIPEI_TZ 會在函式被呼叫時重新取得當下時間
|
| 29 |
today = datetime.now(TAIPEI_TZ)
|
| 30 |
weekdays = ["(一)", "(二)", "(三)", "(四)", "(五)", "(六)", "(日)"]
|
| 31 |
for i in range(30):
|
|
|
|
| 58 |
|
| 59 |
return gr.update(choices=slots, value=slots[0] if slots else None), status_msg
|
| 60 |
|
| 61 |
+
# --- [新增] 初始化 UI 的函式 (解決日期過期問題) ---
|
| 62 |
+
def init_ui():
|
| 63 |
+
"""
|
| 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 與 處理訂位) ---
|
| 84 |
def get_line_id_from_url(request: gr.Request):
|
| 85 |
if request:
|
|
|
|
| 131 |
except Exception as e: return f"❌ 系統錯誤: {str(e)}"
|
| 132 |
|
| 133 |
# --- 5. Webhook (確認/取消 + 回傳轉址 URL) ---
|
|
|
|
| 134 |
def check_confirmation(request: gr.Request):
|
| 135 |
if not request: return ""
|
| 136 |
action = request.query_params.get('action')
|
|
|
|
| 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 |
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():
|
| 190 |
gr.Markdown("### 🕰️ 選擇時段 Time Slot")
|
| 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>")
|
| 199 |
gr.Markdown("### 👤 聯絡人資料 Contact,收到確認 E-Mail 並點擊 確認出席 才算訂位成功")
|
| 200 |
with gr.Group():
|