File size: 6,795 Bytes
c8dda34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
import pandas as pd
import streamlit as st
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import io
import base64
from matplotlib.patches import Rectangle
import matplotlib.gridspec as gridspec

# 定义全局常量
SPLIT_TIME = "17:30"  # 分界线时间
BUSINESS_START = "09:30"  # 营业开始时间
BUSINESS_END = "01:30"  # 营业结束时间

def process_schedule(file):
    """处理上传的 Excel 文件,生成排序和分组后的打印内容"""
    try:
        # 读取 Excel,跳过前 8 行
        df = pd.read_excel(file, skiprows=8)
        
        # 提取所需列 (G9, H9, J9)
        df = df.iloc[:, [6, 7, 9]]  # G, H, J 列
        df.columns = ['Hall', 'StartTime', 'EndTime']
        
        # 清理数据
        df = df.dropna(subset=['Hall', 'StartTime', 'EndTime'])
        
        # 转换影厅格式为 "#号" 格式
        df['Hall'] = df['Hall'].str.extract(r'(\d+)号').astype(str) + '#'
        
        # 转换时间格式
        df['StartTime'] = pd.to_datetime(df['StartTime']).dt.strftime('%H:%M')
        df['EndTime'] = pd.to_datetime(df['EndTime']).dt.strftime('%H:%M')
        
        # 将时间转换为 datetime 对象便于比较
        base_date = datetime.today().date()
        df['StartTime'] = pd.to_datetime(base_date.strftime('%Y-%m-%d ') + df['StartTime'])
        df['EndTime'] = pd.to_datetime(base_date.strftime('%Y-%m-%d ') + df['EndTime'])
        
        # 处理跨天情况
        df.loc[df['EndTime'] < df['StartTime'], 'EndTime'] += timedelta(days=1)
        
        # 筛选营业时间内的场次
        business_start = datetime.strptime(base_date.strftime('%Y-%m-%d ') + BUSINESS_START, '%Y-%m-%d %H:%M')
        business_end = datetime.strptime(base_date.strftime('%Y-%m-%d ') + BUSINESS_END, '%Y-%m-%d %H:%M')
        if business_end < business_start:
            business_end += timedelta(days=1)
            
        mask = (
            (df['StartTime'] >= business_start) | 
            (df['StartTime'] <= business_end)
        )
        df = df[mask]
        
        # 按散场时间排序
        df = df.sort_values('EndTime')
        
        # 分割数据
        split_time = datetime.strptime(base_date.strftime('%Y-%m-%d ') + SPLIT_TIME, '%Y-%m-%d %H:%M')
        part1 = df[df['EndTime'] <= split_time].copy()
        part2 = df[df['EndTime'] > split_time].copy()
        
        # 格式化时间显示
        for part in [part1, part2]:
            part['EndTime'] = part['EndTime'].dt.strftime('%-I:%M')
            
        return part1[['Hall', 'EndTime']], part2[['Hall', 'EndTime']]
    
    except Exception as e:
        st.error(f"处理文件时出错: {str(e)}")
        return None, None

def create_print_layout(data, title):
    """创建打印布局"""
    if data.empty:
        return None
        
    # 设置 A5 横向尺寸(单位:英寸)
    fig = plt.figure(figsize=(8.27, 5.83), dpi=300)
    
    # 减小边距,最大化利用空间
    plt.subplots_adjust(left=0.02, right=0.98, top=0.98, bottom=0.02)
    
    # 创建网格,减小间距
    rows = (len(data) + 3) // 4  # 向上取整除法
    gs = gridspec.GridSpec(rows, 4, hspace=0.1, wspace=0.1)  # 显著减小间距
    
    # 设置字体和样式
    plt.rcParams['font.family'] = 'sans-serif'
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 中文字体
    
    # 计算适合的字体大小
    base_fontsize = min(32, 180 / rows)  # 根据行数动态调整基础字体大小
    
    # 填充数据
    for idx, (hall, end_time) in enumerate(data.values):
        row = idx // 4
        col = idx % 4
        
        # 创建子图
        ax = plt.subplot(gs[row, col])
        
        # 设置边框样式
        for spine in ax.spines.values():
            spine.set_color('lightgray')
            spine.set_linewidth(0.5)
        
        # 调整文本位置,增加上下间距
        # 将影厅号向上移动,时间向下移动
        ax.text(0.5, 0.65, hall,  # y 位置从 0.55 改为 0.65
                fontsize=base_fontsize, 
                fontweight='bold', 
                ha='center', 
                va='center')
        ax.text(0.5, 0.2, end_time,  # y 位置从 0.25 改为 0.2
                fontsize=base_fontsize, 
                fontweight='bold', 
                ha='center', 
                va='center')
        
        # 设置更小的内边距
        ax.set_xlim(-0.02, 1.02)
        ax.set_ylim(-0.02, 1.02)
        
        # 移除坐标轴
        ax.set_xticks([])
        ax.set_yticks([])
    
    # 将图表转换为 base64 字符串
    buffer = io.BytesIO()
    plt.savefig(buffer, format='png', bbox_inches='tight', pad_inches=0.05)  # 减小边距
    buffer.seek(0)
    image_base64 = base64.b64encode(buffer.getvalue()).decode()
    plt.close()
    
    return f'data:image/png;base64,{image_base64}'

def get_html_content(image_base64):
    """生成打印页面的 HTML 内容"""
    return f"""
    <!DOCTYPE html>
    <html>
    <head>
        <style>
            @page {{
                size: A5 landscape;
                margin: 0;
            }}
            body {{
                margin: 0;
                padding: 0;
                display: flex;
                justify-content: center;
                align-items: center;
                height: 100vh;
            }}
            img {{
                width: 100%;
                height: 100%;
                object-fit: fill;
            }}
        </style>
        <script>
            window.onload = function() {{
                window.print();
            }}
        </script>
    </head>
    <body>
        <img src="{image_base64}">
    </body>
    </html>
    """

# Streamlit 界面
st.set_page_config(page_title="散厅时间快捷打印", layout="wide")
st.title("散厅时间快捷打印")

uploaded_file = st.file_uploader("上传 放映场次核对表.xls 文件", type=["xls", "xlsx"])

if uploaded_file:
    part1, part2 = process_schedule(uploaded_file)
    
    if part1 is not None and part2 is not None:
        # 创建打印布局
        part1_image = create_print_layout(part1, "第一部分")
        part2_image = create_print_layout(part2, "第二部分")
        
        # 显示预览
        col1, col2 = st.columns(2)
        
        with col1:
            st.subheader("第一部分预览 (散场时间 ≤ 17:30)")
            if part1_image:
                st.image(part1_image)
            else:
                st.info("第一部分没有数据")
        
        with col2:
            st.subheader("第二部分预览 (散场时间 > 17:30)")
            if part2_image:
                st.image(part2_image)
            else:
                st.info("第二部分没有数据")