背景需求

今天又发了牙齿涂氟单

继续用原来代码批量打印幼儿信息

【办公类-18-08】20251217(Python)全园幼儿“口腔检查涂氟信息”批量生成打印https://mp.csdn.net/mp_blog/creation/editor/156028065

复制原来的代码

00、必须有的表格

 01、下载园园通的数据

把 path路径改掉

'''
20251217涂氟单制作
1、下载园园通新生名册.xls,把两个新生名册合并在一起
2、部分插班生信息手动添加
deepseek,阿夏
20251124
'''

import pandas as pd
import os
import re

def format_long_number(value):
    """处理长数字,避免科学计数法和精度丢失"""
    if pd.isna(value) or value == '':
        return value
    
    str_value = str(value).strip()
    
    # 处理科学计数法
    if 'e+' in str_value.lower() or 'e-' in str_value.lower():
        try:
            # 将科学计数法转换为完整数字
            num_value = float(str_value)
            return str(int(num_value)) if num_value.is_integer() else str(num_value)
        except:
            return str_value
    
    # 处理浮点数.0的情况
    if '.' in str_value and str_value.endswith('.0'):
        return str_value[:-2]
    
    return str_value

def format_class_name(class_name):
    """格式化班级名称"""
    if pd.isna(class_name) or class_name == '':
        return class_name
    
    class_str = str(class_name)
    
    # 定义班级类型和对应的前缀
    class_types = {
        '托班': '托', '托': '托',
        '小班': '小', '小': '小', 
        '中班': '中', '中': '中',
        '大班': '大', '大': '大'
    }
    
    # 中文数字到阿拉伯数字的映射
    chinese_to_arabic = {
        '一': '1', '二': '2', '三': '3', '四': '4', '五': '5',
        '六': '6', '七': '7', '八': '8', '九': '9', '十': '10',
        '1': '1', '2': '2', '3': '3', '4': '4', '5': '5',
        '6': '6', '7': '7', '8': '8', '9': '9', '10': '10'
    }
    
    # 尝试匹配各种班级格式
    patterns = [
        r'([托小中大])班(\S+?)班',  # 如:大班一班
        r'([托小中大])(\S+?)班',    # 如:大一班
        r'(\S+?)([托小中大])班',    # 如:一班大班
        r'([托小中大])班',          # 如:大班(没有具体班号)
    ]
    
    for pattern in patterns:
        match = re.search(pattern, class_str)
        if match:
            if len(match.groups()) >= 0:
                # 有班级类型和班号
                class_type = match.group(1)
                class_num = match.group(2)
                
                # 获取班级前缀
                prefix = class_types.get(class_type, class_type)
                
                # 转换班号
                if class_num in chinese_to_arabic:
                    num = chinese_to_arabic[class_num]
                    return f"{prefix}{num}班"
                else:
                    return f"{prefix}{class_num}班"
            else:
                # 只有班级类型,没有班号
                class_type = match.group(1)
                prefix = class_types.get(class_type, class_type)
                return f"{prefix}班"
    
    # 如果没有匹配到任何模式,返回原值
    return class_str

def merge_and_format_excel():
    # 定义文件路径
    path = r'D:\test\20桌面素材\20260604口腔涂氟全园'
    folder_path = path + r"\01园园通下载"
    output_path = path + r'\02园园通全部班级信息合并.xlsx'
    
    # 获取文件夹中的所有Excel文件
    excel_files = [f for f in os.listdir(folder_path) if f.endswith(('.xlsx', '.xls'))]
    
    # if len(excel_files) < 2:
    #     print("234文件夹中Excel文件数量不足2个")
    #     return
    
    # 读取所有Excel文件时指定数据类型为字符串,避免数字精度丢失
    dfs = []
    for file in excel_files[:3]:  # 只处理前两个文件
        file_path = os.path.join(folder_path, file)
        
        # 首先读取第一行来检测列的数据类型
        temp_df = pd.read_excel(file_path, nrows=1)
        
        # 创建dtype字典,将所有列都设置为字符串类型
        dtype_dict = {col: str for col in temp_df.columns}
        
        # 用字符串类型重新读取整个文件
        df = pd.read_excel(file_path, dtype=dtype_dict, keep_default_na=False)
        
        # 特别处理身份证号、学号等可能的长数字列
        for col in df.columns:
            if any(keyword in col for keyword in ['身份证', '证件号', '学号', '幼儿编号', 'ID']):
                # 去除可能的空格和特殊字符
                df[col] = df[col].astype(str).str.strip()
                # 如果是以科学计数法形式出现的数字,进行转换
                df[col] = df[col].apply(lambda x: format_long_number(x))
        
        dfs.append(df)
        print(f"已读取文件: {file}")
    
    # 合并数据
    merged_df = pd.concat(dfs, ignore_index=True)
    
    # 查找包含班级信息的列
    class_columns = [col for col in merged_df.columns if any(keyword in col for keyword in ['班', 'class', '班级'])]
    
    if class_columns:
        for class_col in class_columns:
            print(f"检测到班级列: {class_col}")
            merged_df[class_col] = merged_df[class_col].apply(format_class_name)
    else:
        print("未检测到班级列,跳过格式转换")
    
    # 再次处理所有列,确保数字格式正确
    for col in merged_df.columns:
        merged_df[col] = merged_df[col].apply(format_long_number)
    
    # 保存合并后的文件
    # 使用openpyxl引擎,避免xlsxwriter对长数字的处理问题
    with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
        merged_df.to_excel(writer, index=False)
    
    print(f"文件已保存至: {output_path}")
    print(f"合并完成,共{len(merged_df)}条记录")
    
    # 显示一些样本数据以供验证
    print("\n前5条数据的班级信息:")
    if class_columns:
        for class_col in class_columns:
            print(f"{class_col}列的前5个值:")
            print(merged_df[class_col].head().tolist())
    
    # 特别显示可能的长数字列
    long_num_cols = [col for col in merged_df.columns if any(keyword in col for keyword in ['身份证', '证件号', '学号', '幼儿编号', 'ID'])]
    if long_num_cols:
        print("\n长数字列样本数据:")
        for col in long_num_cols:
            print(f"{col}列的前3个值:")
            print(merged_df[col].head(3).tolist())

# 执行函数
if __name__ == "__main__":
    merge_and_format_excel()

这一步是合并多个表格,因为原来园园通下载的是三个园区,三个Excel,所以需要合并成一个表格,

现在改版后,只有一个包含全部园区全部有的xlsx工作表。其实也不用合并。

02、匹配学号(按学号排序)+按班级拆分单独工作表

根据“00班级信息表里面的学号.xlsx”,把“02园园通全部班级信息合并.xlsx”的姓名添加学号,排序。(没有按照班级拆分单独工作表)

原来班级列的名称是“所在班级”,现在改成“班级名称”

'''
20251217涂氟单制作
1、用合并xls与班级信息表的学号匹配,按学号排队,保存03匹配学号.xlsx

deepseek,阿夏
20251217
'''


import pandas as pd
import os

def format_long_number(value):
    """处理长数字,避免科学计数法和精度丢失"""
    if pd.isna(value) or value == '':
        return value
    
    str_value = str(value).strip()
    
    # 处理科学计数法
    if 'e+' in str_value.lower() or 'e-' in str_value.lower():
        try:
            # 将科学计数法转换为完整数字
            num_value = float(str_value)
            return str(int(num_value)) if num_value.is_integer() else str(num_value)
        except:
            return str_value
    
    # 处理浮点数.0的情况
    if '.' in str_value and str_value.endswith('.0'):
        return str_value[:-2]
    
    # 处理浮点数显示为整数的情况
    if '.' in str_value:
        try:
            # 检查是否可以转换为整数
            float_val = float(str_value)
            if float_val.is_integer():
                return str(int(float_val))
        except:
            pass
    
    return str_value

# 设置路径
path = r'D:\test\20桌面素材\20260604口腔涂氟全园'

# 1. 读取园园通信息表 - 所有列都作为字符串读取
df_main = pd.read_excel(path + r'\02园园通全部班级信息合并.xlsx', dtype=str, keep_default_na=False)

# 2. 读取班级信息表的所有工作表 - 所有列都作为字符串读取
xls = pd.ExcelFile(path + r'\00班级信息表.xlsx')
sheet_names = xls.sheet_names

# 3. 合并所有班级信息表
df_list = []
for sheet in sheet_names:
    df_sheet = pd.read_excel(xls, sheet_name=sheet, dtype=str, keep_default_na=False)
    df_sheet['班级'] = sheet  # 添加班级列
    df_list.append(df_sheet)

df_info = pd.concat(df_list, ignore_index=True)

# 4. 匹配学号
df_merged = pd.merge(df_main, 
                    df_info[['班级', '姓名', '学号']], 
                    left_on=['班级名称', '姓名'], 
                    right_on=['班级', '姓名'], 
                    how='left')

# 5. 移动学号列到最前面
cols = df_merged.columns.tolist()
cols = ['学号'] + [col for col in cols if col != '学号']
df_merged = df_merged[cols]

# 6. 处理所有数字列,避免精度丢失
for col in df_merged.columns:
    df_merged[col] = df_merged[col].apply(format_long_number)

# 7. 对完整匹配结果进行排序并保存
# 确保学号列是数值类型用于排序,但保存时保持字符串格式
df_merged['学号_排序'] = pd.to_numeric(df_merged['学号'], errors='coerce')

# 创建班级排序的映射关系
class_order = {
    '托1班': 1, '托2班': 2, '托3班': 3, '托4班': 4,
    '小1班': 5, '小2班': 6, '小3班': 7, '小4班': 8,'小5班': 9,'小6班': 10,
    '中1班': 11, '中2班': 12, '中3班': 13, '中4班': 14,'中5班': 15,'中6班': 16,
    '大1班': 17, '大2班': 18, '大3班': 19, '大4班':20 , '大5班': 21, '大6班': 22,
}

# 添加临时排序列
df_merged['班级排序'] = df_merged['班级名称'].map(class_order)

# 先按班级排序,再按学号排序
df_merged_sorted = df_merged.sort_values(by=['班级排序', '学号_排序'])

# 删除临时排序列
df_merged_sorted = df_merged_sorted.drop(['班级排序', '学号_排序'], axis=1)

# 保存排序后的完整表格,使用openpyxl引擎避免数字格式问题
with pd.ExcelWriter(path + r'\03匹配学号.xlsx', engine='openpyxl') as writer:
    df_merged_sorted.to_excel(writer, index=False)

匹配学号,只有一个工作表,所有孩子都在这里面,并且按照托、小、中、大顺序排列班级,

按学号排列班级内人员。

03、套用龋齿表需要的内容,按班级拆分Excel工作表

'''
20251217涂氟单制作
1、将03匹配学号.xlsx里面的学号、班级、姓名、身份证号,幼儿编号等数据写入到医保模版指定的列里
2、先生成每个班级的独立Excel文件,再合并所有文件到一个工作簿(每个班级一个工作表)
3、合并完成后删除存放单个文件的文件夹
deepseek,阿夏
20251216
'''

import pandas as pd
import numpy as np
from openpyxl import load_workbook, Workbook
from openpyxl.styles import Alignment
import os
import glob
import shutil  # 用于删除文件夹(含子文件)

# 全局定义上海行政区列表(避免作用域问题)
OUTER_DISTRICT_LIST = [
    '黄浦区', '徐汇区', '长宁区', '静安区', '普陀区', '虹口区', '杨浦区',
    '浦东新区', '宝山区', '嘉定区', '金山区', '松江区', '青浦区', '奉贤区', '崇明区'
]
SHANGHAI_DISTRICTS = ['闵行区'] + OUTER_DISTRICT_LIST

def batch_process_all_classes():
    """批量处理所有班级的医保表格数据(生成单个班级文件)"""
    base_path = r'D:\test\20桌面素材\20260604口腔涂氟全园'
    
    main_data_file = os.path.join(base_path, '03匹配学号.xlsx')
    df_main = pd.read_excel(main_data_file, sheet_name=0)
    
    valid_classes = [cls for cls in df_main['班级名称'].unique() if pd.notna(cls)]
    print(f"✅ 成功识别 {len(valid_classes)} 个班级:{valid_classes}")
    
    for class_name in valid_classes:
        process_single_class(df_main, class_name, base_path)
    
    print(f"\n🎉 所有班级独立文件生成完成!累计处理 {len(valid_classes)} 个班级")
    
    # 生成完成后自动执行合并操作
    merge_class_files_to_one_workbook(base_path)
    
    # 合并完成后删除单个文件的文件夹
    output_dir = os.path.join(base_path, '2025全校学生涂氟单')
    delete_folder(output_dir)

def process_single_class(main_df, class_name, base_path):
    """处理单个班级:加载模板、设置格式、填充数据、保存文件"""
    class_students = main_df[main_df['班级名称'] == class_name].copy()
    student_count_total = len(class_students)
    print(f"\n📌 开始处理班级:{class_name}(共{student_count_total}名学生)")
    
    template_file = os.path.join(base_path, '00模版涂氟单表格.xlsx')
    try:
        workbook = load_workbook(template_file)
        worksheet = workbook.active
    except FileNotFoundError:
        print(f"❌ 模板文件缺失:{template_file},请检查文件路径")
        return
    
    # 全局统一文本格式(E/F列)
    for col_letter in ['E', 'F']:
        for cell in worksheet[col_letter]:
            cell.number_format = '@'
            cell.alignment = Alignment(horizontal='left')
    
    start_row = 2
    max_student_limit = 35
    filled_count = 0
    
    for row_idx, (_, student_info) in enumerate(class_students.iterrows(), start=start_row):
        if filled_count >= max_student_limit:
            print(f"⚠️  班级 {class_name} 学生数超过{max_student_limit}人,仅保留前{max_student_limit}条数据")
            break
        
        filled_count += 1
        print(f"   🔄 处理第{filled_count}名学生:{student_info['姓名']}")
        fill_student_details(worksheet, row_idx, student_info, class_name)
    
    # 创建输出目录并保存文件
    output_dir = os.path.join(base_path, '2025全校学生涂氟单')
    os.makedirs(output_dir, exist_ok=True)
    
    output_filename = f'{class_name}_2025园园通学生涂氟单.xlsx'
    output_path = os.path.join(output_dir, output_filename)
    
    try:
        workbook.save(output_path)
        print(f"✅ 班级 {class_name} 处理完成,文件保存至:{output_path}")
    except PermissionError:
        print(f"❌ 保存失败:{output_path} 已被打开,请关闭后重试")

def fill_student_details(worksheet, row_num, student_data, class_name):
    """填充单个学生的详细信息到表格指定位置"""
    # A列:学号
    if '学号' in student_data and pd.notna(student_data['学号']):
        worksheet[f'A{row_num}'] = str(student_data['学号'])
    
    # B列:姓名
    if '姓名' in student_data and pd.notna(student_data['姓名']):
        worksheet[f'B{row_num}'] = student_data['姓名']

    # N列:民族
    if '民族' in student_data and pd.notna(student_data['民族']):
        worksheet[f'N{row_num}'] = student_data['民族']
    
    # I列:证件号码(身份证号)
    if '证件号码' in student_data and pd.notna(student_data['证件号码']):
        worksheet[f'I{row_num}'] = str(student_data['证件号码'])
        # 强制文本格式,避免身份证号科学计数法显示
        worksheet[f'I{row_num}'].number_format = '@'
    
    # L/M列:性别(女→L列勾,男→M列勾)
    if '性别' in student_data and pd.notna(student_data['性别']):
        gender = student_data['性别'].strip()
        if gender == '女':
            worksheet[f'M{row_num}'] = '✓'
        elif gender == '男':
            worksheet[f'L{row_num}'] = '✓'
  
    # F/G/H列:出生日期(拆分为年/月/日,补零至2位)
    if '出生日期' in student_data and pd.notna(student_data['出生日期']):
        try:
            # 统一转为datetime格式处理,兼容字符串/日期类型
            birth_dt = pd.to_datetime(student_data['出生日期'])
            # 拆分年/月/日并填充到对应列
            worksheet[f'F{row_num}'] = birth_dt.year  # 年
            worksheet[f'G{row_num}'] = f"{birth_dt.month:02d}"  # 月(补零)
            worksheet[f'H{row_num}'] = f"{birth_dt.day:02d}"    # 日(补零)
            # 月/日列强制文本格式,避免Excel自动转数字
            worksheet[f'G{row_num}'].number_format = '@'
            worksheet[f'H{row_num}'].number_format = '@'
        except Exception as e:
            # 异常处理:保留原始值并提示
            worksheet[f'F{row_num}'] = str(student_data['出生日期'])
            print(f"   ⚠️ {student_data['姓名']} 出生日期格式异常:{student_data['出生日期']},错误:{str(e)}")
    
    # J/K列:户口所在地(上海→J列勾,非上海→K列勾)
    if '户口所在地-省份' in student_data and pd.notna(student_data['户口所在地-区县']):
        hukou_district = str(student_data['户口所在地-区县']).strip()
        if hukou_district in SHANGHAI_DISTRICTS:
            worksheet[f'J{row_num}'] = '√'
        else:
            worksheet[f'K{row_num}'] = '√'
    
    # E列:班级(去除最后一位,如"中2班"→"中2")
    worksheet[f'E{row_num}'] = class_name[:-1] if class_name and len(class_name) > 1 else class_name

    # C列:闵行区(固定值)
    worksheet[f'C{row_num}'] = '闵行区'

    # D列:学校名称(固定值)
    worksheet[f'D{row_num}'] = '景谷二幼'

def merge_class_files_to_one_workbook(base_path):
    """将2025全校学生涂氟单文件夹中的所有班级文件合并到一个工作簿(仅复制值,避免格式报错)"""
    # 1. 定义文件夹路径和文件匹配规则
    output_dir = os.path.join(base_path, '2025全校学生涂氟单')
    file_pattern = os.path.join(output_dir, '*_2025园园通学生涂氟单.xlsx')
    class_files = glob.glob(file_pattern)
    
    if not class_files:
        print(f"\n⚠️  未找到待合并的班级文件,检查路径:{output_dir}")
        return
    
    print(f"\n📁 找到 {len(class_files)} 个待合并的班级文件:")
    for f in class_files:
        print(f"   - {os.path.basename(f)}")
    
    # 2. 创建新的整合工作簿
    merged_wb = Workbook()
    # 删除默认的Sheet工作表
    if 'Sheet' in merged_wb.sheetnames:
        merged_wb.remove(merged_wb['Sheet'])
    
    # 3. 逐个读取班级文件,仅复制值到整合工作簿
    for file_path in class_files:
        try:
            # 读取单个班级文件(仅读值,不加载格式,提升效率)
            class_wb = load_workbook(file_path, data_only=True)
            class_ws = class_wb.active
            
            # 提取班级名(从文件名中截取,如"中2班_2025园园通学生涂氟单.xlsx"→"中2班")
            file_name = os.path.basename(file_path)
            class_name = file_name.replace('_2025园园通学生涂氟单.xlsx', '')
            
            # 在整合工作簿中新建工作表,命名为班级名
            new_ws = merged_wb.create_sheet(title=class_name)
            
            # 仅复制单元格的值(跳过格式复制,解决StyleProxy报错)
            for row_idx, row in enumerate(class_ws.iter_rows(values_only=True), start=1):
                for col_idx, cell_value in enumerate(row, start=1):
                    new_ws.cell(row=row_idx, column=col_idx, value=cell_value)
            
            # 对关键列设置文本格式(保证身份证号/日期等不被转格式)
            key_cols = ['A', 'E', 'F', 'G', 'H', 'I']  # 学号、班级、出生日期、身份证号列
            for col_letter in key_cols:
                for row in new_ws.iter_rows(min_row=1, max_row=100):
                    cell = row[ord(col_letter)-ord('A')]
                    cell.number_format = '@'
                    cell.alignment = Alignment(horizontal='left')
            
            print(f"✅ 已合并班级:{class_name}")
        except Exception as e:
            print(f"❌ 合并文件 {file_path} 失败:{str(e)}")
    
    # 4. 保存整合后的工作簿
    merged_file_path = os.path.join(base_path, '04园园通学生涂氟单_班级合并版.xlsx')
    try:
        merged_wb.save(merged_file_path)
        print(f"\n🎉 所有班级文件合并完成!")
        print(f"📑 合并文件保存至:{merged_file_path}")
        print(f"📊 工作簿包含工作表:{merged_wb.sheetnames}")
    except PermissionError:
        print(f"\n❌ 合并文件保存失败:{merged_file_path} 已被打开,请关闭后重试")

def delete_folder(folder_path):
    """删除指定文件夹(含所有子文件/子文件夹),处理权限问题"""
    if not os.path.exists(folder_path):
        print(f"\n📂 文件夹 {folder_path} 不存在,无需删除")
        return
    
    try:
        # rmtree 递归删除文件夹及所有内容
        shutil.rmtree(folder_path)
        print(f"\n🗑️  已成功删除文件夹:{folder_path}")
    except PermissionError:
        print(f"\n❌ 删除文件夹失败:{folder_path} 或其中的文件被占用,请关闭相关Excel文件后手动删除")
    except Exception as e:
        print(f"\n❌ 删除文件夹 {folder_path} 失败:{str(e)}")

# 主程序入口
if __name__ == "__main__":
    base_path = r'D:\test\20桌面素材\20260604口腔涂氟全园'
    try:
        main_data_path = os.path.join(base_path, '03匹配学号.xlsx')
        if not os.path.exists(main_data_path):
            raise FileNotFoundError(f"主数据文件不存在:{main_data_path}")
        
        df_check = pd.read_excel(main_data_path)
        # 调整必要列清单,适配实际业务(移除非必需列,避免误判)
        required_columns = [
            '班级名称', '学号', '姓名', '性别', '证件号码', '出生日期'
        ]
        missing_cols = [col for col in required_columns if col not in df_check.columns]
        if missing_cols:
            raise ValueError(f"主数据文件缺少必要列:{', '.join(missing_cols)}")
        
        print("="*60)
        print("📋 主数据文件信息:")
        print(f"   列名:{df_check.columns.tolist()}")
        print(f"   总行数:{len(df_check)}")
        print(f"   涉及班级:{[cls for cls in df_check['班级名称'].unique() if pd.notna(cls)]}")
        print("="*60)
        
        batch_process_all_classes()
    
    except Exception as main_err:
        print(f"\n❌ 程序执行失败:{str(main_err)}")
        print("请优先检查:1. 文件路径是否正确 2. 主数据文件列是否完整 3. 模板文件是否存在且未被占用")

最后生成每个班级工作表,并获得龋齿表里面的数据

04、制作PDF(只做小2班)

# -*- coding:utf-8 -*- 
'''
目的:口腔检查涂氟单(仅处理小2班)
作者:deepseek,阿夏
日期:20251215
功能:仅处理Excel中「小2班」工作表,生成该班级独立的合并PDF(存放至“合并PDF”文件夹)
'''

# 一、导入相关模块,设定路径
from docxtpl import DocxTemplate
import pandas as pd
import os
import time
from docx2pdf import convert
from PyPDF2 import PdfFileMerger
import shutil

# 配置参数
l = 2  # 1=有背景图,2=无背景图
zpath = r'D:\test\20桌面素材\20260604口腔涂氟全园\\'
temp_word_path = zpath + r'零时Word'  # 临时Word/PDF文件夹
pdf_output_dir = os.path.join(zpath, "02合并PDF")  # 最终PDF统一存放文件夹

# 二、核心函数:处理单个班级(工作表)的数据
def process_class_sheet(sheet_name, sheet_data):
    """
    处理单个班级的Excel数据
    :param sheet_name: 工作表名(班级名)
    :param sheet_data: 该班级的DataFrame数据
    """
    # 1. 创建临时文件夹(每个班级单独的临时目录,避免冲突)
    class_temp_path = os.path.join(temp_word_path, sheet_name)
    try:
        os.makedirs(class_temp_path)
    except FileExistsError:
        pass
    
    # 2. 获取班级数据
    total_people = sheet_data.shape[0]
    print(f"\n===== 开始处理【{sheet_name}】班,共 {total_people} 人 =====")
    
    # 提取列数据(做空值处理,避免报错)
    sheet_data = sheet_data.fillna("")  # 空值替换为空字符串
    num = sheet_data["num"]
    name = sheet_data["name"]
    school = sheet_data["school"]
    classroom = sheet_data["classroom"].astype(str).str.replace('\n', '')  # 去掉换行符
    y = sheet_data["y"]
    m = sheet_data["m"]
    d = sheet_data["d"]
    ID = sheet_data["ID"]
    SH = sheet_data["SH"]
    FSH = sheet_data["FSH"]
    M = sheet_data["M"]
    F = sheet_data["F"]
    dis = sheet_data["dis"]
    nation = sheet_data["nation"]
    
    # 3. 遍历生成单个Word和PDF
    pdf_files = []  # 存储该班级的所有PDF路径
    for i in range(total_people):
        try:
            # 构造渲染数据
            context = {
                "num": str(int(num.iloc[i])),
                "dis": dis.iloc[i],
                "name": name.iloc[i],
                "school": school.iloc[i],
                "classroom": classroom.iloc[i],
                "y": y.iloc[i],
                "m": m.iloc[i],
                "d": d.iloc[i],
                "ID": ID.iloc[i],
                "SH": SH.iloc[i],
                "FSH": FSH.iloc[i],
                "M": M.iloc[i],
                "F": F.iloc[i],
                "nation": nation.iloc[i],
            }
            
            # 加载模板
            if l == 1:
                tpl = DocxTemplate(zpath + '打印单字(有背景).docx')
            else:
                tpl = DocxTemplate(zpath + '打印单字(无背景).docx')
            
            # 生成Word

            sn = int(float(num.iloc[i]))
            
            
            word_file = os.path.join(class_temp_path, f'{sn:02d}.docx')
            tpl.render(context)
            tpl.save(word_file)
            
            # 转换为PDF
            pdf_file = os.path.join(class_temp_path, f'{sn:02d}.pdf')
        
            convert(word_file, pdf_file)
            pdf_files.append(pdf_file)
            
            print(f"  已生成:{sheet_name} - {sn:02d}.pdf")
            time.sleep(1)  # 避免转换过快报错
        except Exception as e:
            print(f"  ❌ 处理第{i+1}条数据失败:{str(e)}")
            continue
    
    # 4. 合并该班级的所有PDF(保存到“合并PDF”文件夹)
    if pdf_files:
        # 创建“合并PDF”文件夹(确保存在)
        os.makedirs(pdf_output_dir, exist_ok=True)
        
        pdf_files.sort()  # 按序号排序
        merger = PdfFileMerger()
        for pdf in pdf_files:
            try:
                merger.append(pdf)
            except:
                pass
        
        # 定义最终PDF文件名(保存到“合并PDF”文件夹)
        bg_flag = "有背景图" if l == 1 else "无背景图"
        final_pdf_name = f"{sheet_name}班涂氟单({total_people}人)({bg_flag}).pdf"
        final_pdf_path = os.path.join(pdf_output_dir, final_pdf_name)
        
        # 保存合并后的PDF
        merger.write(final_pdf_path)
        merger.close()
        print(f"\n✅ 【{sheet_name}】班合并PDF完成:{final_pdf_path}")
    else:
        print(f"\n⚠️  【{sheet_name}】班无有效PDF文件,跳过合并")
    
    # 5. 删除该班级的临时文件夹
    try:
        shutil.rmtree(class_temp_path)
        print(f"🗑️  已删除【{sheet_name}】班临时文件")
    except:
        print(f"⚠️  【{sheet_name}】班临时文件删除失败,请手动清理:{class_temp_path}")

# 三、主流程:仅处理「小2班」工作表
if __name__ == "__main__":
    # 1. 检查Excel文件是否存在
    excel_path = zpath + '04园园通学生涂氟单_班级合并版.xlsx'
    if not os.path.exists(excel_path):
        print(f"❌ 未找到Excel文件:{excel_path}")
        exit()
    
    # 2. 提前创建“合并PDF”文件夹(确保目录存在)
    os.makedirs(pdf_output_dir, exist_ok=True)
    print(f"📂 最终PDF将保存至:{pdf_output_dir}")
    
    # 3. 获取所有工作表名称
    excel_file = pd.ExcelFile(excel_path)
    sheet_names = excel_file.sheet_names
    print(f"📋 Excel中所有工作表:{sheet_names}")
    
    # 4. 仅处理【小2班】工作表(核心修改点)
    target_sheet = "小2班"
    # 先检查目标工作表是否存在,避免报错
    if target_sheet not in sheet_names:
        print(f"❌ 未找到【{target_sheet}】工作表,请检查Excel中工作表名称是否完全一致!")
        exit()
    # 读取小2班工作表数据
    df = pd.read_excel(excel_path, sheet_name=target_sheet)
    # 执行生成逻辑
    process_class_sheet(target_sheet, df)
    
    # 5. 删除总临时文件夹
    try:
        shutil.rmtree(temp_word_path)
        print(f"\n🗑️  已删除总临时文件夹:{temp_word_path}")
    except:
        print(f"\n⚠️  总临时文件夹删除失败,请手动清理:{temp_word_path}")
    
    print(f"\n🎉 【小2班】PDF生成完成!文件已保存至:{pdf_output_dir}")

制作docx和PDF

打印机

卡纸设置(只能竖着放,背面向上)

如果横折放,上部卡板卡不住

打印机设置

因为纸张是竖着放,所以打印机属性设置的时候:

宽140 高210(竖着放)

存在问题:

1、以下是测试错误的打印纸(打印机首选项测试时候,用了210*140横版,所以打出来文字都是垂直90度。)

2、本市户籍列问题

在做这份CSDN记录时,我才发现“本市”“非本市”的地方没有打钩(因为原来的列名是:户口所在地区,而现在的列名是户口所在地-区县)重新生成后才显示有√,

已经打印了,所以看着Excel,手动打钩

3、性别勾选错误

随后发现男女位置都错了(我们班是先女后男,现在显示的是前面都是男(male))

把写入列的字母修改

但是已经打印的不好再打印一次,就用修正液修改,再用水笔打钩了。

感悟:

忙着测试打印位置,没有注意到“户籍”缺失勾选和“性别”勾选错误。本次都是因为要做CSDN记录才复查一遍,才发现了这些问题。并进行代码重修。

下次一定要测试第一张时,仔细看每一项的内容的位置是否正确。

更多推荐