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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -45
app.py CHANGED
@@ -22,6 +22,7 @@ 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
  try:
26
  res = supabase.table("bookings").select("*").order("created_at", desc=True).execute()
27
  if not res.data: return pd.DataFrame()
@@ -89,13 +90,17 @@ def send_confirmation_hybrid(booking_id):
89
  return log_msg
90
  except Exception as e: return f"Error: {e}"
91
 
92
- # 🔥🔥🔥 3.0 版卡片:標籤化 + 大字體 + 重發功能 🔥🔥🔥
93
  def render_booking_cards():
94
  df = get_bookings()
 
 
 
 
95
  if df.empty:
96
- return "<div style='text-align:center; padding:60px; color:#666; font-size:1.2em;'>📭 目前沒有訂位資料</div>"
97
 
98
- cards_html = "<div style='display: flex; flex-direction: column; gap: 20px; padding-bottom: 80px;'>"
99
 
100
  for index, row in df.iterrows():
101
  # 狀態邏輯
@@ -131,71 +136,79 @@ def render_booking_cards():
131
  <div class="booking-card" style="
132
  background: #1e1e1e;
133
  border-left: 6px solid {border_color};
134
- border-radius: 10px;
135
- padding: 20px;
136
  box-shadow: 0 6px 16px rgba(0,0,0,0.4);
137
  font-family: 'Segoe UI', Roboto, sans-serif;
138
  position: relative;">
139
 
140
- <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:15px; border-bottom:1px solid #333; padding-bottom:10px;">
141
- <div style="font-size:1.1em; color:#d4af37; font-weight:600;">
142
- <span style="font-size:0.8em; color:#888; margin-right:5px;">📅 日期</span> {row['date']}
143
  </div>
144
  <div style="
145
  color: {status_color};
146
  background: {status_color}1a;
147
- padding: 4px 12px;
148
  border-radius: 20px;
149
- font-size: 0.85em;
150
  font-weight: bold;
151
  letter-spacing: 1px;">
152
  {status}
153
  </div>
154
  </div>
155
 
156
- <div style="display:grid; grid-template-columns: 1fr 1fr; gap:15px; margin-bottom:15px;">
157
  <div>
158
- <div style="font-size:0.8em; color:#666; margin-bottom:2px;">⏰ 訂位時間</div>
159
- <div style="font-size:1.6em; color:#fff; font-weight:800; font-family:monospace;">{row['time']}</div>
160
  </div>
161
  <div>
162
- <div style="font-size:0.8em; color:#666; margin-bottom:2px;">👥 人數</div>
163
- <div style="font-size:1.6em; color:#fff; font-weight:800;">{row['pax']} <span style="font-size:0.5em; font-weight:400; color:#888;">位</span></div>
164
  </div>
165
  </div>
166
 
167
- <div style="background:#262626; padding:15px; border-radius:8px; margin-bottom:15px;">
168
- <div style="margin-bottom:8px;">
169
- <span style="color:#888; font-size:0.85em; display:inline-block; width:40px;">姓名</span>
170
- <span style="color:#eee; font-size:1.1em; font-weight:600;">{row['name']}</span>
171
  </div>
172
- <div style="margin-bottom:8px;">
173
- <span style="color:#888; font-size:0.85em; display:inline-block; width:40px;">電話</span>
174
- <a href="tel:{row['tel']}" style="color:#4dabf7; text-decoration:none; font-size:1.05em; letter-spacing:0.5px;">{row['tel']}</a>
175
  </div>
176
  <div>
177
- <span style="color:#888; font-size:0.85em; display:inline-block; width:40px;">信箱</span>
178
- <span style="color:#aaa; font-size:0.95em;">{row['email'] or '未提供'}</span>
179
  </div>
180
  </div>
181
 
182
  <div style="margin-bottom:20px;">
183
- <div style="font-size:0.8em; color:#888; margin-bottom:4px;">📝 備註事項</div>
184
- <div style="color:#d4af37; background:#d4af371a; padding:10px; border-radius:6px; font-size:0.95em; line-height:1.5;">
185
  {row.get('remarks') or '無特別備註'}
186
  </div>
187
  </div>
188
 
189
- <div style="display:flex; justify-content:space-between; align-items:center; border-top:1px solid #333; padding-top:15px;">
190
- <span style="font-size:0.75em; color:#444; font-family:monospace;">ID: {row['id']}</span>
 
 
 
 
 
 
 
 
191
 
192
  <button onclick="{btn_onclick}" style="
193
  border: none;
194
- padding: 10px 24px;
195
- border-radius: 6px;
196
- font-size: 0.95em;
197
  transition: all 0.2s;
198
- width: 140px;
199
  {btn_style}">
200
  {btn_text}
201
  </button>
@@ -237,32 +250,33 @@ function() {
237
  }
238
  """
239
 
240
- # --- CSS 優化 (修復 elem_style 錯誤) ---
241
- # 把原本 inline 的 elem_style 移到這裡的 header-panel
242
  custom_css = """
243
  body, .gradio-container { background-color: #0F0F0F; color: #fff; }
244
 
245
- /* 讓卡片容器可以滾動但隱藏捲軸 */
246
  #booking_display {
247
  max-height: 85vh;
248
  overflow-y: auto;
249
  padding-right: 5px;
250
  }
251
- #booking_display::-webkit-scrollbar { width: 4px; }
252
- #booking_display::-webkit-scrollbar-thumb { background: #444; border-radius: 4px; }
 
 
253
  button:active { transform: scale(0.98); }
254
 
255
  /* Header Panel 樣式 */
256
  #header-panel {
257
  background: #1a1a1a;
258
  border: none;
259
- padding: 10px;
260
  margin-bottom: 20px;
 
261
  }
262
  """
263
 
264
  # --- 介面 ---
265
- # ⚠️ 注意:css 參數從 Blocks 移到 launch
266
  with gr.Blocks(title="Admin") as demo:
267
 
268
  # 1. 登入
@@ -276,7 +290,6 @@ with gr.Blocks(title="Admin") as demo:
276
 
277
  # 2. 後台
278
  with gr.Group(visible=False) as admin_row:
279
- # 修正:移除 elem_style,改用 elem_id
280
  with gr.Row(variant="panel", elem_id="header-panel"):
281
  gr.Markdown("### 🍷 Cié Cié Dashboard")
282
  refresh_btn = gr.Button("🔄 刷新列表", size="sm", variant="secondary")
@@ -298,7 +311,6 @@ with gr.Blocks(title="Admin") as demo:
298
 
299
  refresh_btn.click(render_booking_cards, outputs=booking_display)
300
 
301
- # 點擊卡片 -> 發�� -> 刷新卡片
302
  hidden_send_btn.click(
303
  send_confirmation_hybrid,
304
  inputs=hidden_id_input,
@@ -308,9 +320,8 @@ with gr.Blocks(title="Admin") as demo:
308
  outputs=booking_display
309
  )
310
 
311
- # 載入 JS
312
- demo.load(None, js=js_logic)
313
 
314
  if __name__ == "__main__":
315
- # ⚠️ 修正:將 css 參數移至 launch()
316
- demo.launch(css=custom_css)
 
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
  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
  # 狀態邏輯
 
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
  }
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;
276
  }
277
  """
278
 
279
  # --- 介面 ---
 
280
  with gr.Blocks(title="Admin") as demo:
281
 
282
  # 1. 登入
 
290
 
291
  # 2. 後台
292
  with gr.Group(visible=False) as admin_row:
 
293
  with gr.Row(variant="panel", elem_id="header-panel"):
294
  gr.Markdown("### 🍷 Cié Cié Dashboard")
295
  refresh_btn = gr.Button("🔄 刷新列表", size="sm", variant="secondary")
 
311
 
312
  refresh_btn.click(render_booking_cards, outputs=booking_display)
313
 
 
314
  hidden_send_btn.click(
315
  send_confirmation_hybrid,
316
  inputs=hidden_id_input,
 
320
  outputs=booking_display
321
  )
322
 
323
+ # 載入 JS 與 CSS
324
+ demo.launch(css=custom_css, js=js_logic)
325
 
326
  if __name__ == "__main__":
327
+ demo.launch()