Files
growth_report/ui/views/signature_page.py
2026-01-30 00:19:09 +08:00

216 lines
7.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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")