Spaces:
Running
Running
| import gradio as gr | |
| from datetime import datetime, timedelta | |
| # --- 1. 主題配色 --- | |
| theme = gr.themes.Soft( | |
| primary_hue="amber", | |
| neutral_hue="zinc", | |
| font=[gr.themes.GoogleFont("Playfair Display"), "ui-sans-serif", "sans-serif"], | |
| ).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", | |
| ) | |
| # --- 2. CSS --- | |
| custom_css = """ | |
| /* 隱藏 Gradio 原生 footer */ | |
| 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, .options .item { | |
| color: #E0E0E0 !important; | |
| padding: 8px 12px !important; | |
| } | |
| /* 滑鼠滑過選項 */ | |
| .item:hover, .item.selected, .options .item:hover { | |
| background-color: #d4af37 !important; | |
| color: black !important; | |
| } | |
| /* 輸入框聚焦時的金色光暈 */ | |
| input:focus, .dropdown-trigger:focus-within { | |
| border-color: #d4af37 !important; | |
| box-shadow: 0 0 8px rgba(212, 175, 55, 0.4) !important; | |
| } | |
| /* 標題樣式 */ | |
| h3 { | |
| border-bottom: 1px solid #444; | |
| padding-bottom: 5px; | |
| margin-bottom: 10px; | |
| } | |
| """ | |
| # --- 核心邏輯 --- | |
| def get_date_options(): | |
| options = [] | |
| today = datetime.now() | |
| weekdays = ["(一)", "(二)", "(三)", "(四)", "(五)", "(六)", "(日)"] | |
| for i in range(30): | |
| current_date = today + timedelta(days=i) | |
| date_str = f"{current_date.strftime('%Y-%m-%d')} {weekdays[current_date.weekday()]}" | |
| options.append(date_str) | |
| return options | |
| def update_time_slots(date_str): | |
| if not date_str: | |
| return gr.update(choices=[]), "請先選擇日期" | |
| try: | |
| clean_date_str = date_str.split(" ")[0] | |
| date_obj = datetime.strptime(clean_date_str, "%Y-%m-%d") | |
| weekday = date_obj.weekday() | |
| except: | |
| return gr.update(choices=[]), "日期格式錯誤" | |
| slots = ["18:00", "18:30", "19:00", "19:30", "20:00", "20:30", | |
| "21:00", "21:30", "22:00", "22:30", "23:00", "23:30", | |
| "00:00", "00:30", "01:00"] | |
| if weekday == 4 or weekday == 5: | |
| slots.extend(["01:30", "02:00", "02:30"]) | |
| status_msg = f"✨ 已選擇 {date_str} (週末營業至 03:00)" | |
| else: | |
| slots.extend(["01:30"]) | |
| status_msg = f"🌙 已選擇 {date_str} (平日營業至 02:00)" | |
| return gr.update(choices=slots, value=slots[0] if slots else None), status_msg | |
| def handle_booking(name, tel, date_str, time, pax): | |
| if not name or not tel or not date_str or not time: | |
| return "⚠️ 請完整填寫所有欄位" | |
| return f""" | |
| <div style='text-align: center; color: #fff; padding: 20px; border: 1px solid #d4af37; border-radius: 8px; background: #222;'> | |
| <h2 style='color: #d4af37; margin: 0;'>Request Received</h2> | |
| <p style='margin: 10px 0;'>🥂 預約申請已提交</p> | |
| <p style='font-size: 0.9em; color: #aaa;'>系統將發送確認信至您的信箱。</p> | |
| </div> | |
| """ | |
| # --- 介面佈局 --- | |
| with gr.Blocks(theme=theme, css=custom_css, title="Booking") as demo: | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("### 📅 預約資訊 Booking Info") | |
| date_options = get_date_options() | |
| booking_date = gr.Dropdown(choices=date_options, label="選擇日期 Select Date", interactive=True) | |
| pax_count = gr.Slider(minimum=1, maximum=10, value=2, step=1, label="用餐人數 Guest Count") | |
| with gr.Column(): | |
| gr.Markdown("### 🕰️ 選擇時段 Time Slot") | |
| status_box = gr.Markdown("請先選擇日期...", visible=True) | |
| time_slot = gr.Dropdown(choices=[], label="可用時段 Available Time", interactive=True) | |
| gr.HTML("<div style='height: 20px'></div>") | |
| gr.Markdown("### 👤 聯絡人資料 Contact") | |
| with gr.Group(): | |
| with gr.Row(): | |
| cust_name = gr.Textbox(label="訂位姓名 Name", placeholder="ex. 王小明") | |
| cust_tel = gr.Textbox(label="手機號碼 Phone", placeholder="ex. 0912-xxx-xxx") | |
| gr.HTML("<div style='height: 20px'></div>") | |
| submit_btn = gr.Button("確認預約 Request Booking", size="lg", variant="primary") | |
| output_msg = gr.HTML(label="系統訊息") | |
| # --- 新增的頁尾宣告區 --- | |
| gr.HTML(""" | |
| <div style="text-align: center; margin-top: 50px; padding-top: 20px; border-top: 1px solid #333; color: #666; font-size: 0.8rem; line-height: 1.6;"> | |
| <p>© 2026 CIE CIE TAIPEI. All Rights Reserved.</p> | |
| <p style="margin-top: 5px; color: #888;">內容涉及酒類產品訊息,請勿轉發分享給未達法定購買年齡者;未滿十八歲請勿飲酒。<br>喝酒不開車,開車不喝酒。</p> | |
| </div> | |
| """) | |
| booking_date.change(update_time_slots, inputs=booking_date, outputs=[time_slot, status_box]) | |
| submit_btn.click(handle_booking, inputs=[cust_name, cust_tel, booking_date, time_slot, pax_count], outputs=output_msg) | |
| if __name__ == "__main__": | |
| demo.launch() |