Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
-
from datetime import datetime
|
| 3 |
|
| 4 |
-
# --- 設定主題配色 (
|
| 5 |
theme = gr.themes.Soft(
|
| 6 |
primary_hue="amber",
|
| 7 |
neutral_hue="zinc",
|
|
@@ -12,7 +12,7 @@ theme = gr.themes.Soft(
|
|
| 12 |
block_border_width="0px",
|
| 13 |
input_background_fill="#333333",
|
| 14 |
input_border_color="#444444",
|
| 15 |
-
body_text_color="#E0E0E0",
|
| 16 |
block_title_text_color="#d4af37",
|
| 17 |
button_primary_background_fill="#d4af37",
|
| 18 |
button_primary_text_color="#000000",
|
|
@@ -24,17 +24,37 @@ footer {visibility: hidden}
|
|
| 24 |
.header-box { text-align: center; padding: 30px 0; margin-bottom: 20px; border-bottom: 1px solid #d4af37; }
|
| 25 |
.header-title { font-family: 'Playfair Display', serif; font-size: 42px; color: #d4af37; letter-spacing: 3px; margin: 0; }
|
| 26 |
.header-subtitle { font-family: sans-serif; color: #888; font-size: 14px; margin-top: 10px; letter-spacing: 1px; }
|
| 27 |
-
|
|
|
|
| 28 |
"""
|
| 29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
# --- 核心邏輯:動態計算時段 ---
|
| 31 |
-
def update_time_slots(
|
| 32 |
-
if
|
| 33 |
return gr.update(choices=[]), "請先選擇日期"
|
| 34 |
|
| 35 |
-
#
|
| 36 |
-
|
| 37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
# 基礎時段 (每天都有)
|
| 39 |
slots = ["18:00", "18:30", "19:00", "19:30", "20:00", "20:30",
|
| 40 |
"21:00", "21:30", "22:00", "22:30", "23:00", "23:30",
|
|
@@ -43,35 +63,30 @@ def update_time_slots(date_obj):
|
|
| 43 |
# 判斷營業時間
|
| 44 |
if weekday == 4 or weekday == 5:
|
| 45 |
# --- 週五 (4) 與 週六 (5) ---
|
| 46 |
-
# 營業到 03:00,最後訂位開放到 02:00 或 02:30
|
| 47 |
slots.extend(["01:30", "02:00", "02:30"])
|
| 48 |
-
status_msg = f"📅 選擇了 {
|
| 49 |
else:
|
| 50 |
# --- 週日 到 週四 ---
|
| 51 |
-
# 營業到 02:00,最後訂位開放到 01:00 或 01:30
|
| 52 |
slots.extend(["01:30"])
|
| 53 |
-
status_msg = f"📅 選擇了 {
|
| 54 |
|
| 55 |
-
return gr.update(choices=slots, value=slots[0]), status_msg
|
| 56 |
|
| 57 |
# --- 模擬寫入資料 ---
|
| 58 |
-
def handle_booking(name, tel,
|
| 59 |
-
if not name or not tel or not
|
| 60 |
-
return "⚠️ 請完整填寫所有欄位
|
| 61 |
-
|
| 62 |
-
# 這裡格式化一下顯示的日期
|
| 63 |
-
date_str = date.strftime("%Y-%m-%d")
|
| 64 |
|
| 65 |
return f"""
|
| 66 |
<div style='background: #2a2a2a; padding: 20px; border-left: 3px solid #d4af37; color: #fff;'>
|
| 67 |
<h3 style='color: #d4af37; margin:0;'>🥂 預約申請已提交</h3>
|
| 68 |
-
<
|
| 69 |
-
<ul style='color: #ccc;'>
|
| 70 |
<li>日期:{date_str}</li>
|
| 71 |
<li>時間:{time}</li>
|
| 72 |
<li>人數:{pax} 位</li>
|
|
|
|
| 73 |
</ul>
|
| 74 |
-
<p>系統將發送確認信至您的信箱,請留意查收。</p>
|
| 75 |
</div>
|
| 76 |
"""
|
| 77 |
|
|
@@ -88,8 +103,15 @@ with gr.Blocks(theme=theme, css=custom_css, title="Cié Ci�� Taipei") as demo:
|
|
| 88 |
with gr.Row():
|
| 89 |
with gr.Column(scale=1):
|
| 90 |
gr.Markdown("### 📅 預約資訊")
|
| 91 |
-
|
| 92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
|
| 94 |
pax_count = gr.Slider(minimum=1, maximum=10, value=2, step=1, label="用餐人數",
|
| 95 |
info="超過 10 人請直接來電")
|
|
@@ -109,13 +131,16 @@ with gr.Blocks(theme=theme, css=custom_css, title="Cié Cié Taipei") as demo:
|
|
| 109 |
output_msg = gr.HTML(label="系統訊息")
|
| 110 |
|
| 111 |
# --- 互動邏輯 ---
|
| 112 |
-
#
|
| 113 |
booking_date.change(
|
| 114 |
fn=update_time_slots,
|
| 115 |
inputs=booking_date,
|
| 116 |
outputs=[time_slot, status_box]
|
| 117 |
)
|
| 118 |
|
|
|
|
|
|
|
|
|
|
| 119 |
submit_btn.click(
|
| 120 |
handle_booking,
|
| 121 |
inputs=[cust_name, cust_tel, booking_date, time_slot, pax_count],
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
+
from datetime import datetime, timedelta
|
| 3 |
|
| 4 |
+
# --- 設定主題配色 (維持之前的黑金高級感) ---
|
| 5 |
theme = gr.themes.Soft(
|
| 6 |
primary_hue="amber",
|
| 7 |
neutral_hue="zinc",
|
|
|
|
| 12 |
block_border_width="0px",
|
| 13 |
input_background_fill="#333333",
|
| 14 |
input_border_color="#444444",
|
| 15 |
+
body_text_color="#E0E0E0",
|
| 16 |
block_title_text_color="#d4af37",
|
| 17 |
button_primary_background_fill="#d4af37",
|
| 18 |
button_primary_text_color="#000000",
|
|
|
|
| 24 |
.header-box { text-align: center; padding: 30px 0; margin-bottom: 20px; border-bottom: 1px solid #d4af37; }
|
| 25 |
.header-title { font-family: 'Playfair Display', serif; font-size: 42px; color: #d4af37; letter-spacing: 3px; margin: 0; }
|
| 26 |
.header-subtitle { font-family: sans-serif; color: #888; font-size: 14px; margin-top: 10px; letter-spacing: 1px; }
|
| 27 |
+
/* 強制讓下拉選單的選項背景也是深色 (避免展開時變白) */
|
| 28 |
+
.wrap { background-color: #262626 !important; }
|
| 29 |
"""
|
| 30 |
|
| 31 |
+
# --- 核心邏輯:產生未來 30 天的日期選項 ---
|
| 32 |
+
def get_date_options():
|
| 33 |
+
options = []
|
| 34 |
+
today = datetime.now()
|
| 35 |
+
weekdays = ["(一)", "(二)", "(三)", "(四)", "(五)", "(六)", "(日)"]
|
| 36 |
+
|
| 37 |
+
for i in range(30): # 開放未來 30 天
|
| 38 |
+
current_date = today + timedelta(days=i)
|
| 39 |
+
# 格式:2026-01-16 (五)
|
| 40 |
+
date_str = f"{current_date.strftime('%Y-%m-%d')} {weekdays[current_date.weekday()]}"
|
| 41 |
+
options.append(date_str)
|
| 42 |
+
return options
|
| 43 |
+
|
| 44 |
# --- 核心邏輯:動態計算時段 ---
|
| 45 |
+
def update_time_slots(date_str):
|
| 46 |
+
if not date_str:
|
| 47 |
return gr.update(choices=[]), "請先選擇日期"
|
| 48 |
|
| 49 |
+
# 解析日期字串,例如 "2026-01-16 (五)" -> 找出星期幾
|
| 50 |
+
# 我們可以直接看括號裡的字,或是重新 parse 日期,這裡用 parse 比較穩
|
| 51 |
+
try:
|
| 52 |
+
clean_date_str = date_str.split(" ")[0] # 拿掉後面的 (五)
|
| 53 |
+
date_obj = datetime.strptime(clean_date_str, "%Y-%m-%d")
|
| 54 |
+
weekday = date_obj.weekday() # 0=週一, ... 4=週五, 5=週六
|
| 55 |
+
except:
|
| 56 |
+
return gr.update(choices=[]), "日期格式錯誤"
|
| 57 |
+
|
| 58 |
# 基礎時段 (每天都有)
|
| 59 |
slots = ["18:00", "18:30", "19:00", "19:30", "20:00", "20:30",
|
| 60 |
"21:00", "21:30", "22:00", "22:30", "23:00", "23:30",
|
|
|
|
| 63 |
# 判斷營業時間
|
| 64 |
if weekday == 4 or weekday == 5:
|
| 65 |
# --- 週五 (4) 與 週六 (5) ---
|
|
|
|
| 66 |
slots.extend(["01:30", "02:00", "02:30"])
|
| 67 |
+
status_msg = f"📅 選擇了 {date_str} (週末時段 營業至 03:00)"
|
| 68 |
else:
|
| 69 |
# --- 週日 到 週四 ---
|
|
|
|
| 70 |
slots.extend(["01:30"])
|
| 71 |
+
status_msg = f"📅 選擇了 {date_str} (平日時段 營業至 02:00)"
|
| 72 |
|
| 73 |
+
return gr.update(choices=slots, value=slots[0] if slots else None), status_msg
|
| 74 |
|
| 75 |
# --- 模擬寫入資料 ---
|
| 76 |
+
def handle_booking(name, tel, date_str, time, pax):
|
| 77 |
+
if not name or not tel or not date_str or not time:
|
| 78 |
+
return "⚠️ 請完整填寫所有欄位"
|
|
|
|
|
|
|
|
|
|
| 79 |
|
| 80 |
return f"""
|
| 81 |
<div style='background: #2a2a2a; padding: 20px; border-left: 3px solid #d4af37; color: #fff;'>
|
| 82 |
<h3 style='color: #d4af37; margin:0;'>🥂 預約申請已提交</h3>
|
| 83 |
+
<ul style='color: #ccc; list-style: none; padding: 0;'>
|
|
|
|
| 84 |
<li>日期:{date_str}</li>
|
| 85 |
<li>時間:{time}</li>
|
| 86 |
<li>人數:{pax} 位</li>
|
| 87 |
+
<li>貴賓:{name} ({tel})</li>
|
| 88 |
</ul>
|
| 89 |
+
<p style='font-size: 0.9em; color: #888;'>系統將發送確認信至您的信箱,請留意查收。</p>
|
| 90 |
</div>
|
| 91 |
"""
|
| 92 |
|
|
|
|
| 103 |
with gr.Row():
|
| 104 |
with gr.Column(scale=1):
|
| 105 |
gr.Markdown("### 📅 預約資訊")
|
| 106 |
+
|
| 107 |
+
# 🌟 修正重點:改用 Dropdown,並預先填入未來 30 天的選項
|
| 108 |
+
date_options = get_date_options()
|
| 109 |
+
booking_date = gr.Dropdown(
|
| 110 |
+
choices=date_options,
|
| 111 |
+
label="選擇日期 (未來 30 天)",
|
| 112 |
+
value=date_options[0] if date_options else None,
|
| 113 |
+
interactive=True
|
| 114 |
+
)
|
| 115 |
|
| 116 |
pax_count = gr.Slider(minimum=1, maximum=10, value=2, step=1, label="用餐人數",
|
| 117 |
info="超過 10 人請直接來電")
|
|
|
|
| 131 |
output_msg = gr.HTML(label="系統訊息")
|
| 132 |
|
| 133 |
# --- 互動邏輯 ---
|
| 134 |
+
# 當「日期選單」改變時,觸發更新
|
| 135 |
booking_date.change(
|
| 136 |
fn=update_time_slots,
|
| 137 |
inputs=booking_date,
|
| 138 |
outputs=[time_slot, status_box]
|
| 139 |
)
|
| 140 |
|
| 141 |
+
# 頁面載入時,自動觸發一次 (讓時段選單有預設值)
|
| 142 |
+
demo.load(fn=update_time_slots, inputs=booking_date, outputs=[time_slot, status_box])
|
| 143 |
+
|
| 144 |
submit_btn.click(
|
| 145 |
handle_booking,
|
| 146 |
inputs=[cust_name, cust_tel, booking_date, time_slot, pax_count],
|