Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -7,12 +7,11 @@ import base64
|
|
7 |
import matplotlib.gridspec as gridspec
|
8 |
import math
|
9 |
|
10 |
-
# [前面的常量定义和 process_schedule 函数保持不变]
|
11 |
SPLIT_TIME = "17:30"
|
12 |
BUSINESS_START = "09:30"
|
13 |
BUSINESS_END = "01:30"
|
14 |
BORDER_COLOR = '#A9A9A9'
|
15 |
-
DATE_COLOR = '#A9A9A9'
|
16 |
|
17 |
def process_schedule(file):
|
18 |
"""处理上传的 Excel 文件,生成排序和分组后的打印内容"""
|
@@ -49,24 +48,19 @@ def process_schedule(file):
|
|
49 |
# 标准化所有时间到同一天
|
50 |
for idx, row in df.iterrows():
|
51 |
end_time = row['EndTime']
|
52 |
-
# 如果结束时间在凌晨(0点到9:30之间),认为是第二天
|
53 |
if end_time.hour < 9:
|
54 |
df.at[idx, 'EndTime'] = end_time + timedelta(days=1)
|
55 |
|
56 |
-
# 如果开始时间在晚上9点之后,结束时间在凌晨,也需要调整结束时间
|
57 |
if row['StartTime'].hour >= 21 and end_time.hour < 9:
|
58 |
df.at[idx, 'EndTime'] = end_time + timedelta(days=1)
|
59 |
|
60 |
# 筛选营业时间内的场次
|
61 |
-
# 转换时间为当天的时间点进行比较
|
62 |
df['time_for_comparison'] = df['EndTime'].apply(
|
63 |
lambda x: datetime.combine(base_date, x.time())
|
64 |
)
|
65 |
|
66 |
-
# 处理跨天的情况
|
67 |
df.loc[df['time_for_comparison'].dt.hour < 9, 'time_for_comparison'] += timedelta(days=1)
|
68 |
|
69 |
-
# 应用时间筛选
|
70 |
valid_times = (
|
71 |
((df['time_for_comparison'] >= datetime.combine(base_date, business_start.time())) &
|
72 |
(df['time_for_comparison'] <= datetime.combine(base_date + timedelta(days=1), business_end.time())))
|
@@ -90,9 +84,24 @@ def process_schedule(file):
|
|
90 |
for part in [part1, part2]:
|
91 |
part['EndTime'] = part['EndTime'].dt.strftime('%-I:%M')
|
92 |
|
93 |
-
#
|
94 |
-
date_df = pd.read_excel(
|
95 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
|
97 |
return part1[['Hall', 'EndTime']], part2[['Hall', 'EndTime']], date_str
|
98 |
|
@@ -111,7 +120,7 @@ def create_print_layout(data, title, date_str):
|
|
111 |
|
112 |
# 设置字体
|
113 |
plt.rcParams['font.family'] = 'sans-serif'
|
114 |
-
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
|
115 |
|
116 |
# 计算行数和总数
|
117 |
total_items = len(data)
|
@@ -121,46 +130,36 @@ def create_print_layout(data, title, date_str):
|
|
121 |
# 创建网格
|
122 |
gs = gridspec.GridSpec(num_rows + 1, num_cols, hspace=0.1, wspace=0.1, height_ratios=[1] * num_rows + [0.2])
|
123 |
|
124 |
-
|
125 |
-
base_fontsize = min(30, 265 / num_rows) # 最大字体限制为30
|
126 |
|
127 |
-
# 重要改动:正确的竖向排序逻辑
|
128 |
data_values = data.values.tolist()
|
129 |
|
130 |
-
# 确保数据长度是3的倍数
|
131 |
while len(data_values) % 3 != 0:
|
132 |
data_values.append(['', ''])
|
133 |
|
134 |
-
# 计算每列应该包含的行数
|
135 |
rows_per_col = math.ceil(len(data_values) / 3)
|
136 |
|
137 |
-
# 创建一个新的数据列表,用于存储重新排序后的数据
|
138 |
sorted_data = [['', '']] * len(data_values)
|
139 |
|
140 |
-
# 正确的竖向排序逻辑
|
141 |
for i, item in enumerate(data_values):
|
142 |
-
if item[0] and item[1]:
|
143 |
-
# 计算新的位置
|
144 |
row = i % rows_per_col
|
145 |
col = i // rows_per_col
|
146 |
new_index = row * 3 + col
|
147 |
if new_index < len(sorted_data):
|
148 |
sorted_data[new_index] = item
|
149 |
|
150 |
-
# 填充数据
|
151 |
for idx, (hall, end_time) in enumerate(sorted_data):
|
152 |
-
if hall and end_time:
|
153 |
row = idx // 3
|
154 |
col = idx % 3
|
155 |
|
156 |
ax = plt.subplot(gs[row, col])
|
157 |
|
158 |
-
# 设置边框
|
159 |
for spine in ax.spines.values():
|
160 |
spine.set_color(BORDER_COLOR)
|
161 |
spine.set_linewidth(0.5)
|
162 |
|
163 |
-
# 显示文本
|
164 |
display_text = f"{hall}{end_time}"
|
165 |
ax.text(0.5, 0.5, display_text,
|
166 |
fontsize=base_fontsize,
|
@@ -168,24 +167,21 @@ def create_print_layout(data, title, date_str):
|
|
168 |
ha='center',
|
169 |
va='center')
|
170 |
|
171 |
-
# 设置边距
|
172 |
ax.set_xlim(-0.02, 1.02)
|
173 |
ax.set_ylim(-0.02, 1.02)
|
174 |
|
175 |
-
# 移除坐标轴
|
176 |
ax.set_xticks([])
|
177 |
ax.set_yticks([])
|
178 |
|
179 |
-
#
|
180 |
ax_date = plt.subplot(gs[0, 0])
|
181 |
ax_date.text(0.05, 0.95, f"{date_str} {title}",
|
182 |
-
fontsize=base_fontsize * 0.4,
|
183 |
-
color=DATE_COLOR,
|
184 |
fontweight='bold',
|
185 |
ha='left',
|
186 |
va='top')
|
187 |
|
188 |
-
# 移除日期单元格的边框
|
189 |
for spine in ax_date.spines.values():
|
190 |
spine.set_visible(False)
|
191 |
ax_date.set_xticks([])
|
@@ -210,11 +206,9 @@ if uploaded_file:
|
|
210 |
part1, part2, date_str = process_schedule(uploaded_file)
|
211 |
|
212 |
if part1 is not None and part2 is not None:
|
213 |
-
|
214 |
-
|
215 |
-
part2_image = create_print_layout(part2, "C", date_str) # 夜班改为 C
|
216 |
|
217 |
-
# 显示预览
|
218 |
col1, col2 = st.columns(2)
|
219 |
|
220 |
with col1:
|
@@ -229,4 +223,23 @@ if uploaded_file:
|
|
229 |
if part2_image:
|
230 |
st.image(part2_image)
|
231 |
else:
|
232 |
-
st.info("夜班部分没有数据")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
import matplotlib.gridspec as gridspec
|
8 |
import math
|
9 |
|
|
|
10 |
SPLIT_TIME = "17:30"
|
11 |
BUSINESS_START = "09:30"
|
12 |
BUSINESS_END = "01:30"
|
13 |
BORDER_COLOR = '#A9A9A9'
|
14 |
+
DATE_COLOR = '#A9A9A9'
|
15 |
|
16 |
def process_schedule(file):
|
17 |
"""处理上传的 Excel 文件,生成排序和分组后的打印内容"""
|
|
|
48 |
# 标准化所有时间到同一天
|
49 |
for idx, row in df.iterrows():
|
50 |
end_time = row['EndTime']
|
|
|
51 |
if end_time.hour < 9:
|
52 |
df.at[idx, 'EndTime'] = end_time + timedelta(days=1)
|
53 |
|
|
|
54 |
if row['StartTime'].hour >= 21 and end_time.hour < 9:
|
55 |
df.at[idx, 'EndTime'] = end_time + timedelta(days=1)
|
56 |
|
57 |
# 筛选营业时间内的场次
|
|
|
58 |
df['time_for_comparison'] = df['EndTime'].apply(
|
59 |
lambda x: datetime.combine(base_date, x.time())
|
60 |
)
|
61 |
|
|
|
62 |
df.loc[df['time_for_comparison'].dt.hour < 9, 'time_for_comparison'] += timedelta(days=1)
|
63 |
|
|
|
64 |
valid_times = (
|
65 |
((df['time_for_comparison'] >= datetime.combine(base_date, business_start.time())) &
|
66 |
(df['time_for_comparison'] <= datetime.combine(base_date + timedelta(days=1), business_end.time())))
|
|
|
84 |
for part in [part1, part2]:
|
85 |
part['EndTime'] = part['EndTime'].dt.strftime('%-I:%M')
|
86 |
|
87 |
+
# 关键修改:精确读取C6单元格
|
88 |
+
date_df = pd.read_excel(
|
89 |
+
file,
|
90 |
+
skiprows=5, # 跳过前5行(0-4)
|
91 |
+
nrows=1, # 只读1行
|
92 |
+
usecols=[2], # 第三列(C列)
|
93 |
+
header=None # 无表头
|
94 |
+
)
|
95 |
+
date_cell = date_df.iloc[0, 0]
|
96 |
+
|
97 |
+
try:
|
98 |
+
# 处理不同日期格式
|
99 |
+
if isinstance(date_cell, str):
|
100 |
+
date_str = datetime.strptime(date_cell, '%Y-%m-%d').strftime('%Y-%m-%d')
|
101 |
+
else:
|
102 |
+
date_str = pd.to_datetime(date_cell).strftime('%Y-%m-%d')
|
103 |
+
except:
|
104 |
+
date_str = datetime.today().strftime('%Y-%m-%d')
|
105 |
|
106 |
return part1[['Hall', 'EndTime']], part2[['Hall', 'EndTime']], date_str
|
107 |
|
|
|
120 |
|
121 |
# 设置字体
|
122 |
plt.rcParams['font.family'] = 'sans-serif'
|
123 |
+
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
|
124 |
|
125 |
# 计算行数和总数
|
126 |
total_items = len(data)
|
|
|
130 |
# 创建网格
|
131 |
gs = gridspec.GridSpec(num_rows + 1, num_cols, hspace=0.1, wspace=0.1, height_ratios=[1] * num_rows + [0.2])
|
132 |
|
133 |
+
base_fontsize = min(30, 265 / num_rows)
|
|
|
134 |
|
|
|
135 |
data_values = data.values.tolist()
|
136 |
|
|
|
137 |
while len(data_values) % 3 != 0:
|
138 |
data_values.append(['', ''])
|
139 |
|
|
|
140 |
rows_per_col = math.ceil(len(data_values) / 3)
|
141 |
|
|
|
142 |
sorted_data = [['', '']] * len(data_values)
|
143 |
|
|
|
144 |
for i, item in enumerate(data_values):
|
145 |
+
if item[0] and item[1]:
|
|
|
146 |
row = i % rows_per_col
|
147 |
col = i // rows_per_col
|
148 |
new_index = row * 3 + col
|
149 |
if new_index < len(sorted_data):
|
150 |
sorted_data[new_index] = item
|
151 |
|
|
|
152 |
for idx, (hall, end_time) in enumerate(sorted_data):
|
153 |
+
if hall and end_time:
|
154 |
row = idx // 3
|
155 |
col = idx % 3
|
156 |
|
157 |
ax = plt.subplot(gs[row, col])
|
158 |
|
|
|
159 |
for spine in ax.spines.values():
|
160 |
spine.set_color(BORDER_COLOR)
|
161 |
spine.set_linewidth(0.5)
|
162 |
|
|
|
163 |
display_text = f"{hall}{end_time}"
|
164 |
ax.text(0.5, 0.5, display_text,
|
165 |
fontsize=base_fontsize,
|
|
|
167 |
ha='center',
|
168 |
va='center')
|
169 |
|
|
|
170 |
ax.set_xlim(-0.02, 1.02)
|
171 |
ax.set_ylim(-0.02, 1.02)
|
172 |
|
|
|
173 |
ax.set_xticks([])
|
174 |
ax.set_yticks([])
|
175 |
|
176 |
+
# 添加日期信息
|
177 |
ax_date = plt.subplot(gs[0, 0])
|
178 |
ax_date.text(0.05, 0.95, f"{date_str} {title}",
|
179 |
+
fontsize=base_fontsize * 0.4,
|
180 |
+
color=DATE_COLOR,
|
181 |
fontweight='bold',
|
182 |
ha='left',
|
183 |
va='top')
|
184 |
|
|
|
185 |
for spine in ax_date.spines.values():
|
186 |
spine.set_visible(False)
|
187 |
ax_date.set_xticks([])
|
|
|
206 |
part1, part2, date_str = process_schedule(uploaded_file)
|
207 |
|
208 |
if part1 is not None and part2 is not None:
|
209 |
+
part1_image = create_print_layout(part1, "A", date_str)
|
210 |
+
part2_image = create_print_layout(part2, "C", date_str)
|
|
|
211 |
|
|
|
212 |
col1, col2 = st.columns(2)
|
213 |
|
214 |
with col1:
|
|
|
223 |
if part2_image:
|
224 |
st.image(part2_image)
|
225 |
else:
|
226 |
+
st.info("夜班部分没有数据")
|
227 |
+
|
228 |
+
# 添加打印按钮
|
229 |
+
if part1_image:
|
230 |
+
st.markdown(
|
231 |
+
f'<a href="{part1_image}" target="_blank" style="text-decoration: none;">'
|
232 |
+
'<button style="padding: 10px 20px; background-color: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer;">'
|
233 |
+
'打开并打印第一部分'
|
234 |
+
'</button></a>',
|
235 |
+
unsafe_allow_html=True
|
236 |
+
)
|
237 |
+
|
238 |
+
if part2_image:
|
239 |
+
st.markdown(
|
240 |
+
f'<a href="{part2_image}" target="_blank" style="text-decoration: none;">'
|
241 |
+
'<button style="padding: 10px 20px; background-color: #2196F3; color: white; border: none; border-radius: 5px; cursor: pointer; margin-top: 10px;">'
|
242 |
+
'打开并打印第二部分'
|
243 |
+
'</button></a>',
|
244 |
+
unsafe_allow_html=True
|
245 |
+
)
|