fix:优化PDF转换逻辑
This commit is contained in:
81
.idea/workspace.xml
generated
81
.idea/workspace.xml
generated
@@ -5,13 +5,23 @@
|
|||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="41690157-d51b-4dae-98de-6b96990d681a" name="更改" comment="fix:优化一些命名规范">
|
<list default="true" id="41690157-d51b-4dae-98de-6b96990d681a" name="更改" comment="fix:优化一些命名规范">
|
||||||
|
<change afterPath="$PROJECT_DIR$/ui/views/convert_pdf_page.py" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/main.py" beforeDir="false" afterPath="$PROJECT_DIR$/main.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/ui/views/home_page.py" beforeDir="false" afterPath="$PROJECT_DIR$/ui/views/home_page.py" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
</component>
|
</component>
|
||||||
|
<component name="FileTemplateManagerImpl">
|
||||||
|
<option name="RECENT_TEMPLATES">
|
||||||
|
<list>
|
||||||
|
<option value="Python Script" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
<component name="Git.Settings">
|
<component name="Git.Settings">
|
||||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
</component>
|
</component>
|
||||||
@@ -24,26 +34,51 @@
|
|||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
<option name="showLibraryContents" value="true" />
|
<option name="showLibraryContents" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PropertiesComponent">{
|
<component name="PropertiesComponent"><![CDATA[{
|
||||||
"keyToString": {
|
"keyToString": {
|
||||||
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
||||||
"Python.main_nicegui.executor": "Run",
|
"Python.main.executor": "Run",
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
"Python.main_nicegui.executor": "Run",
|
||||||
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
"RunOnceActivity.git.unshallow": "true",
|
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
||||||
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
"RunOnceActivity.git.unshallow": "true",
|
||||||
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
||||||
"git-widget-placeholder": "master",
|
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||||
"node.js.detected.package.eslint": "true",
|
"git-widget-placeholder": "master",
|
||||||
"node.js.detected.package.tslint": "true",
|
"node.js.detected.package.eslint": "true",
|
||||||
"node.js.selected.package.eslint": "(autodetect)",
|
"node.js.detected.package.tslint": "true",
|
||||||
"node.js.selected.package.tslint": "(autodetect)",
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
"nodejs_package_manager_path": "npm",
|
"node.js.selected.package.tslint": "(autodetect)",
|
||||||
"settings.editor.selected.configurable": "preferences.lookFeel",
|
"nodejs_package_manager_path": "npm",
|
||||||
"vue.rearranger.settings.migration": "true"
|
"settings.editor.selected.configurable": "preferences.lookFeel",
|
||||||
|
"vue.rearranger.settings.migration": "true"
|
||||||
}
|
}
|
||||||
}</component>
|
}]]></component>
|
||||||
<component name="RunManager">
|
<component name="RunManager" selected="Python.main">
|
||||||
|
<configuration name="main" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||||
|
<module name="growth_report" />
|
||||||
|
<option name="ENV_FILES" value="" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="PARENT_ENVS" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="PYTHONUNBUFFERED" value="1" />
|
||||||
|
</envs>
|
||||||
|
<option name="SDK_HOME" value="" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
|
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||||
|
<option name="RUN_TOOL" value="" />
|
||||||
|
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main.py" />
|
||||||
|
<option name="PARAMETERS" value="" />
|
||||||
|
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||||
|
<option name="EMULATE_TERMINAL" value="false" />
|
||||||
|
<option name="MODULE_MODE" value="false" />
|
||||||
|
<option name="REDIRECT_INPUT" value="false" />
|
||||||
|
<option name="INPUT_FILE" value="" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
<configuration name="main_nicegui" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
<configuration name="main_nicegui" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||||
<module name="growth_report" />
|
<module name="growth_report" />
|
||||||
<option name="ENV_FILES" value="" />
|
<option name="ENV_FILES" value="" />
|
||||||
@@ -70,6 +105,7 @@
|
|||||||
</configuration>
|
</configuration>
|
||||||
<recent_temporary>
|
<recent_temporary>
|
||||||
<list>
|
<list>
|
||||||
|
<item itemvalue="Python.main" />
|
||||||
<item itemvalue="Python.main_nicegui" />
|
<item itemvalue="Python.main_nicegui" />
|
||||||
</list>
|
</list>
|
||||||
</recent_temporary>
|
</recent_temporary>
|
||||||
@@ -77,8 +113,8 @@
|
|||||||
<component name="SharedIndexes">
|
<component name="SharedIndexes">
|
||||||
<attachedChunks>
|
<attachedChunks>
|
||||||
<set>
|
<set>
|
||||||
<option value="bundled-js-predefined-d6986cc7102b-9b0f141eb926-JavaScript-PY-253.29346.142" />
|
<option value="bundled-js-predefined-d6986cc7102b-9b0f141eb926-JavaScript-PY-253.29346.308" />
|
||||||
<option value="bundled-python-sdk-f2b7a9f6281b-6e1f45a539f7-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-253.29346.142" />
|
<option value="bundled-python-sdk-ca5e2b39c7df-6e1f45a539f7-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-253.29346.308" />
|
||||||
</set>
|
</set>
|
||||||
</attachedChunks>
|
</attachedChunks>
|
||||||
</component>
|
</component>
|
||||||
@@ -100,6 +136,8 @@
|
|||||||
<workItem from="1768312728552" duration="228000" />
|
<workItem from="1768312728552" duration="228000" />
|
||||||
<workItem from="1768312972093" duration="486000" />
|
<workItem from="1768312972093" duration="486000" />
|
||||||
<workItem from="1768314152581" duration="7000" />
|
<workItem from="1768314152581" duration="7000" />
|
||||||
|
<workItem from="1769696481591" duration="57000" />
|
||||||
|
<workItem from="1769696548056" duration="2806000" />
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00001" summary="fix:修复一些BUG">
|
<task id="LOCAL-00001" summary="fix:修复一些BUG">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
@@ -159,6 +197,7 @@
|
|||||||
<option name="REARRANGE_BEFORE_PROJECT_COMMIT" value="true" />
|
<option name="REARRANGE_BEFORE_PROJECT_COMMIT" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
||||||
|
<SUITE FILE_PATH="coverage/growth_report$main.coverage" NAME="main 覆盖结果" MODIFIED="1769699312262" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||||
<SUITE FILE_PATH="coverage/growth_report$main_nicegui.coverage" NAME="main_nicegui 覆盖结果" MODIFIED="1766329725535" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
<SUITE FILE_PATH="coverage/growth_report$main_nicegui.coverage" NAME="main_nicegui 覆盖结果" MODIFIED="1766329725535" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
9
main.py
9
main.py
@@ -7,12 +7,12 @@ from nicegui import ui, app, run, native
|
|||||||
from screeninfo import get_monitors
|
from screeninfo import get_monitors
|
||||||
|
|
||||||
from config.config import load_config
|
from config.config import load_config
|
||||||
|
|
||||||
# 导入我们的模块
|
# 导入我们的模块
|
||||||
from ui.core.logger import setup_logger
|
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.convert_pdf_page import create_convert_pdf_page
|
||||||
from ui.views.data_page import create_data_page
|
from ui.views.data_page import create_data_page
|
||||||
|
from ui.views.home_page import create_home_page
|
||||||
from ui.views.signature_page import create_signature_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
|
||||||
|
|
||||||
@@ -101,6 +101,10 @@ def signature_page(folder: str = ""):
|
|||||||
create_signature_page(folder)
|
create_signature_page(folder)
|
||||||
|
|
||||||
|
|
||||||
|
@ui.page("/convert_pdf")
|
||||||
|
def convert_pdf_page(folder: str = ""):
|
||||||
|
create_convert_pdf_page(folder)
|
||||||
|
|
||||||
# 4. 启动时钩子
|
# 4. 启动时钩子
|
||||||
async def startup_check():
|
async def startup_check():
|
||||||
try:
|
try:
|
||||||
@@ -122,5 +126,4 @@ if __name__ in {"__main__", "__mp_main__"}:
|
|||||||
native=True,
|
native=True,
|
||||||
window_size=calculated_size,
|
window_size=calculated_size,
|
||||||
port=native.find_open_port(), # 自动寻找端口
|
port=native.find_open_port(), # 自动寻找端口
|
||||||
reload=True,
|
|
||||||
)
|
)
|
||||||
|
|||||||
266
ui/views/convert_pdf_page.py
Normal file
266
ui/views/convert_pdf_page.py
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
import comtypes.client
|
||||||
|
import pythoncom
|
||||||
|
from loguru import logger
|
||||||
|
from nicegui import ui
|
||||||
|
|
||||||
|
from utils.file_utils import open_folder
|
||||||
|
|
||||||
|
progress_bar = None
|
||||||
|
progress_label = None
|
||||||
|
powerpoint = None
|
||||||
|
|
||||||
|
|
||||||
|
def onload_page(folder: str = ""):
|
||||||
|
global powerpoint
|
||||||
|
pdf_path = os.path.join(folder, "PDF")
|
||||||
|
if not os.path.exists(pdf_path):
|
||||||
|
os.makedirs(pdf_path)
|
||||||
|
if not powerpoint:
|
||||||
|
try:
|
||||||
|
pythoncom.CoInitialize()
|
||||||
|
powerpoint = comtypes.client.CreateObject("PowerPoint.Application")
|
||||||
|
logger.success("PowerPoint 应用启动成功")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"PowerPoint 应用启动失败: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
def update_progress(current: int, total: int, message: str):
|
||||||
|
global progress_bar, progress_label
|
||||||
|
if total <= 0:
|
||||||
|
pct = 0
|
||||||
|
text = f"{message}: 准备中..."
|
||||||
|
else:
|
||||||
|
pct = current / total
|
||||||
|
text = f"{message}: {current}/{total} ({int(pct * 100)}%)"
|
||||||
|
|
||||||
|
# 更新 UI
|
||||||
|
if progress_bar:
|
||||||
|
progress_bar.set_value(pct)
|
||||||
|
if progress_label:
|
||||||
|
progress_label.set_text(text)
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup_powerpoint():
|
||||||
|
"""清理 PowerPoint COM 组件资源"""
|
||||||
|
global powerpoint
|
||||||
|
if powerpoint:
|
||||||
|
try:
|
||||||
|
powerpoint.Quit()
|
||||||
|
logger.success("PowerPoint 应用已关闭")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"关闭 PowerPoint 应用失败: {str(e)}")
|
||||||
|
finally:
|
||||||
|
powerpoint = None
|
||||||
|
|
||||||
|
|
||||||
|
def create_convert_pdf_page(folder: str = ""):
|
||||||
|
onload_page(folder)
|
||||||
|
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"):
|
||||||
|
with ui.row().classes("w-full justify-between"):
|
||||||
|
ui.label("📑 格式转换").classes("section-title")
|
||||||
|
with ui.row().classes("flex-1 justify-end"):
|
||||||
|
ui.button(
|
||||||
|
"📑 格式转换",
|
||||||
|
on_click=lambda: convert_all_pdf_files(folder),
|
||||||
|
).props().classes()
|
||||||
|
ui.button(
|
||||||
|
"📂 打开文件夹",
|
||||||
|
on_click=lambda: open_folder(folder),
|
||||||
|
).props("outline").classes()
|
||||||
|
ui.button(
|
||||||
|
"🔄 刷新数据",
|
||||||
|
on_click=lambda: convert_files_list(list_card, folder),
|
||||||
|
).props("outline").classes()
|
||||||
|
# 进度条
|
||||||
|
with ui.row().classes("w-full"):
|
||||||
|
global progress_label, progress_bar
|
||||||
|
progress_bar = ui.linear_progress(value=0, show_value=False).classes(
|
||||||
|
"h-4 rounded"
|
||||||
|
)
|
||||||
|
progress_bar.props("color=positive")
|
||||||
|
progress_label = ui.label("⛳ 任务进度: 待命").classes(
|
||||||
|
"font-bold text-gray-700 mb-1"
|
||||||
|
)
|
||||||
|
|
||||||
|
list_card = ui.card().classes("w-full p-4 gap-4")
|
||||||
|
convert_files_list(list_card, folder)
|
||||||
|
|
||||||
|
|
||||||
|
# 遍历目录
|
||||||
|
def convert_files_list(list_card, folder):
|
||||||
|
# 清空旧内容
|
||||||
|
list_card.clear()
|
||||||
|
files = get_convert_files(folder)
|
||||||
|
with list_card:
|
||||||
|
ui.label(f"📄 找到 {len(files)} 个 PPT 文件").classes(
|
||||||
|
"text-sm text-gray-600 mb-4"
|
||||||
|
)
|
||||||
|
# 创建可滚动的文件列表
|
||||||
|
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"
|
||||||
|
):
|
||||||
|
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: (convert_pdf_file(folder, f),),
|
||||||
|
).props("outline").classes("text-xs")
|
||||||
|
|
||||||
|
|
||||||
|
def get_convert_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 convert_file(folder, file_name: str):
|
||||||
|
"""
|
||||||
|
转换单个PPT文件为PDF格式
|
||||||
|
:param folder: PPT 文件所在目录
|
||||||
|
:param file_name: PPT 文件名称
|
||||||
|
"""
|
||||||
|
global progress_bar, progress_label, powerpoint
|
||||||
|
|
||||||
|
if not powerpoint:
|
||||||
|
logger.error("PowerPoint 应用未初始化,请重新加载页面")
|
||||||
|
ui.notify("PowerPoint 应用未初始化", type="negative")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
ppt_path = os.path.join(folder, file_name)
|
||||||
|
pdf_name = os.path.splitext(file_name)[0] + ".pdf"
|
||||||
|
pdf_path = os.path.join(folder, "PDF", pdf_name)
|
||||||
|
|
||||||
|
# 如果 PDF 已存在,可以选择跳过
|
||||||
|
if os.path.exists(pdf_path):
|
||||||
|
logger.info(f"[跳过] 已存在: {pdf_name}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
# 打开 -> 另存为 -> 关闭
|
||||||
|
deck = powerpoint.Presentations.Open(ppt_path)
|
||||||
|
deck.SaveAs(pdf_path, 32)
|
||||||
|
deck.Close()
|
||||||
|
logger.success(f"文件转换完成: {file_name}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = f"转换失败: {str(e)}"
|
||||||
|
logger.error(error_msg)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def convert_pdf_file(folder, file_name: str):
|
||||||
|
"""
|
||||||
|
转换单个PPT文件为PDF格式(带UI更新)
|
||||||
|
:param folder: PPT 文件所在目录
|
||||||
|
:param file_name: PPT 文件名称
|
||||||
|
"""
|
||||||
|
update_progress(0, 1, f"⛳ 任务进度: 开始转换 {file_name}")
|
||||||
|
result = convert_file(folder, file_name)
|
||||||
|
|
||||||
|
if result is True:
|
||||||
|
update_progress(1, 1, f"✅ 转换完成: {file_name}")
|
||||||
|
ui.notify(f"转换完成: {file_name}", type="positive")
|
||||||
|
elif result is None:
|
||||||
|
update_progress(1, 1, f"⏭️ 已存在: {file_name}")
|
||||||
|
ui.notify(f"已存在: {file_name}", type="info")
|
||||||
|
else:
|
||||||
|
update_progress(1, 1, f"❌ 转换失败: {file_name}")
|
||||||
|
ui.notify(f"转换失败: {file_name}", type="negative")
|
||||||
|
|
||||||
|
|
||||||
|
def convert_all_pdf_files(folder: str):
|
||||||
|
"""批量转换目录下所有PPT文件为PDF格式"""
|
||||||
|
global progress_bar, progress_label
|
||||||
|
|
||||||
|
pdf_files = get_convert_files(folder)
|
||||||
|
pdf_total = len(pdf_files)
|
||||||
|
|
||||||
|
if pdf_total == 0:
|
||||||
|
ui.notify("没有找到需要转换的PPT文件", type="warning")
|
||||||
|
return
|
||||||
|
|
||||||
|
success_count = 0
|
||||||
|
skip_count = 0
|
||||||
|
fail_count = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
for index, file in enumerate(pdf_files):
|
||||||
|
update_progress(index, pdf_total, f"正在转换: {file}")
|
||||||
|
result = convert_file(folder, file)
|
||||||
|
|
||||||
|
if result is True:
|
||||||
|
success_count += 1
|
||||||
|
elif result is None:
|
||||||
|
skip_count += 1
|
||||||
|
else:
|
||||||
|
fail_count += 1
|
||||||
|
|
||||||
|
update_progress(pdf_total, pdf_total, f"✅ 批量转换完成")
|
||||||
|
|
||||||
|
summary_msg = f"转换完成: 成功 {success_count} 个, 跳过 {skip_count} 个, 失败 {fail_count} 个"
|
||||||
|
logger.success(summary_msg)
|
||||||
|
ui.notify(summary_msg, type="positive")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = f"批量转换失败: {str(e)}"
|
||||||
|
update_progress(pdf_total, pdf_total, f"❌ 批量转换失败")
|
||||||
|
logger.error(error_msg)
|
||||||
|
ui.notify(error_msg, type="negative")
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
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, select_folder
|
from ui.core.task_runner import run_task, select_folder
|
||||||
|
from utils.file_utils import open_folder
|
||||||
# 导入业务函数
|
# 导入业务函数
|
||||||
from utils.generate_utils import (
|
from utils.generate_utils import (
|
||||||
generate_template,
|
generate_template,
|
||||||
generate_comment_all,
|
generate_comment_all,
|
||||||
generate_convert_pdf,
|
|
||||||
generate_report,
|
generate_report,
|
||||||
generate_zodiac,
|
generate_zodiac,
|
||||||
)
|
)
|
||||||
from utils.file_utils import open_folder
|
|
||||||
|
|
||||||
config = load_config("config.toml")
|
config = load_config("config.toml")
|
||||||
|
|
||||||
@@ -68,9 +67,20 @@ def create_home_page():
|
|||||||
func_btn("📁 生成图片路径", generate_template)
|
func_btn("📁 生成图片路径", generate_template)
|
||||||
func_btn("🤖 生成评语 (AI)", generate_comment_all)
|
func_btn("🤖 生成评语 (AI)", generate_comment_all)
|
||||||
func_btn("📊 生成报告 (PPT)", generate_report)
|
func_btn("📊 生成报告 (PPT)", generate_report)
|
||||||
func_btn("📑 格式转换 (PDF)", generate_convert_pdf)
|
|
||||||
func_btn("🐂 生肖转化 (生日)", generate_zodiac)
|
func_btn("🐂 生肖转化 (生日)", generate_zodiac)
|
||||||
|
|
||||||
|
# 格式转换按钮
|
||||||
|
async def on_convert_pdf_click():
|
||||||
|
selected_folder = await select_folder()
|
||||||
|
if selected_folder:
|
||||||
|
ui.navigate.to(f"/convert_pdf?folder={selected_folder}")
|
||||||
|
else:
|
||||||
|
ui.notify("未选择目录", type="warning")
|
||||||
|
|
||||||
|
ui.button("📑 格式转换 (PDF)", on_click=on_convert_pdf_click).props(
|
||||||
|
f"outline"
|
||||||
|
).classes("w-full")
|
||||||
|
|
||||||
# 签名按钮
|
# 签名按钮
|
||||||
async def on_signature_click():
|
async def on_signature_click():
|
||||||
selected_folder = await select_folder()
|
selected_folder = await select_folder()
|
||||||
|
|||||||
Reference in New Issue
Block a user