Ethscriptions commited on
Commit
c8dda34
·
verified ·
1 Parent(s): ef3f125

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +204 -0
app.py ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import streamlit as st
3
+ from datetime import datetime, timedelta
4
+ import matplotlib.pyplot as plt
5
+ import io
6
+ import base64
7
+ from matplotlib.patches import Rectangle
8
+ import matplotlib.gridspec as gridspec
9
+
10
+ # 定义全局常量
11
+ SPLIT_TIME = "17:30" # 分界线时间
12
+ BUSINESS_START = "09:30" # 营业开始时间
13
+ BUSINESS_END = "01:30" # 营业结束时间
14
+
15
+ def process_schedule(file):
16
+ """处理上传的 Excel 文件,生成排序和分组后的打印内容"""
17
+ try:
18
+ # 读取 Excel,跳过前 8 行
19
+ df = pd.read_excel(file, skiprows=8)
20
+
21
+ # 提取所需列 (G9, H9, J9)
22
+ df = df.iloc[:, [6, 7, 9]] # G, H, J 列
23
+ df.columns = ['Hall', 'StartTime', 'EndTime']
24
+
25
+ # 清理数据
26
+ df = df.dropna(subset=['Hall', 'StartTime', 'EndTime'])
27
+
28
+ # 转换影厅格式为 "#号" 格式
29
+ df['Hall'] = df['Hall'].str.extract(r'(\d+)号').astype(str) + '#'
30
+
31
+ # 转换时间格式
32
+ df['StartTime'] = pd.to_datetime(df['StartTime']).dt.strftime('%H:%M')
33
+ df['EndTime'] = pd.to_datetime(df['EndTime']).dt.strftime('%H:%M')
34
+
35
+ # 将时间转换为 datetime 对象便于比较
36
+ base_date = datetime.today().date()
37
+ df['StartTime'] = pd.to_datetime(base_date.strftime('%Y-%m-%d ') + df['StartTime'])
38
+ df['EndTime'] = pd.to_datetime(base_date.strftime('%Y-%m-%d ') + df['EndTime'])
39
+
40
+ # 处理跨天情况
41
+ df.loc[df['EndTime'] < df['StartTime'], 'EndTime'] += timedelta(days=1)
42
+
43
+ # 筛选营业时间内的场次
44
+ business_start = datetime.strptime(base_date.strftime('%Y-%m-%d ') + BUSINESS_START, '%Y-%m-%d %H:%M')
45
+ business_end = datetime.strptime(base_date.strftime('%Y-%m-%d ') + BUSINESS_END, '%Y-%m-%d %H:%M')
46
+ if business_end < business_start:
47
+ business_end += timedelta(days=1)
48
+
49
+ mask = (
50
+ (df['StartTime'] >= business_start) |
51
+ (df['StartTime'] <= business_end)
52
+ )
53
+ df = df[mask]
54
+
55
+ # 按散场时间排序
56
+ df = df.sort_values('EndTime')
57
+
58
+ # 分割数据
59
+ split_time = datetime.strptime(base_date.strftime('%Y-%m-%d ') + SPLIT_TIME, '%Y-%m-%d %H:%M')
60
+ part1 = df[df['EndTime'] <= split_time].copy()
61
+ part2 = df[df['EndTime'] > split_time].copy()
62
+
63
+ # 格式化时间显示
64
+ for part in [part1, part2]:
65
+ part['EndTime'] = part['EndTime'].dt.strftime('%-I:%M')
66
+
67
+ return part1[['Hall', 'EndTime']], part2[['Hall', 'EndTime']]
68
+
69
+ except Exception as e:
70
+ st.error(f"处理文件时出错: {str(e)}")
71
+ return None, None
72
+
73
+ def create_print_layout(data, title):
74
+ """创建打印布局"""
75
+ if data.empty:
76
+ return None
77
+
78
+ # 设置 A5 横向尺寸(单位:英寸)
79
+ fig = plt.figure(figsize=(8.27, 5.83), dpi=300)
80
+
81
+ # 减小边距,最大化利用空间
82
+ plt.subplots_adjust(left=0.02, right=0.98, top=0.98, bottom=0.02)
83
+
84
+ # 创建网格,减小间距
85
+ rows = (len(data) + 3) // 4 # 向上取整除法
86
+ gs = gridspec.GridSpec(rows, 4, hspace=0.1, wspace=0.1) # 显著减小间距
87
+
88
+ # 设置字体和样式
89
+ plt.rcParams['font.family'] = 'sans-serif'
90
+ plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文字体
91
+
92
+ # 计算适合的字体大小
93
+ base_fontsize = min(32, 180 / rows) # 根据行数动态调整基础字体大小
94
+
95
+ # 填充数据
96
+ for idx, (hall, end_time) in enumerate(data.values):
97
+ row = idx // 4
98
+ col = idx % 4
99
+
100
+ # 创建子图
101
+ ax = plt.subplot(gs[row, col])
102
+
103
+ # 设置边框样式
104
+ for spine in ax.spines.values():
105
+ spine.set_color('lightgray')
106
+ spine.set_linewidth(0.5)
107
+
108
+ # 调整文本位置,增加上下间距
109
+ # 将影厅号向上移动,时间向下移动
110
+ ax.text(0.5, 0.65, hall, # y 位置从 0.55 改为 0.65
111
+ fontsize=base_fontsize,
112
+ fontweight='bold',
113
+ ha='center',
114
+ va='center')
115
+ ax.text(0.5, 0.2, end_time, # y 位置从 0.25 改为 0.2
116
+ fontsize=base_fontsize,
117
+ fontweight='bold',
118
+ ha='center',
119
+ va='center')
120
+
121
+ # 设置更小的内边距
122
+ ax.set_xlim(-0.02, 1.02)
123
+ ax.set_ylim(-0.02, 1.02)
124
+
125
+ # 移除坐标轴
126
+ ax.set_xticks([])
127
+ ax.set_yticks([])
128
+
129
+ # 将图表转换为 base64 字符串
130
+ buffer = io.BytesIO()
131
+ plt.savefig(buffer, format='png', bbox_inches='tight', pad_inches=0.05) # 减小边距
132
+ buffer.seek(0)
133
+ image_base64 = base64.b64encode(buffer.getvalue()).decode()
134
+ plt.close()
135
+
136
+ return f'data:image/png;base64,{image_base64}'
137
+
138
+ def get_html_content(image_base64):
139
+ """生成打印���面的 HTML 内容"""
140
+ return f"""
141
+ <!DOCTYPE html>
142
+ <html>
143
+ <head>
144
+ <style>
145
+ @page {{
146
+ size: A5 landscape;
147
+ margin: 0;
148
+ }}
149
+ body {{
150
+ margin: 0;
151
+ padding: 0;
152
+ display: flex;
153
+ justify-content: center;
154
+ align-items: center;
155
+ height: 100vh;
156
+ }}
157
+ img {{
158
+ width: 100%;
159
+ height: 100%;
160
+ object-fit: fill;
161
+ }}
162
+ </style>
163
+ <script>
164
+ window.onload = function() {{
165
+ window.print();
166
+ }}
167
+ </script>
168
+ </head>
169
+ <body>
170
+ <img src="{image_base64}">
171
+ </body>
172
+ </html>
173
+ """
174
+
175
+ # Streamlit 界面
176
+ st.set_page_config(page_title="散厅时间快捷打印", layout="wide")
177
+ st.title("散厅时间快捷打印")
178
+
179
+ uploaded_file = st.file_uploader("上传 放映场次核对表.xls 文件", type=["xls", "xlsx"])
180
+
181
+ if uploaded_file:
182
+ part1, part2 = process_schedule(uploaded_file)
183
+
184
+ if part1 is not None and part2 is not None:
185
+ # 创建打印布局
186
+ part1_image = create_print_layout(part1, "第一部分")
187
+ part2_image = create_print_layout(part2, "第二部分")
188
+
189
+ # 显示预览
190
+ col1, col2 = st.columns(2)
191
+
192
+ with col1:
193
+ st.subheader("第一部分预览 (散场时间 ≤ 17:30)")
194
+ if part1_image:
195
+ st.image(part1_image)
196
+ else:
197
+ st.info("第一部分没有数据")
198
+
199
+ with col2:
200
+ st.subheader("第二部分预览 (散场时间 > 17:30)")
201
+ if part2_image:
202
+ st.image(part2_image)
203
+ else:
204
+ st.info("第二部分没有数据")