合并达成度功能
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
from PySide6.QtGui import QDesktopServices
|
||||
from PySide6.QtWidgets import QVBoxLayout
|
||||
from qfluentwidgets import PrimaryPushSettingCard, FluentIcon, GroupHeaderCardWidget, PushButton
|
||||
from PySide6.QtGui import QDesktopServices, Qt
|
||||
from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout
|
||||
from qfluentwidgets import PrimaryPushSettingCard, FluentIcon, GroupHeaderCardWidget, PushButton, ImageLabel, TitleLabel
|
||||
|
||||
from ui.components.widget import Widget
|
||||
|
||||
@@ -9,11 +9,19 @@ class AboutWidget(Widget):
|
||||
def __init__(self, key: str, parent=None):
|
||||
super().__init__(key, parent)
|
||||
|
||||
self.logoImage = ImageLabel(':/images/logo.png')
|
||||
self.logoImage.scaledToHeight(100)
|
||||
self.appNameLabel = TitleLabel('建工工具箱🛠️')
|
||||
|
||||
self.hBox = QHBoxLayout()
|
||||
self.hBox.addWidget(self.logoImage, 0, Qt.AlignLeft)
|
||||
self.hBox.addWidget(self.appNameLabel, 1, Qt.AlignLeft)
|
||||
|
||||
self.version_card = PrimaryPushSettingCard(
|
||||
text="获取源码",
|
||||
icon=FluentIcon.INFO,
|
||||
title="关于",
|
||||
content="作者:许方杰。当前版本:1.0.0\n使用 GPLv3 开源协议,作者不对使用本软件造成的任何损失负责。"
|
||||
content="作者:许方杰。当前版本:1.0.0\n本软件使用 GPLv3 开源协议进行分发,作者不对使用本软件造成的任何损失负责。"
|
||||
)
|
||||
self.button_list = [
|
||||
PushButton("访问网站"),
|
||||
@@ -31,6 +39,7 @@ class AboutWidget(Widget):
|
||||
self.group_card.setTitle("第三方框架")
|
||||
self.vbox = QVBoxLayout(self)
|
||||
|
||||
self.vbox.addLayout(self.hBox)
|
||||
self.vbox.addWidget(self.version_card)
|
||||
self.vbox.addWidget(self.group_card)
|
||||
self.vbox.addStretch(1)
|
||||
|
||||
243
ui/pyui/achievement_ui.py
Normal file
243
ui/pyui/achievement_ui.py
Normal file
@@ -0,0 +1,243 @@
|
||||
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()
|
||||
@@ -4,7 +4,7 @@ from functools import wraps
|
||||
from PySide6.QtCore import Qt, Signal, QThread
|
||||
from PySide6.QtWidgets import QHBoxLayout, QVBoxLayout, QFileDialog
|
||||
from qfluentwidgets import GroupHeaderCardWidget, PushButton, IconWidget, InfoBarIcon, \
|
||||
BodyLabel, PrimaryPushButton, FluentIcon, LineEdit, InfoBar, InfoBarPosition, ProgressBar
|
||||
BodyLabel, PrimaryPushButton, FluentIcon, LineEdit, InfoBar, InfoBarPosition, ProgressBar, IndeterminateProgressBar
|
||||
|
||||
from module.worker import DTGWorker
|
||||
from ui.components.widget import Widget
|
||||
@@ -16,7 +16,7 @@ class InitSettingCard(GroupHeaderCardWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.setTitle("初始化")
|
||||
self.setTitle("输入选项")
|
||||
self.setBorderRadius(8)
|
||||
|
||||
self.chooseStudentButton = PushButton("打开")
|
||||
@@ -53,7 +53,7 @@ class ExportSettingsCard(GroupHeaderCardWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.setTitle("导出")
|
||||
self.setTitle("输入选项")
|
||||
self.setBorderRadius(8)
|
||||
|
||||
self.chooseExportDirectoryButton = PushButton("选择")
|
||||
@@ -100,14 +100,16 @@ class ExportSettingsCard(GroupHeaderCardWidget):
|
||||
|
||||
def update_export_setting_by_signal(self, path: str) -> None:
|
||||
f_dir = path[:path.rfind('/')]
|
||||
f_name = path[path.rfind('/') + 1:path.rfind('.')]
|
||||
f_name = path[path.rfind('/') + 1:path.rfind('.')] + '-答辩题目'
|
||||
self.dirGroup.setContent(f"当前保存的文件目录:{f_dir}")
|
||||
self.updateSignal.emit('d', f_dir)
|
||||
self.exportFileNameLineEdit.setText(f"{f_name}-答辩题目")
|
||||
self.exportFileNameLineEdit.setText(f_name)
|
||||
self.updateSignal.emit('n', f_name)
|
||||
|
||||
|
||||
class DefenseWidget(Widget):
|
||||
errorSignal = Signal(str, str)
|
||||
|
||||
def __init__(self, key: str, parent=None):
|
||||
super().__init__(key, parent)
|
||||
|
||||
@@ -125,6 +127,8 @@ class DefenseWidget(Widget):
|
||||
self.thread = None
|
||||
self.worker = None
|
||||
|
||||
self.successFlag = True
|
||||
|
||||
# ===================================
|
||||
|
||||
self.input_student_filepath = None
|
||||
@@ -157,17 +161,21 @@ class DefenseWidget(Widget):
|
||||
self.pb.setValue(value)
|
||||
if value == 100:
|
||||
self.infoBar.close()
|
||||
self.infoBar = InfoBar.success(
|
||||
title='成功!',
|
||||
content="正在打开文件...",
|
||||
self.infoBar = InfoBar(
|
||||
icon=InfoBarIcon.INFORMATION,
|
||||
title='正在转换文件',
|
||||
content="",
|
||||
orient=Qt.Horizontal,
|
||||
isClosable=True,
|
||||
isClosable=False,
|
||||
position=InfoBarPosition.BOTTOM,
|
||||
duration=5000,
|
||||
duration=-1,
|
||||
parent=self
|
||||
)
|
||||
self.infoBar.addWidget(IndeterminateProgressBar(start=True))
|
||||
self.infoBar.show()
|
||||
self.pb = None
|
||||
self.exportCard.startButton.setEnabled(True)
|
||||
elif value == -1:
|
||||
self.successFlag = False
|
||||
|
||||
def enable_start_check(func: Callable):
|
||||
@wraps(func)
|
||||
@@ -198,7 +206,6 @@ class DefenseWidget(Widget):
|
||||
self.output_filepath = value
|
||||
elif key == "output_filename":
|
||||
self.output_filename = value
|
||||
setattr(self, key, value)
|
||||
|
||||
def input_signal_receive(self, s_type: Literal['s', 'q'], value: str):
|
||||
if s_type == "s":
|
||||
@@ -224,16 +231,19 @@ class DefenseWidget(Widget):
|
||||
self.worker.moveToThread(self.thread)
|
||||
|
||||
self.show_info_bar()
|
||||
self.successFlag = True
|
||||
self.exportCard.startButton.setEnabled(False)
|
||||
|
||||
# 线程启动与信号连接
|
||||
self.thread.started.connect(self.worker.run)
|
||||
self.worker.progress.connect(self.set_pb_value)
|
||||
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()
|
||||
@@ -241,3 +251,30 @@ class DefenseWidget(Widget):
|
||||
def clear_thread_worker_refs(self):
|
||||
self.thread = None
|
||||
self.worker = None
|
||||
|
||||
def after_generate(self):
|
||||
self.exportCard.startButton.setEnabled(True)
|
||||
self.infoBar.close()
|
||||
if self.successFlag:
|
||||
self.infoBar = InfoBar.success(
|
||||
title='成功!',
|
||||
content="正在打开文件...",
|
||||
orient=Qt.Horizontal,
|
||||
isClosable=True,
|
||||
position=InfoBarPosition.BOTTOM,
|
||||
duration=5000,
|
||||
parent=self
|
||||
)
|
||||
else:
|
||||
self.infoBar = InfoBar.error(
|
||||
title='失败!',
|
||||
content="",
|
||||
orient=Qt.Horizontal,
|
||||
isClosable=True,
|
||||
position=InfoBarPosition.BOTTOM,
|
||||
duration=5000,
|
||||
parent=self
|
||||
)
|
||||
|
||||
def show_error(self, title: str, content: str):
|
||||
self.errorSignal.emit(title, content)
|
||||
|
||||
Reference in New Issue
Block a user