244 lines
9.1 KiB
Python
244 lines
9.1 KiB
Python
import os
|
||
from functools import wraps
|
||
from typing import Callable, Literal
|
||
|
||
from PySide6.QtCore import Qt, Signal, QThread
|
||
from PySide6.QtWidgets import QVBoxLayout, QFileDialog, QHBoxLayout, QProgressBar
|
||
from qfluentwidgets import GroupHeaderCardWidget, FluentIcon, PushButton, LineEdit, IconWidget, InfoBarIcon, BodyLabel, \
|
||
PrimaryPushButton, SwitchButton, MessageBox, InfoBar, InfoBarPosition, IndeterminateProgressBar
|
||
|
||
from module.worker import ARGWorker
|
||
from ui.components.widget import Widget
|
||
|
||
|
||
class InputSettingCard(GroupHeaderCardWidget):
|
||
chooseSignal = Signal(str)
|
||
|
||
def __init__(self, parent=None):
|
||
super().__init__(parent)
|
||
|
||
self.setTitle("输入选项")
|
||
self.setBorderRadius(8)
|
||
|
||
self.chooseFileButton = PushButton("打开")
|
||
|
||
self.chooseFileButton.setFixedWidth(120)
|
||
|
||
self.inputGroup = self.addGroup(FluentIcon.DOCUMENT, "目标文件", "选择达成度计算表", self.chooseFileButton)
|
||
|
||
# ============================
|
||
self.chooseFileButton.clicked.connect(self.choose_file)
|
||
|
||
def choose_file(self):
|
||
file_path, _ = QFileDialog.getOpenFileName(self, "选择文件", "", "Excel 文件 (*.xlsm);")
|
||
if file_path:
|
||
self.inputGroup.setContent("已选择文件:" + file_path)
|
||
self.chooseSignal.emit(file_path)
|
||
|
||
|
||
class OutputSettingCard(GroupHeaderCardWidget):
|
||
updateSignal = Signal(str, str)
|
||
startSignal = Signal()
|
||
|
||
def __init__(self, parent=None):
|
||
super().__init__(parent)
|
||
|
||
self.setTitle("输出选项")
|
||
self.setBorderRadius(8)
|
||
|
||
self.chooseExportDirectoryButton = PushButton("选择")
|
||
self.exportFileNameLineEdit = LineEdit()
|
||
self.startButton = PrimaryPushButton(FluentIcon.PLAY_SOLID, "开始")
|
||
self.autoOpenSwitch = SwitchButton()
|
||
self.disableCompatibilityCheckSwitch = SwitchButton()
|
||
|
||
self.autoOpenSwitch.setChecked(True)
|
||
self.bottomLayout = QHBoxLayout()
|
||
self.hintIcon = IconWidget(InfoBarIcon.INFORMATION)
|
||
self.hintLabel = BodyLabel("点击开始按钮以开始生成 👉")
|
||
self.startButton.setEnabled(False)
|
||
|
||
# 设置底部工具栏布局
|
||
self.hintIcon.setFixedSize(16, 16)
|
||
self.bottomLayout.setSpacing(10)
|
||
self.bottomLayout.setContentsMargins(24, 15, 24, 20)
|
||
self.bottomLayout.addWidget(self.hintIcon, 0, Qt.AlignLeft)
|
||
self.bottomLayout.addWidget(self.hintLabel, 0, Qt.AlignLeft)
|
||
self.bottomLayout.addStretch(1)
|
||
self.bottomLayout.addWidget(self.startButton, 0, Qt.AlignRight)
|
||
self.bottomLayout.setAlignment(Qt.AlignVCenter)
|
||
|
||
self.chooseExportDirectoryButton.setFixedWidth(120)
|
||
self.exportFileNameLineEdit.setPlaceholderText("请输入文件名")
|
||
self.startButton.setFixedWidth(120)
|
||
self.exportFileNameLineEdit.setFixedWidth(360)
|
||
self.exportFileNameLineEdit.setPlaceholderText("输入导出文件名,例如:21工程管理(1)达成度报告")
|
||
|
||
self.dirGroup = self.addGroup(FluentIcon.FOLDER, "导出目录", "选择导出文件的目录",
|
||
self.chooseExportDirectoryButton)
|
||
self.fnGroup = self.addGroup(FluentIcon.DOCUMENT, "导出文件名", "输入导出文件名", self.exportFileNameLineEdit)
|
||
self.aoGroup = self.addGroup(FluentIcon.VIEW, "自动打开", "生成完成后自动打开文件", self.autoOpenSwitch)
|
||
self.ccGroup = self.addGroup(FluentIcon.DEVELOPER_TOOLS, "关闭兼容性检查",
|
||
"⚠ 注意:该功能为实验性内容,仅当你明确了解其影响并知道自己在做什么时,才建议关闭兼容性检查!",
|
||
self.disableCompatibilityCheckSwitch)
|
||
self.ccGroup.setSeparatorVisible(True)
|
||
self.vBoxLayout.addLayout(self.bottomLayout)
|
||
|
||
# =============================
|
||
self.chooseExportDirectoryButton.clicked.connect(self.choose_dir)
|
||
self.startButton.clicked.connect(self.startSignal)
|
||
|
||
def choose_dir(self) -> None:
|
||
dir_path = QFileDialog.getExistingDirectory(self, "选择文件夹", "")
|
||
if dir_path:
|
||
self.dirGroup.setContent(f"当前保存的文件目录:{dir_path}")
|
||
self.updateSignal.emit('d', dir_path)
|
||
|
||
def update_path_and_filename_by_input_path(self, path: str):
|
||
dir_path = path[:path.rfind("/")]
|
||
self.dirGroup.setContent(f"已选择目录:{dir_path}")
|
||
self.updateSignal.emit('d', dir_path)
|
||
|
||
file_name = path[path.rfind("/") + 1:path.rfind(".")] + "-达成度报告"
|
||
self.exportFileNameLineEdit.setText(file_name)
|
||
self.updateSignal.emit('f', file_name)
|
||
|
||
|
||
class AchievementWidget(Widget):
|
||
error = Signal(str, str)
|
||
|
||
def __init__(self, key: str, parent=None):
|
||
super().__init__(key, parent)
|
||
|
||
self.inputGroup = InputSettingCard(self)
|
||
self.outputGroup = OutputSettingCard(self)
|
||
self.vbox = QVBoxLayout(self)
|
||
|
||
self.vbox.addWidget(self.inputGroup)
|
||
self.vbox.addWidget(self.outputGroup)
|
||
self.vbox.addStretch(1)
|
||
|
||
# =================================
|
||
|
||
self.infoBar = None
|
||
|
||
# =================================
|
||
|
||
self.thread = None
|
||
self.worker = None
|
||
|
||
# ==================================
|
||
|
||
self.input_file_path = ""
|
||
self.output_file_path = ""
|
||
self.output_file_name = ""
|
||
|
||
# ==================================
|
||
|
||
self.inputGroup.chooseSignal.connect(self.input_signal_receive)
|
||
self.outputGroup.updateSignal.connect(self.export_signal_receive)
|
||
self.outputGroup.startSignal.connect(self.start_generate)
|
||
|
||
def enable_start_check(func: Callable):
|
||
@wraps(func)
|
||
def wrapper(self, *args, **kwargs):
|
||
result = func(self, *args, **kwargs)
|
||
|
||
fields = [
|
||
self.input_file_path,
|
||
self.output_file_path,
|
||
self.output_file_name,
|
||
]
|
||
if all(fields):
|
||
self.outputGroup.startButton.setEnabled(True)
|
||
else:
|
||
self.outputGroup.startButton.setEnabled(False)
|
||
return result
|
||
|
||
return wrapper
|
||
|
||
@enable_start_check
|
||
def set_value(
|
||
self,
|
||
key: Literal['input_file_path', 'output_file_path', 'output_file_name'],
|
||
value: str
|
||
) -> None:
|
||
setattr(self, key, value)
|
||
|
||
def input_signal_receive(self, file_path: str) -> None:
|
||
self.set_value('input_file_path', file_path)
|
||
self.outputGroup.update_path_and_filename_by_input_path(file_path)
|
||
|
||
def export_signal_receive(self, s_type: Literal['d', 'f'], value: str) -> None:
|
||
if s_type == 'd':
|
||
self.set_value('output_file_path', value)
|
||
elif s_type == 'f':
|
||
self.set_value('output_file_name', value)
|
||
|
||
def start_generate(self):
|
||
self.thread = QThread()
|
||
self.worker = ARGWorker(
|
||
self.input_file_path,
|
||
self.output_file_path,
|
||
self.output_file_name,
|
||
disable_cc=self.outputGroup.disableCompatibilityCheckSwitch.isChecked()
|
||
)
|
||
self.worker.moveToThread(self.thread)
|
||
|
||
self.outputGroup.startButton.setEnabled(False)
|
||
|
||
# 线程启动与信号连接
|
||
self.thread.started.connect(self.worker.run)
|
||
|
||
self.show_info_bar('')
|
||
self.worker.error.connect(self.show_error)
|
||
|
||
self.worker.finished.connect(self.thread.quit)
|
||
self.worker.finished.connect(self.worker.deleteLater)
|
||
self.thread.finished.connect(self.thread.deleteLater)
|
||
self.thread.finished.connect(self.clear_thread_worker_refs)
|
||
self.thread.finished.connect(self.after_generate)
|
||
|
||
# 启动线程
|
||
self.thread.start()
|
||
|
||
def clear_thread_worker_refs(self):
|
||
self.thread = None
|
||
self.worker = None
|
||
|
||
def after_generate(self):
|
||
self.outputGroup.startButton.setEnabled(True)
|
||
if self.outputGroup.autoOpenSwitch.isChecked():
|
||
try:
|
||
os.startfile(self.output_file_path + "/" + self.output_file_name + ".docx")
|
||
except Exception as e:
|
||
self.show_error("?? 不好出错了", str(e))
|
||
if self.infoBar:
|
||
self.infoBar.close()
|
||
self.infoBar = InfoBar.success(
|
||
title='成功!',
|
||
content="正在打开文件" if self.outputGroup.autoOpenSwitch.isChecked() else "文件已保存",
|
||
orient=Qt.Horizontal,
|
||
isClosable=True,
|
||
position=InfoBarPosition.BOTTOM,
|
||
duration=5000,
|
||
parent=self
|
||
)
|
||
|
||
def show_error(self, title: str, content: str):
|
||
self.error.emit(title, content)
|
||
|
||
def show_info_bar(self, info: str):
|
||
self.infoBar = InfoBar(
|
||
icon=InfoBarIcon.INFORMATION,
|
||
title='请稍后',
|
||
content=info,
|
||
orient=Qt.Horizontal,
|
||
isClosable=False,
|
||
position=InfoBarPosition.BOTTOM,
|
||
duration=-1,
|
||
parent=self
|
||
)
|
||
self.infoBar.addWidget(IndeterminateProgressBar(start=True))
|
||
self.infoBar.show()
|