Ethscriptions commited on
Commit
9a3e51f
·
verified ·
1 Parent(s): e522499

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +74 -37
app.py CHANGED
@@ -9,6 +9,7 @@ import math
9
  from matplotlib.backends.backend_pdf import PdfPages
10
  from matplotlib.patches import FancyBboxPatch
11
 
 
12
  SPLIT_TIME = "17:30"
13
  BUSINESS_START = "09:30"
14
  BUSINESS_END = "01:30"
@@ -21,8 +22,8 @@ def process_schedule(file):
21
  # 读取 Excel,跳过前 8 行
22
  df = pd.read_excel(file, skiprows=8)
23
 
24
- # 提取所需列 (G9, H9, J9)
25
- df = df.iloc[:, [6, 7, 9]] # G, H, J 列
26
  df.columns = ['Hall', 'StartTime', 'EndTime']
27
 
28
  # 清理数据
@@ -47,25 +48,27 @@ def process_schedule(file):
47
  if business_end < business_start:
48
  business_end += timedelta(days=1)
49
 
50
- # 标准化所有时间到同一天
51
  for idx, row in df.iterrows():
52
  end_time = row['EndTime']
 
53
  if end_time.hour < 9:
54
  df.at[idx, 'EndTime'] = end_time + timedelta(days=1)
55
-
56
- if row['StartTime'].hour >= 21 and end_time.hour < 9:
57
  df.at[idx, 'EndTime'] = end_time + timedelta(days=1)
58
 
59
- # 筛选营业时间内的场次
60
  df['time_for_comparison'] = df['EndTime'].apply(
61
  lambda x: datetime.combine(base_date, x.time())
62
  )
63
-
64
  df.loc[df['time_for_comparison'].dt.hour < 9, 'time_for_comparison'] += timedelta(days=1)
65
 
 
66
  valid_times = (
67
- ((df['time_for_comparison'] >= datetime.combine(base_date, business_start.time())) &
68
- (df['time_for_comparison'] <= datetime.combine(base_date + timedelta(days=1), business_end.time())))
69
  )
70
 
71
  df = df[valid_times]
@@ -74,19 +77,16 @@ def process_schedule(file):
74
  df = df.sort_values('EndTime')
75
 
76
  # 分割数据
77
- split_time = datetime.strptime(f"{base_date} {SPLIT_TIME}", "%Y-%m-%d %H:%M")
78
- split_time_for_comparison = df['time_for_comparison'].apply(
79
- lambda x: datetime.combine(base_date, split_time.time())
80
- )
81
 
82
- part1 = df[df['time_for_comparison'] <= split_time_for_comparison].copy()
83
- part2 = df[df['time_for_comparison'] > split_time_for_comparison].copy()
84
 
85
  # 格式化时间显示
86
  for part in [part1, part2]:
87
  part['EndTime'] = part['EndTime'].dt.strftime('%-H:%M')
88
 
89
- # 关键修改:精确读取C6单元格
90
  date_df = pd.read_excel(
91
  file,
92
  skiprows=5, # 跳过前5行(0-4)
@@ -139,20 +139,15 @@ def create_print_layout(data, title, date_str):
139
 
140
  gs = gridspec.GridSpec(num_rows + 1, num_cols, hspace=0.05, wspace=0.05, height_ratios=[0.1] + [1] * num_rows, figure=fig)
141
 
142
- # --- 新增:预先计算单元格的目标宽度(以像素为单位)---
143
- target_width_px = 1
144
  if total_items > 0:
145
- # 创建一个临时坐标轴来测量其像素宽度
146
  ax_temp = fig.add_subplot(gs[1, 0])
147
- # 必须绘制画布才能使用渲染器并获得几何属性
148
  fig.canvas.draw()
149
- # 获取像素宽度并计算目标宽度(90%)
150
  target_width_px = ax_temp.get_window_extent().width * 0.90
151
- # 移除临时坐标轴
152
  ax_temp.remove()
153
  # --- 预计算结束 ---
154
 
155
- # 此字体大小计算仅用于顶部的日期
156
  available_height_per_row = (8.27 * 0.9 * (1 / 1.2)) / num_rows if num_rows > 0 else 1
157
  date_fontsize = min(40, max(10, available_height_per_row * 72 * 0.5))
158
 
@@ -191,34 +186,28 @@ def create_print_layout(data, title, date_str):
191
 
192
  display_text = f"{hall}{end_time}"
193
 
194
- # --- 修改部分:动态字体大小调整逻辑 ---
195
- # 创建一个文本对象
196
  t = ax.text(0.5, 0.5, display_text,
197
  fontweight='bold', ha='center', va='center',
198
  transform=ax.transAxes)
199
 
200
- # 从一个较大的字号开始,迭代查找最佳字号
201
- current_size = 120 # 从更大的字号开始
202
  while current_size > 1:
203
  t.set_fontsize(current_size)
204
- # 获取渲染后的文本边界框
205
  text_bbox = t.get_window_extent(renderer=fig.canvas.get_renderer())
206
 
207
- # 如果文本宽度小于等于目标宽度,则此字号适用
208
  if text_bbox.width <= target_width_px:
209
  break
210
- current_size -= 2 # 步长可以大一点以提高速度
211
  # --- 修改结束 ---
212
 
213
  ax.set_xticks([])
214
  ax.set_yticks([])
215
- else:
216
- print(f"Warning: Index out of bounds - idx={idx}, row_grid={row_grid}, col_grid={col_grid}")
217
 
218
  # 添加日期信息
219
  ax_date = fig.add_subplot(gs[0, :])
220
  ax_date.text(0.01, 0.5, f"{date_str} {title}",
221
- fontsize=date_fontsize * 0.5, # 日期使用之前计算的字号
222
  color=DATE_COLOR, fontweight='bold',
223
  ha='left', va='center', transform=ax_date.transAxes)
224
  for spine in ax_date.spines.values():
@@ -256,24 +245,49 @@ def display_pdf(base64_pdf):
256
  pdf_display = f'<iframe src="{base64_pdf}" width="100%" height="800" type="application/pdf"></iframe>'
257
  return pdf_display
258
 
259
- # Streamlit 界面
260
  st.set_page_config(page_title="散厅时间快捷打印", layout="wide")
261
  st.title("散厅时间快捷打印")
262
 
263
  uploaded_file = st.file_uploader("上传【放映场次核对表.xls】文件", type=["xls"])
264
 
265
  if uploaded_file:
266
- part1, part2, date_str = process_schedule(uploaded_file)
 
267
 
268
  if part1 is not None and part2 is not None:
269
- part1_output = create_print_layout(part1, "A", date_str)
270
- part2_output = create_print_layout(part2, "C", date_str)
 
271
 
272
  col1, col2 = st.columns(2)
273
 
274
  with col1:
275
  st.subheader("白班散场预览(时间 ≤ 17:30)")
276
  if part1_output:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  tab1_1, tab1_2 = st.tabs(["PDF 预览", "PNG 预览"])
278
  with tab1_1:
279
  st.markdown(display_pdf(part1_output['pdf']), unsafe_allow_html=True)
@@ -285,6 +299,29 @@ if uploaded_file:
285
  with col2:
286
  st.subheader("夜班散场预览(时间 > 17:30)")
287
  if part2_output:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  tab2_1, tab2_2 = st.tabs(["PDF 预览", "PNG 预览"])
289
  with tab2_1:
290
  st.markdown(display_pdf(part2_output['pdf']), unsafe_allow_html=True)
 
9
  from matplotlib.backends.backend_pdf import PdfPages
10
  from matplotlib.patches import FancyBboxPatch
11
 
12
+ # --- Constants ---
13
  SPLIT_TIME = "17:30"
14
  BUSINESS_START = "09:30"
15
  BUSINESS_END = "01:30"
 
22
  # 读取 Excel,跳过前 8 行
23
  df = pd.read_excel(file, skiprows=8)
24
 
25
+ # 提取所需列 (G, H, J)
26
+ df = df.iloc[:, [6, 7, 9]]
27
  df.columns = ['Hall', 'StartTime', 'EndTime']
28
 
29
  # 清理数据
 
48
  if business_end < business_start:
49
  business_end += timedelta(days=1)
50
 
51
+ # 标准化所有时间到同一天或第二天
52
  for idx, row in df.iterrows():
53
  end_time = row['EndTime']
54
+ # If end time is early in the morning (e.g., after midnight), move it to the next day
55
  if end_time.hour < 9:
56
  df.at[idx, 'EndTime'] = end_time + timedelta(days=1)
57
+ # Handle cases starting late and ending after midnight
58
+ elif row['StartTime'].hour >= 21 and end_time.hour < 9:
59
  df.at[idx, 'EndTime'] = end_time + timedelta(days=1)
60
 
61
+ # 创建用于比较的时间列,不受日期影响
62
  df['time_for_comparison'] = df['EndTime'].apply(
63
  lambda x: datetime.combine(base_date, x.time())
64
  )
65
+ # 确保凌晨的时间被推到第二天进行比较
66
  df.loc[df['time_for_comparison'].dt.hour < 9, 'time_for_comparison'] += timedelta(days=1)
67
 
68
+ # 筛选营业时间内的场次
69
  valid_times = (
70
+ (df['time_for_comparison'] >= datetime.combine(base_date, business_start.time())) &
71
+ (df['time_for_comparison'] <= business_end)
72
  )
73
 
74
  df = df[valid_times]
 
77
  df = df.sort_values('EndTime')
78
 
79
  # 分割数据
80
+ split_time_dt = datetime.strptime(f"{base_date} {SPLIT_TIME}", "%Y-%m-%d %H:%M")
 
 
 
81
 
82
+ part1 = df[df['EndTime'] <= split_time_dt].copy()
83
+ part2 = df[df['EndTime'] > split_time_dt].copy()
84
 
85
  # 格式化时间显示
86
  for part in [part1, part2]:
87
  part['EndTime'] = part['EndTime'].dt.strftime('%-H:%M')
88
 
89
+ # 精确读取C6单元格以获取日期
90
  date_df = pd.read_excel(
91
  file,
92
  skiprows=5, # 跳过前5行(0-4)
 
139
 
140
  gs = gridspec.GridSpec(num_rows + 1, num_cols, hspace=0.05, wspace=0.05, height_ratios=[0.1] + [1] * num_rows, figure=fig)
141
 
142
+ # --- 预先计算单元格的目标宽度(以像素为单位)---
143
+ target_width_px = 1
144
  if total_items > 0:
 
145
  ax_temp = fig.add_subplot(gs[1, 0])
 
146
  fig.canvas.draw()
 
147
  target_width_px = ax_temp.get_window_extent().width * 0.90
 
148
  ax_temp.remove()
149
  # --- 预计算结束 ---
150
 
 
151
  available_height_per_row = (8.27 * 0.9 * (1 / 1.2)) / num_rows if num_rows > 0 else 1
152
  date_fontsize = min(40, max(10, available_height_per_row * 72 * 0.5))
153
 
 
186
 
187
  display_text = f"{hall}{end_time}"
188
 
189
+ # --- 动态字体大小调整逻辑 ---
 
190
  t = ax.text(0.5, 0.5, display_text,
191
  fontweight='bold', ha='center', va='center',
192
  transform=ax.transAxes)
193
 
194
+ current_size = 120
 
195
  while current_size > 1:
196
  t.set_fontsize(current_size)
 
197
  text_bbox = t.get_window_extent(renderer=fig.canvas.get_renderer())
198
 
 
199
  if text_bbox.width <= target_width_px:
200
  break
201
+ current_size -= 2
202
  # --- 修改结束 ---
203
 
204
  ax.set_xticks([])
205
  ax.set_yticks([])
 
 
206
 
207
  # 添加日期信息
208
  ax_date = fig.add_subplot(gs[0, :])
209
  ax_date.text(0.01, 0.5, f"{date_str} {title}",
210
+ fontsize=date_fontsize * 0.5,
211
  color=DATE_COLOR, fontweight='bold',
212
  ha='left', va='center', transform=ax_date.transAxes)
213
  for spine in ax_date.spines.values():
 
245
  pdf_display = f'<iframe src="{base64_pdf}" width="100%" height="800" type="application/pdf"></iframe>'
246
  return pdf_display
247
 
248
+ # --- Streamlit 界面 ---
249
  st.set_page_config(page_title="散厅时间快捷打印", layout="wide")
250
  st.title("散厅时间快捷打印")
251
 
252
  uploaded_file = st.file_uploader("上传【放映场次核对表.xls】文件", type=["xls"])
253
 
254
  if uploaded_file:
255
+ with st.spinner("文件处理中..."):
256
+ part1, part2, date_str = process_schedule(uploaded_file)
257
 
258
  if part1 is not None and part2 is not None:
259
+ with st.spinner("正在生成布局..."):
260
+ part1_output = create_print_layout(part1, "A", date_str)
261
+ part2_output = create_print_layout(part2, "C", date_str)
262
 
263
  col1, col2 = st.columns(2)
264
 
265
  with col1:
266
  st.subheader("白班散场预览(时间 ≤ 17:30)")
267
  if part1_output:
268
+ # --- 新增:下载按钮 ---
269
+ png_data_1 = base64.b64decode(part1_output['png'].split(',')[1])
270
+ pdf_data_1 = base64.b64decode(part1_output['pdf'].split(',')[1])
271
+
272
+ btn_col1, btn_col2 = st.columns(2)
273
+ with btn_col1:
274
+ st.download_button(
275
+ label="下载 PNG 图片",
276
+ data=png_data_1,
277
+ file_name=f"{date_str}-白班-A.png",
278
+ mime="image/png",
279
+ use_container_width=True
280
+ )
281
+ with btn_col2:
282
+ st.download_button(
283
+ label="下载 PDF 文件",
284
+ data=pdf_data_1,
285
+ file_name=f"{date_str}-白班-A.pdf",
286
+ mime="application/pdf",
287
+ use_container_width=True
288
+ )
289
+ # --- 新增结束 ---
290
+
291
  tab1_1, tab1_2 = st.tabs(["PDF 预览", "PNG 预览"])
292
  with tab1_1:
293
  st.markdown(display_pdf(part1_output['pdf']), unsafe_allow_html=True)
 
299
  with col2:
300
  st.subheader("夜班散场预览(时间 > 17:30)")
301
  if part2_output:
302
+ # --- 新增:下载按钮 ---
303
+ png_data_2 = base64.b64decode(part2_output['png'].split(',')[1])
304
+ pdf_data_2 = base64.b64decode(part2_output['pdf'].split(',')[1])
305
+
306
+ btn_col3, btn_col4 = st.columns(2)
307
+ with btn_col3:
308
+ st.download_button(
309
+ label="下载 PNG 图片",
310
+ data=png_data_2,
311
+ file_name=f"{date_str}-夜班-C.png",
312
+ mime="image/png",
313
+ use_container_width=True
314
+ )
315
+ with btn_col4:
316
+ st.download_button(
317
+ label="下载 PDF 文件",
318
+ data=pdf_data_2,
319
+ file_name=f"{date_str}-夜班-C.pdf",
320
+ mime="application/pdf",
321
+ use_container_width=True
322
+ )
323
+ # --- 新增结束 ---
324
+
325
  tab2_1, tab2_2 = st.tabs(["PDF 预览", "PNG 预览"])
326
  with tab2_1:
327
  st.markdown(display_pdf(part2_output['pdf']), unsafe_allow_html=True)