216 lines
7.9 KiB
Python
216 lines
7.9 KiB
Python
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('<link href="/assets/style.css" rel="stylesheet" />')
|
||
|
||
# 添加样式
|
||
ui.add_head_html(
|
||
"""
|
||
<style>
|
||
.file-list { max-height: 450px; overflow-y: auto; }
|
||
.file-list::-webkit-scrollbar {
|
||
width: 6px;
|
||
}
|
||
.file-list::-webkit-scrollbar-track {
|
||
background: #f1f1f1;
|
||
border-radius: 3px;
|
||
}
|
||
.file-list::-webkit-scrollbar-thumb {
|
||
background: #c1c1c1;
|
||
border-radius: 3px;
|
||
}
|
||
.file-list::-webkit-scrollbar-thumb:hover {
|
||
background: #a1a1a1;
|
||
}
|
||
.file-item { transition: background-color 0.2s ease; }
|
||
.file-item:hover { background-color: #f8f9fa; }
|
||
</style>
|
||
"""
|
||
)
|
||
|
||
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")
|