import os import traceback from loguru import logger from nicegui import ui from pptx import Presentation from config.config import load_config from utils.file_utils import open_folder def create_signature_page(folder: str = ""): ui.add_head_html('') # 添加样式 ui.add_head_html( """ """ ) with ui.header().classes("app-header items-center justify-between shadow-md"): # 左侧:图标和标题 with ui.row().classes("items-center gap-2"): ui.image("/assets/icon.ico").classes("w-8 h-8").props("fit=contain") ui.label("尚城幼儿园成长报告助手").classes("text-xl font-bold") # 右侧:署名 + 配置按钮 with ui.row().classes("items-center gap-4"): ui.label("By 寒寒 | 这里的每一份评语都充满爱意").classes( "text-xs opacity-90" ) ui.button(icon="home", on_click=lambda: ui.navigate.to("/")).props( "flat round color=white" ) with ui.card().classes("w-full"): ui.label("💴 园长签名").classes("section-title") with ui.row().classes("w-full items-center justify-between"): with ui.row().classes("flex-1 items-center"): ui.label("📁 当前目录:").classes( "text-sm text-white border bg-[#2e8b57] p-2 rounded" ) ui.label(f"{folder}").classes("text-sm text-gray-600") with ui.row().classes("items-center"): ui.button( "💴 一键签名", on_click=lambda: sign_all_files(folder), ).props().classes() ui.button( "📂 打开文件夹", on_click=lambda: open_folder(folder), ).props("outline").classes() ui.button( "🔄 刷新数据", on_click=lambda: for_file_list(list_card, folder), ).props("outline").classes() list_card = ui.card().classes("w-full p-4 gap-4") for_file_list(list_card, folder) # 遍历目录 def for_file_list(list_card, folder): # 清空旧内容 list_card.clear() files = get_signature_files(folder) with list_card: ui.label(f"📄 找到 {len(files)} 个 PPT 文件").classes( "text-sm text-gray-600 mb-4" ) # 存储选中的文件 selected_files = [] def toggle_file(file_name): if file_name in selected_files: selected_files.remove(file_name) else: selected_files.append(file_name) # 创建可滚动的文件列表 with ui.grid(columns=2).classes("file-list"): for ppt_file in files: with ui.row().classes( "w-full justify-between items-center file-item p-3 rounded mb-2" ): with ui.row().classes("flex-1 items-center"): ui.checkbox( on_change=lambda e, f=ppt_file: toggle_file(f) ).classes("mr-3") ui.label(ppt_file).classes("flex-1 text-sm") with ui.row().classes("items-center gap-2"): # 打开文件按钮 ui.button( "📂 打开", on_click=lambda f=ppt_file: open_folder( os.path.join(folder, f) ), ).props("outline").classes("text-xs") # 签名按钮 ui.button( "💴 签名", on_click=lambda f=ppt_file: ( sign_file(folder, f), ui.notify(f"签名完成: {f}", type="positive"), ), ).props("outline").classes("text-xs") def get_signature_files(folder: str) -> list: """获取目录下所有 PPT 文件""" if not os.path.exists(folder): return [] files = [] for filename in os.listdir(folder): if not filename.startswith(".") and filename.endswith(".pptx"): files.append(filename) return sorted(files) def sign_file(folder, file_name: str): """ 生成园长签名(不依赖占位符,直接在指定位置添加) :param folder: PPT 文件所在目录 :param file_name: PPT 文件名称 """ try: # 1. 加载配置文件 config = load_config() except Exception as e: logger.error(f"配置文件获取失败: {str(e)}") # 打印详细报错位置,方便调试 logger.error(traceback.format_exc()) try: # 2. 等待签名文件路径 file_path = os.path.join(folder, file_name) logger.info(f"开始生成签名,PPT文件:{file_name}") # 加载签名图片路径 img_path = config.get("signature_image") if not img_path or not os.path.exists(img_path): logger.error(f"签名图片不存在: {img_path}") logger.warning(f"⚠️ 警告: 缺少签名照片('signature')") return logger.info(f"签名图片存在: {img_path}") # 从配置文件获取签名位置信息,如果没有则使用默认值 signature_left = config.get("signature_left", 2987040) # 左位置 signature_top = config.get("signature_top", 8273415) # 上位置 signature_width = config.get("signature_width", 1800000) # 宽度 signature_height = config.get("signature_height", 720000) # 高度 # 导入必要的模块 from utils.image_utils import get_corrected_image_stream # 打开 PPT 对象 prs = Presentation(file_path) # 获取第二张幻灯片 (索引为1) slide = prs.slides[1] # 获取修正后的图片流 img_stream = get_corrected_image_stream(img_path) # 直接在指定位置添加签名图片 slide.shapes.add_picture( img_stream, signature_left, signature_top, signature_width, signature_height, ) # 保存修改后的 PPT prs.save(file_path) logger.info(f"签名完成,PPT文件:{file_name}") except Exception as e: logger.error(f"generate_signature 发生未知错误: {e}") # 打印详细报错位置,方便调试 logger.error(traceback.format_exc()) return str(e) def sign_selected_files(folder: str, files: list): """为选中的文件进行签名""" total_files = len(files) logger.info(f"开始生成签名,共 {total_files} 个文件") for i, file_name in enumerate(files): sign_file(folder, file_name) logger.info(f"已为 {total_files} 个文件签名") ui.notify(f"签名完成: {total_files} 个文件", type="positive") def sign_all_files(folder: str): """为目录下所有文件进行签名""" files = get_signature_files(folder) if files: sign_selected_files(folder, files) total_files = len(files) ui.notify(f"签名完成: {total_files} 个文件", type="positive")