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.config_page import create_config_page
|
||||||
from ui.views.home_page import create_home_page
|
from ui.views.home_page import create_home_page
|
||||||
from ui.views.data_page import create_data_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
|
from utils.font_utils import install_fonts_from_directory
|
||||||
|
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
@@ -95,6 +96,11 @@ def data_page():
|
|||||||
create_data_page()
|
create_data_page()
|
||||||
|
|
||||||
|
|
||||||
|
@ui.page("/signature")
|
||||||
|
def signature_page(folder: str = ""):
|
||||||
|
create_signature_page(folder)
|
||||||
|
|
||||||
|
|
||||||
# 4. 启动时钩子
|
# 4. 启动时钩子
|
||||||
async def startup_check():
|
async def startup_check():
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from nicegui import ui
|
from nicegui import ui
|
||||||
from config.config import load_config
|
from config.config import load_config
|
||||||
from ui.core.state import app_state
|
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 (
|
from utils.generate_utils import (
|
||||||
@@ -10,7 +10,6 @@ from utils.generate_utils import (
|
|||||||
generate_convert_pdf,
|
generate_convert_pdf,
|
||||||
generate_report,
|
generate_report,
|
||||||
generate_zodiac,
|
generate_zodiac,
|
||||||
generate_signature,
|
|
||||||
)
|
)
|
||||||
from utils.file_utils import open_folder
|
from utils.file_utils import open_folder
|
||||||
|
|
||||||
@@ -71,7 +70,18 @@ def create_home_page():
|
|||||||
func_btn("📊 生成报告 (PPT)", generate_report)
|
func_btn("📊 生成报告 (PPT)", generate_report)
|
||||||
func_btn("📑 格式转换 (PDF)", generate_convert_pdf)
|
func_btn("📑 格式转换 (PDF)", generate_convert_pdf)
|
||||||
func_btn("🐂 生肖转化 (生日)", generate_zodiac)
|
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