DeepLearning101 commited on
Commit
169b49f
·
verified ·
1 Parent(s): 5a5ae27

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +75 -67
app.py CHANGED
@@ -22,7 +22,6 @@ REAL_ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD") or "2016-11-11"
22
  supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
23
 
24
  def get_bookings():
25
- # 這裡抓取所有資料,沒有設限制
26
  try:
27
  res = supabase.table("bookings").select("*").order("created_at", desc=True).execute()
28
  if not res.data: return pd.DataFrame()
@@ -90,35 +89,33 @@ def send_confirmation_hybrid(booking_id):
90
  return log_msg
91
  except Exception as e: return f"Error: {e}"
92
 
93
- # 🔥🔥🔥 3.1 版卡片:大字體 + 高對比 ID + 標題計數 🔥🔥🔥
94
  def render_booking_cards():
95
  df = get_bookings()
96
 
97
- # 在標題顯示總筆數,方便您確認是否抓漏了
98
- count_html = f"<div style='color:#888; margin-bottom:10px; text-align:right;'>共找到 {len(df)} 筆訂位資料</div>"
99
 
100
  if df.empty:
101
- return f"{count_html}<div style='text-align:center; padding:60px; color:#666; font-size:1.2em;'>📭 目前沒有訂位資料</div>"
102
 
103
- cards_html = f"{count_html}<div style='display: flex; flex-direction: column; gap: 20px; padding-bottom: 80px;'>"
 
104
 
105
  for index, row in df.iterrows():
106
- # 狀態邏輯
107
  status = row.get('status', '待處理')
108
  status_color = "#ccc"
109
  border_color = "#444"
110
 
111
  if '確認' in status:
112
- status_color = "#2ecc71" # 綠
113
  border_color = "#2ecc71"
114
  elif '取消' in status:
115
- status_color = "#e74c3c" # 紅
116
  border_color = "#e74c3c"
117
  elif '已發' in status:
118
- status_color = "#f1c40f" # 黃
119
  border_color = "#f1c40f"
120
 
121
- # 按鈕邏輯
122
  is_canceled = '取消' in status
123
  btn_onclick = "" if is_canceled else f"cardAction({row['id']})"
124
 
@@ -126,89 +123,93 @@ def render_booking_cards():
126
  btn_style = "background: #333; color: #666; cursor: not-allowed;"
127
  btn_text = "🚫 已取消"
128
  elif '已發' in status or '確認' in status:
129
- btn_style = "background: #2c3e50; color: #fff; border: 1px solid #555; hover:background:#34495e;"
130
  btn_text = "🔄 重發確認"
131
  else:
132
- btn_style = "background: #d4af37; color: #000; font-weight:bold; box-shadow: 0 4px 10px rgba(212, 175, 55, 0.4);"
133
  btn_text = "🚀 發送確認"
134
 
135
  card = f"""
136
  <div class="booking-card" style="
137
- background: #1e1e1e;
138
- border-left: 6px solid {border_color};
139
  border-radius: 12px;
140
- padding: 22px;
141
- box-shadow: 0 6px 16px rgba(0,0,0,0.4);
142
- font-family: 'Segoe UI', Roboto, sans-serif;
143
- position: relative;">
 
144
 
145
- <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:18px; border-bottom:1px solid #333; padding-bottom:12px;">
146
- <div style="font-size:1.2em; color:#d4af37; font-weight:600;">
147
- <span style="font-size:0.75em; color:#888; margin-right:5px; font-weight:normal;">📅 日期</span> {row['date']}
148
  </div>
149
  <div style="
150
  color: {status_color};
151
- background: {status_color}1a;
152
- padding: 6px 14px;
153
- border-radius: 20px;
154
- font-size: 0.9em;
155
  font-weight: bold;
156
- letter-spacing: 1px;">
 
157
  {status}
158
  </div>
159
  </div>
160
 
161
- <div style="display:grid; grid-template-columns: 1fr 1fr; gap:15px; margin-bottom:20px;">
162
  <div>
163
- <div style="font-size:0.9em; color:#666; margin-bottom:4px;">⏰ 訂位時間</div>
164
- <div style="font-size:1.8em; color:#fff; font-weight:800; font-family:monospace; letter-spacing:-1px;">{row['time']}</div>
165
  </div>
166
  <div>
167
- <div style="font-size:0.9em; color:#666; margin-bottom:4px;">👥 人數</div>
168
- <div style="font-size:1.8em; color:#fff; font-weight:800;">{row['pax']} <span style="font-size:0.5em; font-weight:400; color:#888;">位</span></div>
169
  </div>
170
  </div>
171
 
172
- <div style="background:#262626; padding:18px; border-radius:10px; margin-bottom:18px;">
173
- <div style="margin-bottom:12px;">
174
- <span style="color:#666; font-size:0.9em; display:block; margin-bottom:2px;">👤 姓名 Name</span>
175
- <span style="color:#eee; font-size:1.3em; font-weight:700;">{row['name']}</span>
176
  </div>
177
- <div style="margin-bottom:12px;">
178
- <span style="color:#666; font-size:0.9em; display:block; margin-bottom:2px;">📞 電話 Phone</span>
179
- <a href="tel:{row['tel']}" style="color:#4dabf7; text-decoration:none; font-size:1.2em; letter-spacing:0.5px; font-weight:500;">{row['tel']}</a>
180
  </div>
181
  <div>
182
- <span style="color:#666; font-size:0.9em; display:block; margin-bottom:2px;">✉️ 信箱 Email</span>
183
- <span style="color:#ccc; font-size:1.1em; word-break:break-all;">{row['email'] or '未提供'}</span>
184
  </div>
185
  </div>
186
 
187
- <div style="margin-bottom:20px;">
188
- <div style="font-size:0.9em; color:#888; margin-bottom:6px;">📝 備註事項 Note</div>
189
- <div style="color:#d4af37; background:#d4af371a; padding:12px; border-radius:8px; font-size:1.0em; line-height:1.5;">
190
- {row.get('remarks') or '無特別備註'}
191
  </div>
192
  </div>
193
 
194
- <div style="display:flex; justify-content:space-between; align-items:center; border-top:1px solid #333; padding-top:18px;">
195
- <span style="
196
- font-size: 0.85em;
197
- color: #aaa;
198
- font-family: monospace;
199
- background: #333;
200
- padding: 4px 8px;
201
- border-radius: 4px;">
 
202
  ID: {row['id']}
203
- </span>
204
 
205
  <button onclick="{btn_onclick}" style="
206
  border: none;
207
- padding: 12px 28px;
208
  border-radius: 8px;
209
- font-size: 1em;
210
  transition: all 0.2s;
211
- min-width: 140px;
 
212
  {btn_style}">
213
  {btn_text}
214
  </button>
@@ -250,26 +251,33 @@ function() {
250
  }
251
  """
252
 
253
- # --- CSS (樣式全放在這) ---
254
  custom_css = """
255
  body, .gradio-container { background-color: #0F0F0F; color: #fff; }
256
 
257
- /* 捲軸美化 */
 
258
  #booking_display {
259
- max-height: 85vh;
260
- overflow-y: auto;
261
- padding-right: 5px;
 
 
 
 
262
  }
263
- #booking_display::-webkit-scrollbar { width: 6px; }
264
- #booking_display::-webkit-scrollbar-thumb { background: #555; border-radius: 4px; }
 
 
265
  #booking_display::-webkit-scrollbar-track { background: #222; }
266
 
267
- button:active { transform: scale(0.98); }
 
268
 
269
  /* Header Panel 樣式 */
270
  #header-panel {
271
  background: #1a1a1a;
272
- border: none;
273
  padding: 15px;
274
  margin-bottom: 20px;
275
  border-radius: 10px;
@@ -302,7 +310,7 @@ with gr.Blocks(title="Admin") as demo:
302
  hidden_id_input = gr.Number(elem_id="hidden_id_input", precision=0)
303
  hidden_send_btn = gr.Button("Send", elem_id="hidden_send_btn")
304
 
305
- log_output = gr.Textbox(label="系統日誌", lines=1, interactive=False)
306
 
307
  # 綁定事件
308
  login_btn.click(check_login, inputs=[username_input, password_input], outputs=[login_row, admin_row, error_msg]).then(
 
22
  supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
23
 
24
  def get_bookings():
 
25
  try:
26
  res = supabase.table("bookings").select("*").order("created_at", desc=True).execute()
27
  if not res.data: return pd.DataFrame()
 
89
  return log_msg
90
  except Exception as e: return f"Error: {e}"
91
 
92
+ # 🔥🔥🔥 3.2 版卡片:解決截斷問題 + 字體特大號 🔥🔥🔥
93
  def render_booking_cards():
94
  df = get_bookings()
95
 
96
+ count_html = f"<div style='color:#bbb; margin-bottom:15px; text-align:right; font-size:16px;'>📊 共找到 <span style='color:#fff; font-weight:bold;'>{len(df)}</span> 筆資料</div>"
 
97
 
98
  if df.empty:
99
+ return f"{count_html}<div style='text-align:center; padding:60px; color:#666; font-size:1.5em;'>📭 目前沒有訂位資料</div>"
100
 
101
+ # 這裡 padding-bottom 設為 120px,確保最後一張卡片不會被捲軸切掉
102
+ cards_html = f"{count_html}<div style='display: flex; flex-direction: column; gap: 24px; padding-bottom: 150px;'>"
103
 
104
  for index, row in df.iterrows():
 
105
  status = row.get('status', '待處理')
106
  status_color = "#ccc"
107
  border_color = "#444"
108
 
109
  if '確認' in status:
110
+ status_color = "#2ecc71"
111
  border_color = "#2ecc71"
112
  elif '取消' in status:
113
+ status_color = "#e74c3c"
114
  border_color = "#e74c3c"
115
  elif '已發' in status:
116
+ status_color = "#f1c40f"
117
  border_color = "#f1c40f"
118
 
 
119
  is_canceled = '取消' in status
120
  btn_onclick = "" if is_canceled else f"cardAction({row['id']})"
121
 
 
123
  btn_style = "background: #333; color: #666; cursor: not-allowed;"
124
  btn_text = "🚫 已取消"
125
  elif '已發' in status or '確認' in status:
126
+ btn_style = "background: #2c3e50; color: #fff; border: 1px solid #555;"
127
  btn_text = "🔄 重發確認"
128
  else:
129
+ btn_style = "background: #d4af37; color: #000; font-weight:800; box-shadow: 0 4px 12px rgba(212, 175, 55, 0.5);"
130
  btn_text = "🚀 發送確認"
131
 
132
  card = f"""
133
  <div class="booking-card" style="
134
+ background: #1a1a1a;
135
+ border-left: 8px solid {border_color};
136
  border-radius: 12px;
137
+ padding: 24px;
138
+ box-shadow: 0 8px 20px rgba(0,0,0,0.6);
139
+ font-family: '微軟正黑體', sans-serif;
140
+ position: relative;
141
+ margin-bottom: 5px;">
142
 
143
+ <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px; border-bottom:1px solid #333; padding-bottom:15px;">
144
+ <div style="font-size:1.3em; color:#fff; font-weight:bold;">
145
+ <span style="font-size:0.8em; color:#aaa; margin-right:8px; font-weight:normal;">📅 日期</span>{row['date']}
146
  </div>
147
  <div style="
148
  color: {status_color};
149
+ background: {status_color}22;
150
+ padding: 8px 16px;
151
+ border-radius: 30px;
152
+ font-size: 1em;
153
  font-weight: bold;
154
+ letter-spacing: 1px;
155
+ border: 1px solid {status_color}44;">
156
  {status}
157
  </div>
158
  </div>
159
 
160
+ <div style="display:grid; grid-template-columns: 1fr 1fr; gap:20px; margin-bottom:25px;">
161
  <div>
162
+ <div style="font-size:1em; color:#aaa; margin-bottom:5px;">⏰ 訂位時間</div>
163
+ <div style="font-size:2.2em; color:#d4af37; font-weight:900; letter-spacing:-1px; line-height:1;">{row['time']}</div>
164
  </div>
165
  <div>
166
+ <div style="font-size:1em; color:#aaa; margin-bottom:5px;">👥 人數</div>
167
+ <div style="font-size:2.2em; color:#fff; font-weight:900; line-height:1;">{row['pax']} <span style="font-size:0.5em; font-weight:400; color:#888;">位</span></div>
168
  </div>
169
  </div>
170
 
171
+ <div style="background:#222; padding:20px; border-radius:10px; margin-bottom:20px;">
172
+ <div style="margin-bottom:15px;">
173
+ <span style="color:#bbb; font-size:1em; display:block; margin-bottom:4px; font-weight:bold;">👤 姓名 Name</span>
174
+ <span style="color:#fff; font-size:1.5em; font-weight:bold;">{row['name']}</span>
175
  </div>
176
+ <div style="margin-bottom:15px;">
177
+ <span style="color:#bbb; font-size:1em; display:block; margin-bottom:4px; font-weight:bold;">📞 電話 Phone</span>
178
+ <a href="tel:{row['tel']}" style="color:#69c0ff; text-decoration:none; font-size:1.4em; letter-spacing:1px; font-weight:600; border-bottom: 1px dotted #69c0ff;">{row['tel']}</a>
179
  </div>
180
  <div>
181
+ <span style="color:#bbb; font-size:1em; display:block; margin-bottom:4px; font-weight:bold;">✉️ 信箱 Email</span>
182
+ <span style="color:#ddd; font-size:1.1em; word-break:break-all;">{row['email'] or '未提供'}</span>
183
  </div>
184
  </div>
185
 
186
+ <div style="margin-bottom:25px;">
187
+ <div style="font-size:1em; color:#aaa; margin-bottom:8px;">📝 備註 Note</div>
188
+ <div style="color:#f1c40f; background:#f1c40f11; padding:15px; border-radius:8px; font-size:1.1em; line-height:1.6; border: 1px solid #f1c40f33;">
189
+ {row.get('remarks') or '無'}
190
  </div>
191
  </div>
192
 
193
+ <div style="display:flex; justify-content:space-between; align-items:center; border-top:1px solid #333; padding-top:20px;">
194
+ <div style="
195
+ font-size: 1.1em;
196
+ color: #000;
197
+ font-weight: 900;
198
+ background: #e0e0e0;
199
+ padding: 6px 12px;
200
+ border-radius: 6px;
201
+ font-family: monospace;">
202
  ID: {row['id']}
203
+ </div>
204
 
205
  <button onclick="{btn_onclick}" style="
206
  border: none;
207
+ padding: 14px 30px;
208
  border-radius: 8px;
209
+ font-size: 1.1em;
210
  transition: all 0.2s;
211
+ min-width: 150px;
212
+ cursor: pointer;
213
  {btn_style}">
214
  {btn_text}
215
  </button>
 
251
  }
252
  """
253
 
254
+ # --- CSS (修復捲軸與高度問題) ---
255
  custom_css = """
256
  body, .gradio-container { background-color: #0F0F0F; color: #fff; }
257
 
258
+ /* 🔥 關鍵修正:給容器一個固定高度 (例如 65vh),確保它在頁面內捲動 */
259
+ /* 這樣就不會被下方的 Log 區塊擋住,也不會撐開整個網頁 */
260
  #booking_display {
261
+ height: 65vh; /* 固定高度,約佔螢幕 65% */
262
+ overflow-y: auto; /* 內容太多時顯示垂直捲軸 */
263
+ padding-right: 8px; /* 避免文字貼著捲軸 */
264
+ margin-bottom: 20px;
265
+ border: 1px solid #333;
266
+ border-radius: 8px;
267
+ background-color: #111;
268
  }
269
+
270
+ /* 捲軸美化 */
271
+ #booking_display::-webkit-scrollbar { width: 8px; }
272
+ #booking_display::-webkit-scrollbar-thumb { background: #666; border-radius: 4px; }
273
  #booking_display::-webkit-scrollbar-track { background: #222; }
274
 
275
+ /* 讓按鈕有點擊感 */
276
+ button:active { transform: scale(0.96); }
277
 
278
  /* Header Panel 樣式 */
279
  #header-panel {
280
  background: #1a1a1a;
 
281
  padding: 15px;
282
  margin-bottom: 20px;
283
  border-radius: 10px;
 
310
  hidden_id_input = gr.Number(elem_id="hidden_id_input", precision=0)
311
  hidden_send_btn = gr.Button("Send", elem_id="hidden_send_btn")
312
 
313
+ log_output = gr.Textbox(label="系統日誌 (System Log)", lines=2, interactive=False)
314
 
315
  # 綁定事件
316
  login_btn.click(check_login, inputs=[username_input, password_input], outputs=[login_row, admin_row, error_msg]).then(