fix:实现园长签名页面
This commit is contained in:
6
main.py
6
main.py
@@ -13,6 +13,7 @@ from ui.core.logger import setup_logger
|
||||
from ui.views.config_page import create_config_page
|
||||
from ui.views.home_page import create_home_page
|
||||
from ui.views.data_page import create_data_page
|
||||
from ui.views.signature_page import create_signature_page
|
||||
from utils.font_utils import install_fonts_from_directory
|
||||
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
@@ -95,6 +96,11 @@ def data_page():
|
||||
create_data_page()
|
||||
|
||||
|
||||
@ui.page("/signature")
|
||||
def signature_page(folder: str = ""):
|
||||
create_signature_page(folder)
|
||||
|
||||
|
||||
# 4. 启动时钩子
|
||||
async def startup_check():
|
||||
try:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from nicegui import ui
|
||||
from config.config import load_config
|
||||
from ui.core.state import app_state
|
||||
from ui.core.task_runner import run_task
|
||||
from ui.core.task_runner import run_task, select_folder
|
||||
|
||||
# 导入业务函数
|
||||
from utils.generate_utils import (
|
||||
@@ -10,7 +10,6 @@ from utils.generate_utils import (
|
||||
generate_convert_pdf,
|
||||
generate_report,
|
||||
generate_zodiac,
|
||||
generate_signature,
|
||||
)
|
||||
from utils.file_utils import open_folder
|
||||
|
||||
@@ -71,7 +70,18 @@ def create_home_page():
|
||||
func_btn("📊 生成报告 (PPT)", generate_report)
|
||||
func_btn("📑 格式转换 (PDF)", generate_convert_pdf)
|
||||
func_btn("🐂 生肖转化 (生日)", generate_zodiac)
|
||||
func_btn("💴 园长一键签名", generate_signature)
|
||||
|
||||
# 签名按钮
|
||||
async def on_signature_click():
|
||||
selected_folder = await select_folder()
|
||||
if selected_folder:
|
||||
ui.navigate.to(f"/signature?folder={selected_folder}")
|
||||
else:
|
||||
ui.notify("未选择目录", type="warning")
|
||||
|
||||
ui.button("💴 园长签名", on_click=on_signature_click).props(
|
||||
f"outline"
|
||||
).classes("w-full")
|
||||
|
||||
# === 下方双栏布局 ===
|
||||
# 数据管理
|
||||
|
||||
213
ui/views/signature_page.py
Normal file
213
ui/views/signature_page.py
Normal file
@@ -0,0 +1,213 @@
|
||||
from nicegui import ui
|
||||
import os
|
||||
from config.config import load_config
|
||||
from utils.file_utils import open_folder
|
||||
from loguru import logger
|
||||
import traceback
|
||||
from pptx import Presentation
|
||||
|
||||
|
||||
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("config.toml")
|
||||
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")
|
||||
Reference in New Issue
Block a user