【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

内容分享13小时前发布
0 0 0

一、背景需求:

20251114 课题中期指导,本学期共有3个大、3个小课题立项

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

前期做了上下学期资料批量的课题档案袋,刚开始有很多的问题——日期格式必须换成年月日的文本格式。文本占位符字母写错等。

【办公类-89-01】20250103用“课题阶段资料模版“批量制作“7个课题档案袋“【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书https://mp.csdn.net/mp_blog/creation/editor/144920339

本次继续修改代码,完善档案袋内容。

二、收集信息

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

1、从证书网上下载证书,做好文件命名

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

2、从课题上报网站下载申请书,做好文件命名

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

3、把信息贴入去年做好的模版里,把日期信息修改掉

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

补全新信息

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

共享文档,请课题负责人写组室成员和组室

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

填完后下载

三、代码修改

主要修改内容

1、文本占位符修改:部分模版的字母写错。

2、区级一般课题最后加一个“09结题报告“、区级小课题最后加09验收表。

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

3、验收表需要修改每次的届次“上次是16届, 本次是17届”

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

4、把下载的申请书、立项证书,按照文件名的姓名复制到指定的文件夹里

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

代码展示

为了实现同名的申请书WORD和立项书图片的转移,用豆包写了无数次(将路径都上传,才能让豆包理解意图。)

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书



 
'''
根据课题组成员名单制作课题阶段资料(上下学期)的个人模版(包含个人的课题信息),
将立项书图片和申请书WORD放入指定文件夹
大课题有结题报告,小课题有验收表
Deepseek、阿夏
2025年11月15日
'''
 
from docxtpl import DocxTemplate
import pandas as pd
import os
import time
import xlrd
from docx.shared import Inches
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
import shutil
 
print('----1、第一次新WORD制作--------')
# 基础路径(使用原始字符串避免转义问题)
base_path = r'C:Usersjg2yXRZOneDrive桌面2025111上下学期课题模版批量1模版'
print(f"基础路径: {base_path}")
 
# 配置参数(集中管理,便于修改)
# 1. 文件源目录(图片和WORD分开存储)
path=r'C:Usersjg2yXRZOneDrive桌面2025111上下学期课题模版批量0立项书图片和表格'
IMG_SOURCE_DIR = path+r'2立项书'  # 图片源目录(01立项书文件夹)
WORD_SOURCE_DIR = path+r'1申请书'  # WORD源目录(02课题认定书文件夹)
# 2. 目标模版文件名(需与“01x学期(docx)”文件夹中的模版名完全一致)
IMG_TARGET_TPL = '02课题认定书(已下载图片).docx'  # 图片对应的模版(01申请书)
WORD_TARGET_TPL = '01课题申请书(已下载WORD).docx'  # WORD对应的模版(02认定书)
# 3. 图片尺寸
IMG_WIDTH = Inches(18)
IMG_HEIGHT = Inches(27)
SEMESTERS = ['上', '下']  # 学期列表
 
 
def get_target_file(teacher_name, source_dir, file_suffix):
    """根据教师姓名查找指定类型文件(图片/WORD)"""
    for file in os.listdir(source_dir):
        if teacher_name in file and file.lower().endswith(file_suffix):
            return os.path.join(source_dir, file)
    return None
 
 
def insert_image_to_docx(docx_path, img_path, width, height):
    """将图片插入到docx末尾,居中对齐"""
    try:
        doc = DocxTemplate(docx_path)
        para = doc.docx.add_paragraph() if len(doc.docx.paragraphs) == 0 else doc.docx.paragraphs[-1]
        run = para.add_run()
        run.add_picture(img_path, width=width, height=height)
        para.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
        doc.save(docx_path)
        print(f"✅ 图片插入成功:{os.path.basename(docx_path)}")
        return True
    except Exception as e:
        print(f"❌ 图片插入失败:{str(e)}")
        return False
 
 
def delete_level3_docx(docx_path, folder_desc):
    """删除3级文件夹内的原docx(标注文件夹类型)"""
    try:
        if os.path.exists(docx_path) and docx_path.endswith('.docx'):
            os.remove(docx_path)
            print(f"✅ 已删除{folder_desc}3级文件夹原docx:{os.path.basename(docx_path)}")
            return True
    except Exception as e:
        print(f"❌ 删除{folder_desc}3级文件夹原docx失败:{str(e)}")
    return False
 
 
def copy_file_to_target_folder(teacher_name, source_dir, target_level3_dir, file_type, folder_desc):
    """
    复制文件到对应3级文件夹(01/02分类)
    :param folder_desc: 文件夹描述(“01立项书”/“02课题认定书”)
    """
    # 定义文件后缀和描述
    if file_type == 'img':
        suffix = ('.jpg', '.png')
        file_type_desc = '图片'
    else:
        suffix = ('.docx', '.doc')
        file_type_desc = 'WORD文件'
    
    # 查找文件
    file_path = get_target_file(teacher_name, source_dir, suffix)
    if not file_path:
        print(f"❌ 未找到{teacher_name}的{file_type_desc}({folder_desc}源目录:{source_dir})")
        return False
    
    # 复制到对应3级文件夹
    file_dest = os.path.join(target_level3_dir, os.path.basename(file_path))
    try:
        shutil.copy2(file_path, file_dest)
        print(f"✅ {folder_desc}的{file_type_desc}复制成功:{os.path.basename(file_dest)}(存入对应3级文件夹)")
        return True
    except Exception as e:
        print(f"❌ {folder_desc}的{file_type_desc}复制失败:{str(e)}")
        return False
 
 
# 1. 读取课题信息统计表
excel_path = os.path.join(base_path, '总课题信息统计表.xlsx')
if not os.path.exists(excel_path):
    print(f"❌ 课题信息统计表不存在:{excel_path}")
    exit()
 
try:
    workbook = xlrd.open_workbook(excel_path)
    sheet = workbook.sheet_by_index(0)
    print(f"✅ 成功读取统计表,共{sheet.nrows-1}个课题")
except Exception as e:
    print(f"❌ 读取统计表失败:{str(e)}")
    exit()
 
 
# 2. 遍历上下学期处理课题
for semester in SEMESTERS:
    print(f"
===== 处理【{semester}学期】=====")
    semester_template_dir = os.path.join(base_path, f'01{semester}学期(docx)')
    if not os.path.exists(semester_template_dir):
        print(f"❌ 学期模版文件夹不存在:{semester_template_dir}")
        continue
    
    # 获取所有docx模版
    template_files = []
    for root, _, files in os.walk(semester_template_dir):
        for file in files:
            if file.endswith('.docx'):
                template_files.append((file, os.path.join(root, file)))
    
    if len(template_files) == 0:
        print(f"❌ {semester}学期无docx模版")
        continue
    print(f"✅ 找到{len(template_files)}个docx模版")
 
 
    # 3. 遍历每个课题
    for row_idx in range(1, sheet.nrows):
        row_data = sheet.row_values(row_idx, start_colx=4, end_colx=11)
        valid_days = [cell for cell in row_data if cell is not None and str(cell).strip() != '']
        print(f"
----- 处理第{row_idx}行课题(有效天数:{len(valid_days)})-----")
 
        # 读取课题核心信息
        try:
            df = pd.read_excel(excel_path)
            project = df.iloc[row_idx-1]
            proj_num = project['num']
            teacher_name = str(project['name']).strip()
            proj_type = str(project['item']).strip()
        except Exception as e:
            print(f"❌ 读取课题{row_idx}信息失败:{str(e)}")
            continue
 
        if teacher_name in ['nan', '']:
            print(f"❌ 课题{row_idx}无主持人,跳过")
            continue
        print(f"课题主持人:{teacher_name}(类型:{proj_type})")
 
 
        # 4. 遍历每个模版生成文件(分01申请书和02认定书处理)
        # 4. 遍历每个模版生成文件(分01申请书和02认定书处理)
        for tpl_name, tpl_path in template_files:
            print(f"
处理模版:{tpl_name}")
            # 小课题跳过指定模版
            if proj_type != '区级一般':
                if (semester == '上' and tpl_name == '03开题报告(例举).docx') or 
                (semester == '下' and tpl_name == '01中期报告(举例).docx') or 
                (semester == '下' and tpl_name == '09结题报告封面.docx') :
                    print(f"⚠️  小课题跳过模版:{tpl_name}")
                    continue
            elif proj_type != '区级小课题':
                if  (semester == '下' and tpl_name == '10闵行区第X届教学小课题研究过程性材料汇总简表.docx') :
                    print(f"⚠️  区级一般跳过模版:{tpl_name}")
                    continue
 
            # 构建上下文(保留原所有变量)
            context = {
                "num": project['num'],
                "title": str(project['title']).strip(),
                "name": teacher_name,
                "member": str(project['member']).strip(),
                "item": proj_type,
                "number": str(project['number']).strip(),
                "group": str(project['group']).strip(),
                "master": str(project['master']).strip(),
                "year1": project['year1'],
                "month1": project['month1'],
                "year2": project['year2'],
                "month2": project['month2'],
                "first": str(project['first']).strip(),
                "second": str(project['second']).strip(),
                "third": str(project['third']).strip(),
                "d11": str(project['d11']).strip(),
                "d12": str(project['d12']).strip(),
                "d21": str(project['d21']).strip(),
                "d22": str(project['d22']).strip(),
                "d31": str(project['d31']).strip(),
                "d32": str(project['d32']).strip(),
                "start": str(project['start']).strip(),
                "end": str(project['end']).strip(),
                "month3": project['month3'],
                "month4": project['month4'],
                "forth": str(project['forth']).strip(),
                "fifth": str(project['fifth']).strip(),
                "sixth": str(project['sixth']).strip(),
                "d41": str(project['d41']).strip(),
                "d42": str(project['d42']).strip(),
                "d51": str(project['d51']).strip(),
                "d52": str(project['d52']).strip(),
                "d61": str(project['d61']).strip(),
                "d62": str(project['d62']).strip(),
                "xnum": str(int(project['xnum'])) if pd.notna(project['xnum']) and isinstance(project['xnum'], (int, float)) else "",  # 对应表格中的届数(如17)
            }
 
            # -------------------------- 核心修改:同步更新3级文件夹名称 --------------------------
            # 1. 动态生成新的模版名(用于文件和文件夹)
            if tpl_name == '10闵行区第X届教学小课题研究过程性材料汇总简表.docx':
                # 替换“X届”为具体届数(如17届)
                new_tpl_name = f'10闵行区第{context["xnum"]}届教学小课题研究过程性材料汇总简表.docx'
                # 生成3级文件夹名(教师名 + 新模版名(去掉.docx后缀))
                level3_folder_name = f'{teacher_name} {new_tpl_name[:-5]}'
            else:
                # 其他模版保持原逻辑
                new_tpl_name = tpl_name
                level3_folder_name = f'{teacher_name} {tpl_name[:-5]}'
 
            # 2. 生成文件夹路径(使用新的3级文件夹名)
            project_folder = f"{int(proj_num):02d}{teacher_name}_{proj_type}_课题阶段资料"
            level2_dir = os.path.join(base_path, '10批量打包', project_folder, f'01{semester}学期')  # 2级:学期文件夹(保留原docx)
            level3_dir = os.path.join(level2_dir, level3_folder_name)  # 3级:使用新文件夹名
            os.makedirs(level3_dir, exist_ok=True)
            os.makedirs(level2_dir, exist_ok=True)
 
            # 3. 生成docx路径(使用新文件名)
            target_docx_level3 = os.path.join(level3_dir, f'{teacher_name} {new_tpl_name}')
            target_docx_level2 = os.path.join(level2_dir, f'{teacher_name} {new_tpl_name}')
 
            # 渲染保存docx(后续逻辑不变)
            try:
                tpl = DocxTemplate(tpl_path)
                tpl.render(context)
                tpl.save(target_docx_level3)
                tpl.save(target_docx_level2)
                print(f"✅ 生成docx:3级文件夹({os.path.basename(target_docx_level3)})、2级文件夹({os.path.basename(target_docx_level2)})")
            except Exception as e:
                print(f"❌ 生成docx失败:{str(e)}")
                continue
 
            # 5. 分模版处理文件存储(01申请书存图片,02认定书存WORD)
            # 5.1 处理01课题申请书:复制图片到对应3级文件夹
            if tpl_name == IMG_TARGET_TPL:
                print(f"
📷 处理{teacher_name}的01课题申请书(需存入图片)")
                # 复制图片到01申请书的3级文件夹
                img_copy_ok = copy_file_to_target_folder(
                    teacher_name=teacher_name,
                    source_dir=IMG_SOURCE_DIR,
                    target_level3_dir=level3_dir,
                    file_type='img',
                    folder_desc="01立项书"
                )
                # 图片复制成功则删除该文件夹原docx
                if img_copy_ok:
                    delete_level3_docx(target_docx_level3, "01课题申请书")
 
            # 5.2 处理02课题认定书:复制WORD到对应3级文件夹
            elif tpl_name == WORD_TARGET_TPL:
                print(f"
📄 处理{teacher_name}的02课题认定书(需存入WORD)")
                # 复制WORD到02认定书的3级文件夹
                word_copy_ok = copy_file_to_target_folder(
                    teacher_name=teacher_name,
                    source_dir=WORD_SOURCE_DIR,
                    target_level3_dir=level3_dir,
                    file_type='word',
                    folder_desc="02课题认定书"
                )
                # WORD复制成功则删除该文件夹原docx
                if word_copy_ok:
                    delete_level3_docx(target_docx_level3, "02课题认定书")
 
 
# 6. 批量打包
print(f"
===== 开始打包ZIP ======")
zip_source_dir = os.path.join(base_path, '10批量打包')
zip_target_dir = os.path.join(base_path, '11rar')
os.makedirs(zip_target_dir, exist_ok=True)
 
if os.path.exists(zip_source_dir):
    for folder_name in os.listdir(zip_source_dir):
        folder_path = os.path.join(zip_source_dir, folder_name)
        if os.path.isdir(folder_path):
            zip_path = os.path.join(zip_target_dir, folder_name)
            try:
                shutil.make_archive(zip_path, 'zip', folder_path)
                print(f"✅ 打包成功:{folder_name}.zip")
            except Exception as e:
                print(f"❌ 打包失败{folder_name}:{str(e)}")
else:
    print(f"❌ 打包源文件夹不存在:{zip_source_dir}")
 
 
print(f"
===== 所有操作完成!=====")
time.sleep(15)

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

“区级一般课题阶段资料”的内容(有中期报告、开题报告、结题报告)

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

“区级小课题阶段资料”的内容(没有有中期报告、开题报告、结题报告,但有小课题验收表)

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

解析:

1、文本占位符,就是把各个WORD模版里面的基本信息,都做成占位符,便于批量写入个人信息

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

2、通过模版制作,可以提升基本信息的正确性,在1月上学期资料收集、6月下学期资料收集时,检查者就不用为了这些细枝末节的小问题,反复提示负责人修改,毕竟他们只是偶尔做一个课题,不需要去记忆这些小细节的写法。更多的精力应该用在研究实践过程中。

成果应用

在生成文件夹的同时,还做了rar文件,便于发送

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

模版的话,文字大小都差不多。

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

【办公类-89-02】20251115优化“课题阶段资料模版“批量制作“6个课题档案袋”插入证书和申请书

五、后续思考

因为普通老师不怎么想写课题。本次课题都是组长再写,这次的课题资料批量模版很受组长们欢迎。

我希望他们能开发出更多文本占位符的批量需求。让编程更好服务更多教师、幼儿、家长。

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...