This commit is contained in:
睿 安
2026-01-21 16:48:36 +08:00
commit abba5cb273
246 changed files with 57473 additions and 0 deletions

0
app/ui/menu/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

61
app/ui/menu/dialog.py Normal file
View File

@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'dialog.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(553, 394)
self.verticalLayout_2 = QtWidgets.QVBoxLayout(Dialog)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.label_version = QtWidgets.QLabel(Dialog)
self.label_version.setLayoutDirection(QtCore.Qt.LeftToRight)
self.label_version.setAlignment(QtCore.Qt.AlignCenter)
self.label_version.setObjectName("label_version")
self.verticalLayout.addWidget(self.label_version)
self.label_logo = QtWidgets.QLabel(Dialog)
self.label_logo.setMinimumSize(QtCore.QSize(100, 100))
self.label_logo.setObjectName("label_logo")
self.verticalLayout.addWidget(self.label_logo)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.horizontalLayout.addLayout(self.verticalLayout)
self.textBrowser = QtWidgets.QTextBrowser(Dialog)
self.textBrowser.setFrameShape(QtWidgets.QFrame.NoFrame)
self.textBrowser.setObjectName("textBrowser")
self.horizontalLayout.addWidget(self.textBrowser)
self.verticalLayout_2.addLayout(self.horizontalLayout)
self.label_weixin = QtWidgets.QLabel(Dialog)
self.label_weixin.setAlignment(QtCore.Qt.AlignCenter)
self.label_weixin.setObjectName("label_weixin")
self.verticalLayout_2.addWidget(self.label_weixin)
self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.verticalLayout_2.addWidget(self.buttonBox)
self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.label_version.setText(_translate("Dialog", "TextLabel"))
self.label_logo.setText(_translate("Dialog", "logo"))
self.label_weixin.setText(_translate("Dialog", "TextLabel"))

288
app/ui/menu/export.py Normal file
View File

@@ -0,0 +1,288 @@
import os
import sys as sys_
import time
from typing import List
from PyQt5 import QtWidgets
from PyQt5.QtCore import QTimer, QThread, pyqtSignal, QObject
from PyQt5.QtGui import QTextCursor
from PyQt5.QtWidgets import QApplication, QDialog, QCheckBox, QMessageBox
from app.DataBase import micro_msg_db, misc_db
from app.util.exporter.output import Output
from app.components import ScrollBar
from app.components.export_contact_item import ContactQListWidgetItem
from app.config import OUTPUT_DIR
from app.person import Contact
from app.ui.menu.exportUi import Ui_Dialog
from app.ui.menu.export_time_range import TimeRangeDialog
types = {
'文本': 1,
'图片': 3,
'语音': 34,
'视频': 43,
'表情包': 47,
'音乐与音频': 4903,
'文件': 4906,
'分享卡片': 4905,
'转账': 492000,
'音视频通话': 50,
'拍一拍等系统消息': 10000,
}
file_format = {
'Docx': Output.DOCX,
'TXT': Output.TXT,
'HTML': Output.HTML,
'CSV': Output.CSV,
'JSON': Output.JSON,
}
Stylesheet = """
"""
class EmittingStr(QObject):
textWritten = pyqtSignal(str) # 定义一个发送str的信号
def write(self, text):
self.textWritten.emit(str(text))
class ExportDialog(QDialog, Ui_Dialog):
def __init__(self, contact=None, title="选择导出的类型", file_type="html", parent=None):
super(ExportDialog, self).__init__(parent)
self.setupUi(self)
self.contacts: List[Contact] = []
self.setStyleSheet(Stylesheet)
self.contact = contact
self.btn_select_all.clicked.connect(self.select_all)
self.select_all_flag = False
self.btn_start.clicked.connect(self.export_data)
self.comboBox_time.activated.connect(self.set_export_date)
# 下面将输出重定向到textBrowser中
sys_.stdout = EmittingStr(textWritten=self.outputWritten)
# sys.stderr = EmittingStr(textWritten=self.outputWritten)
scroll_bar = ScrollBar()
self.textBrowser.setVerticalScrollBar(scroll_bar)
self.export_choices = {"文本": True, "图片": True, "语音": False, "视频": False, "表情包": False,
'音乐与音频': False, '分享卡片': False, '文件': False,
'转账': False, '音视频通话': False,'拍一拍等系统消息': True} # 定义导出的数据类型
self.setWindowTitle(title)
self.checkBox_word.setEnabled(False)
self.checkBox_word.setText('Docx(暂时不可用)')
self.resize(800, 600)
self.worker = None # 导出线程
for export_type, default_state in self.export_choices.items():
checkbox = QCheckBox(export_type)
checkbox.setObjectName('message_type')
checkbox.setChecked(default_state)
self.verticalLayout_2.addWidget(checkbox)
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout_2.addItem(spacerItem1)
self.timer = QTimer(self)
self.time = 0
self.total_msg_num = 99999 # 总的消息个数
self.num = 0 # 当前完成的消息个数
self.timer.timeout.connect(self.update_elapsed_time)
self.show_thread = ShowContactThread()
self.show_thread.showSingal.connect(self.show_contact)
# self.show_thread.load_finish_signal.connect(self.stop_loading)
self.show_thread.start()
self.listWidget.setVerticalScrollBar(ScrollBar())
# self.listWidget.currentRowChanged.connect(self.setCurrentIndex)
self.listWidget.itemClicked.connect(self.setCurrentIndex)
self.visited = set()
self.now_index = 0
self.time_range = None
def set_export_date(self):
date_range = self.comboBox_time.currentText()
if date_range == '全部时间':
pass
elif date_range == '最近三个月':
from datetime import datetime, timedelta
# 获取今天的日期和时间
today = datetime.now()
# 获取今天的日期
today_date = today.date()
# 获取今天的24:00:00的时间戳
today_midnight = datetime.combine(today_date, datetime.min.time()) + timedelta(days=1)
today_midnight_timestamp = int(today_midnight.timestamp())
# 获取三个月前的日期
three_months_ago = today - timedelta(days=90)
# 获取三个月前的00:00:00的时间戳
three_months_ago_date = three_months_ago.date()
three_months_ago_midnight = datetime.combine(three_months_ago_date, datetime.min.time())
three_months_ago_midnight_timestamp = int(three_months_ago_midnight.timestamp())
self.time_range = (three_months_ago_midnight_timestamp, today_midnight_timestamp)
elif date_range == '自定义时间':
self.time_range_view = TimeRangeDialog(parent=self)
self.time_range_view.date_range_signal.connect(self.set_time_range)
self.time_range_view.show()
self.comboBox_time.setCurrentIndex(0)
# QMessageBox.warning(self,
# "别急别急",
# "马上就实现该功能"
# )
def set_time_range(self, time_range):
self.time_range = time_range
self.comboBox_time.setCurrentIndex(2)
def outputWritten(self, text):
cursor = self.textBrowser.textCursor()
cursor.movePosition(QTextCursor.End)
cursor.insertText(text)
self.textBrowser.setTextCursor(cursor)
self.textBrowser.ensureCursorVisible()
def export_data(self):
self.btn_start.setEnabled(False)
# 在这里获取用户选择的导出数据类型
selected_types = {types[export_type]: checkbox.isChecked() for export_type, checkbox in
zip(self.export_choices.keys(), self.findChildren(QCheckBox, 'message_type'))}
# 在这里根据用户选择的数据类型执行导出操作
print("选择的数据类型:", selected_types)
file_types = []
for checkbox in [self.checkBox_txt, self.checkBox_csv, self.checkBox_html, self.checkBox_word,self.checkBox_json]:
if checkbox.isChecked():
file_types.append(file_format[checkbox.text()])
select_contacts = []
count = self.listWidget.count()
# 遍历listwidget中的内容
for i in range(count):
item = self.listWidget.item(i)
if item.is_select:
select_contacts.append(self.contacts[i])
# 在这里根据用户选择的数据类型执行导出操作
print("选择的文件格式:", file_types)
self.worker = Output(select_contacts, type_=Output.Batch, message_types=selected_types, sub_type=file_types,
time_range=self.time_range)
# self.worker.progressSignal.connect(self.update_progress)
self.worker.okSignal.connect(self.export_finished)
self.worker.rangeSignal.connect(self.set_total_msg_num)
self.worker.nowContact.connect(self.update_progress)
self.worker.start()
# 启动定时器每1000毫秒更新一次任务进度
self.timer.start(1000)
self.start_time = time.time()
# self.accept() # 使用accept关闭对话框
# 绑定点击槽函数 点击显示对应item中的name
def set_total_msg_num(self, num):
self.total_msg_num = num
# b''+num +(1,1)
def setCurrentIndex(self, item):
# print(row)
# row = self.listWidget.it
# item = self.listWidget.item(row)
item.select()
item.dis_select()
# self.now_index = row
def select_all(self):
self.select_all_flag = not self.select_all_flag
print('全选', self.select_all_flag)
if self.select_all_flag:
count = self.listWidget.count()
# 遍历listwidget中的内容
for i in range(count):
item = self.listWidget.item(i)
item.force_select()
self.btn_select_all.setText('全不选')
else:
count = self.listWidget.count()
# 遍历listwidget中的内容
for i in range(count):
item = self.listWidget.item(i)
item.force_dis_select()
self.btn_select_all.setText('全选')
def export_finished(self):
self.btn_start.setEnabled(True)
self.time = 0
end_time = time.time()
print(f'总耗时:{end_time - self.start_time}s')
reply = QMessageBox(self)
reply.setIcon(QMessageBox.Information)
reply.setWindowTitle('OK')
reply.setText(f"导出聊天记录成功\n{OUTPUT_DIR}目录下(跟exe文件在一起)\n{os.path.normpath(os.path.join(os.getcwd(), OUTPUT_DIR))}")
reply.addButton("确认", QMessageBox.AcceptRole)
reply.addButton("取消", QMessageBox.RejectRole)
api = reply.exec_()
# 在任务完成时重置sys.stdout
sys_.stdout = sys_.__stdout__
self.accept()
def close(self):
sys_.stdout = sys_.__stdout__
del self.worker
super().close()
def show_contact(self, contact):
# return
# print(contact.remark)
contact_item = ContactQListWidgetItem(contact.remark, contact.smallHeadImgUrl, contact.smallHeadImgBLOG)
self.listWidget.addItem(contact_item)
self.listWidget.setItemWidget(contact_item, contact_item.widget)
self.contacts.append(contact)
def update_elapsed_time(self):
self.time += 1
self.label_time.setText(f"耗时: {self.time}s")
def update_progress(self, remark):
self.num += 1
progress_percentage = int((self.num) / self.total_msg_num * 100)
self.progressBar.setValue(progress_percentage)
self.label_process.setText(f"导出进度: {progress_percentage}% {remark}")
class ShowContactThread(QThread):
showSingal = pyqtSignal(Contact)
load_finish_signal = pyqtSignal(bool)
# heightSingal = pyqtSignal(int)
def __init__(self):
super().__init__()
def run(self) -> None:
contact_info_lists = micro_msg_db.get_contact()
for contact_info_list in contact_info_lists:
# UserName, Alias,Type,Remark,NickName,PYInitial,RemarkPYInitial,ContactHeadImgUrl.smallHeadImgUrl,ContactHeadImgUrl,bigHeadImgUrl
contact_info = {
'UserName': contact_info_list[0],
'Alias': contact_info_list[1],
'Type': contact_info_list[2],
'Remark': contact_info_list[3],
'NickName': contact_info_list[4],
'smallHeadImgUrl': contact_info_list[7]
}
contact = Contact(contact_info)
contact.smallHeadImgBLOG = misc_db.get_avatar_buffer(contact.wxid)
contact.set_avatar(contact.smallHeadImgBLOG)
self.showSingal.emit(contact)
# print(contact.wxid)
# pprint(contact.__dict__)
self.load_finish_signal.emit(True)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
dialog = ExportDialog()
result = dialog.exec_() # 使用exec_()获取用户的操作结果
if result == QDialog.Accepted:
print("用户点击了导出按钮")
else:
print("用户点击了取消按钮")
sys.exit(app.exec_())

166
app/ui/menu/exportUi.py Normal file
View File

@@ -0,0 +1,166 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'exportUi.ui'
#
# Created by: PyQt5 UI code generator 5.15.10
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(791, 599)
self.verticalLayout_3 = QtWidgets.QVBoxLayout(Dialog)
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.label_3 = QtWidgets.QLabel(Dialog)
self.label_3.setObjectName("label_3")
self.horizontalLayout.addWidget(self.label_3)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.btn_select_all = QtWidgets.QPushButton(Dialog)
self.btn_select_all.setObjectName("btn_select_all")
self.horizontalLayout.addWidget(self.btn_select_all)
self.comboBox_time = QtWidgets.QComboBox(Dialog)
self.comboBox_time.setObjectName("comboBox_time")
self.comboBox_time.addItem("")
self.comboBox_time.addItem("")
self.comboBox_time.addItem("")
self.horizontalLayout.addWidget(self.comboBox_time)
self.comboBox_type = QtWidgets.QComboBox(Dialog)
self.comboBox_type.setObjectName("comboBox_type")
self.comboBox_type.addItem("")
self.comboBox_type.addItem("")
self.horizontalLayout.addWidget(self.comboBox_type)
self.verticalLayout_3.addLayout(self.horizontalLayout)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
self.verticalLayout.setObjectName("verticalLayout")
self.label = QtWidgets.QLabel(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
self.label.setSizePolicy(sizePolicy)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.checkBox_word = QtWidgets.QCheckBox(Dialog)
self.checkBox_word.setObjectName("checkBox_word")
self.verticalLayout.addWidget(self.checkBox_word)
self.checkBox_html = QtWidgets.QCheckBox(Dialog)
self.checkBox_html.setObjectName("checkBox_html")
self.verticalLayout.addWidget(self.checkBox_html)
self.checkBox_csv = QtWidgets.QCheckBox(Dialog)
self.checkBox_csv.setObjectName("checkBox_csv")
self.verticalLayout.addWidget(self.checkBox_csv)
self.checkBox_txt = QtWidgets.QCheckBox(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.checkBox_txt.sizePolicy().hasHeightForWidth())
self.checkBox_txt.setSizePolicy(sizePolicy)
self.checkBox_txt.setChecked(True)
self.checkBox_txt.setObjectName("checkBox_txt")
self.verticalLayout.addWidget(self.checkBox_txt)
self.checkBox_json = QtWidgets.QCheckBox(Dialog)
self.checkBox_json.setObjectName("checkBox_json")
self.verticalLayout.addWidget(self.checkBox_json)
self.label_2 = QtWidgets.QLabel(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth())
self.label_2.setSizePolicy(sizePolicy)
self.label_2.setObjectName("label_2")
self.verticalLayout.addWidget(self.label_2)
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
self.verticalLayout_2.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.verticalLayout.addLayout(self.verticalLayout_2)
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem1)
self.horizontalLayout_2.addLayout(self.verticalLayout)
self.listWidget = QtWidgets.QListWidget(Dialog)
self.listWidget.setMinimumSize(QtCore.QSize(0, 0))
self.listWidget.setObjectName("listWidget")
self.horizontalLayout_2.addWidget(self.listWidget)
self.horizontalLayout_2.setStretch(0, 1)
self.horizontalLayout_2.setStretch(1, 1)
self.verticalLayout_3.addLayout(self.horizontalLayout_2)
self.textBrowser = QtWidgets.QTextBrowser(Dialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.textBrowser.sizePolicy().hasHeightForWidth())
self.textBrowser.setSizePolicy(sizePolicy)
self.textBrowser.setMaximumSize(QtCore.QSize(16777215, 80))
self.textBrowser.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.textBrowser.setTabStopWidth(0)
self.textBrowser.setOpenExternalLinks(False)
self.textBrowser.setObjectName("textBrowser")
self.verticalLayout_3.addWidget(self.textBrowser)
self.progressBar = QtWidgets.QProgressBar(Dialog)
self.progressBar.setProperty("value", 0)
self.progressBar.setObjectName("progressBar")
self.verticalLayout_3.addWidget(self.progressBar)
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.verticalLayout_3.addLayout(self.horizontalLayout_4)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.label_time = QtWidgets.QLabel(Dialog)
self.label_time.setText("")
self.label_time.setObjectName("label_time")
self.horizontalLayout_3.addWidget(self.label_time)
self.label_process = QtWidgets.QLabel(Dialog)
self.label_process.setText("")
self.label_process.setObjectName("label_process")
self.horizontalLayout_3.addWidget(self.label_process)
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_3.addItem(spacerItem2)
self.btn_start = QtWidgets.QPushButton(Dialog)
self.btn_start.setStyleSheet("QPushButton{\n"
" background-color: rgb(233,233,233);\n"
" border-radius: 5px;\n"
" padding: 10px;\n"
"}\n"
"QPushButton:hover { \n"
" background-color: lightgray;\n"
"border:1px solid rgb(31,156,220) ;\n"
"}")
self.btn_start.setAutoDefault(False)
self.btn_start.setDefault(False)
self.btn_start.setFlat(False)
self.btn_start.setObjectName("btn_start")
self.horizontalLayout_3.addWidget(self.btn_start)
self.verticalLayout_3.addLayout(self.horizontalLayout_3)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.label_3.setText(_translate("Dialog", "导出过程中请不要退出,为减少卡顿请尽量不要超过十个"))
self.btn_select_all.setText(_translate("Dialog", "全选"))
self.comboBox_time.setItemText(0, _translate("Dialog", "全部时间"))
self.comboBox_time.setItemText(1, _translate("Dialog", "最近三个月"))
self.comboBox_time.setItemText(2, _translate("Dialog", "自定义时间"))
self.comboBox_type.setItemText(0, _translate("Dialog", "全部聊天记录"))
self.comboBox_type.setItemText(1, _translate("Dialog", "不含图片/视频/文件"))
self.label.setText(_translate("Dialog", "导出格式"))
self.checkBox_word.setText(_translate("Dialog", "Docx"))
self.checkBox_html.setText(_translate("Dialog", "HTML"))
self.checkBox_csv.setText(_translate("Dialog", "CSV"))
self.checkBox_txt.setText(_translate("Dialog", "TXT"))
self.checkBox_json.setText(_translate("Dialog", "JSON"))
self.label_2.setText(_translate("Dialog", "消息类型"))
self.btn_start.setText(_translate("Dialog", "开始"))

View File

@@ -0,0 +1,109 @@
from datetime import datetime
from PyQt5 import QtWidgets
from PyQt5.QtCore import QTimer, QThread, pyqtSignal, Qt, QPoint
from PyQt5.QtGui import QMouseEvent
from PyQt5.QtWidgets import QApplication, QDialog, QCheckBox, QMessageBox, QCalendarWidget, QWidget, QVBoxLayout, QLabel
from app.components.calendar_dialog import CalendarDialog
try:
from .time_range import Ui_Dialog
except:
from time_range import Ui_Dialog
Stylesheet = '''
QToolButton{
color:#000000;
}
QCalendarWidget QAbstractItemView:disabled {
}
QCalendarWidget QAbstractItemView:enabled{
}
'''
class TimeRangeDialog(QDialog, Ui_Dialog):
date_range_signal = pyqtSignal(tuple)
def __init__(self, date_range=None, parent=None):
"""
@param date_range: tuple[Union[QDate, datetime.date],Union[QDate, datetime.date]] 限定的可选择范围
@param parent:
"""
super().__init__(parent)
self.calendar = None
self.setupUi(self)
self.setWindowTitle('选择日期范围')
# self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
self.setStyleSheet(Stylesheet)
self.toolButton_start_time.clicked.connect(self.select_date_start)
self.toolButton_end_time.clicked.connect(self.select_date_end)
self.calendar = CalendarDialog(date_range=date_range, parent=self)
self.calendar.selected_date_signal.connect(self.set_date)
self.btn_ok.clicked.connect(self.ok)
self.btn_ok.setEnabled(False)
self.btn_ok_num = 0
self.btn_cancel.clicked.connect(lambda x: self.close())
self.start_time_flag = True
self.start_timestamp = 0
self.end_timestamp = 0
def set_date(self, timestamp):
if self.start_time_flag:
self.start_timestamp = timestamp
date_object = datetime.fromtimestamp(timestamp)
str_start = date_object.strftime("%Y-%m-%d")
self.toolButton_start_time.setText(str_start)
self.btn_ok_num += 1
else:
date_object = datetime.fromtimestamp(timestamp)
str_start = date_object.strftime("%Y-%m-%d")
self.end_timestamp = timestamp + 86399
self.toolButton_end_time.setText(str_start)
self.btn_ok_num += 1
if self.btn_ok_num == 2:
self.btn_ok.setEnabled(True)
def ok(self):
date_range = (self.start_timestamp, self.end_timestamp)
self.date_range_signal.emit(date_range)
self.close()
def select_date_start(self):
self.start_time_flag = True
self.calendar.set_start_date()
self.calendar.show()
def select_date_end(self):
self.start_time_flag = False
self.calendar.set_end_date()
self.calendar.show()
def mouseMoveEvent(self, e: QMouseEvent): # 重写移动事件
if self._tracking:
self._endPos = e.pos() - self._startPos
self.move(self.pos() + self._endPos)
def mousePressEvent(self, e: QMouseEvent):
if e.button() == Qt.LeftButton:
self._startPos = QPoint(e.x(), e.y())
self._tracking = True
def mouseReleaseEvent(self, e: QMouseEvent):
if e.button() == Qt.LeftButton:
self._tracking = False
self._startPos = None
self._endPos = None
if __name__ == '__main__':
import sys
from datetime import datetime
app = QApplication(sys.argv)
# 设置日期范围
start_date = datetime(2023, 12, 11)
end_date = datetime(2024, 1, 9)
date_range = (start_date.date(), end_date.date())
ex = TimeRangeDialog(date_range=date_range)
ex.show()
sys.exit(app.exec_())

73
app/ui/menu/time_range.py Normal file
View File

@@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'time_range.ui'
#
# Created by: PyQt5 UI code generator 5.15.10
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(280, 200)
Dialog.setMinimumSize(QtCore.QSize(280, 200))
Dialog.setMaximumSize(QtCore.QSize(280, 200))
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
self.verticalLayout.setObjectName("verticalLayout")
self.label = QtWidgets.QLabel(Dialog)
self.label.setLayoutDirection(QtCore.Qt.LeftToRight)
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.label_2 = QtWidgets.QLabel(Dialog)
self.label_2.setObjectName("label_2")
self.horizontalLayout_2.addWidget(self.label_2)
self.toolButton_start_time = QtWidgets.QToolButton(Dialog)
self.toolButton_start_time.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
self.toolButton_start_time.setArrowType(QtCore.Qt.DownArrow)
self.toolButton_start_time.setObjectName("toolButton_start_time")
self.horizontalLayout_2.addWidget(self.toolButton_start_time)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.label_3 = QtWidgets.QLabel(Dialog)
self.label_3.setObjectName("label_3")
self.horizontalLayout.addWidget(self.label_3)
self.toolButton_end_time = QtWidgets.QToolButton(Dialog)
self.toolButton_end_time.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
self.toolButton_end_time.setArrowType(QtCore.Qt.DownArrow)
self.toolButton_end_time.setObjectName("toolButton_end_time")
self.horizontalLayout.addWidget(self.toolButton_end_time)
self.verticalLayout.addLayout(self.horizontalLayout)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.btn_ok = QtWidgets.QPushButton(Dialog)
self.btn_ok.setObjectName("btn_ok")
self.horizontalLayout_3.addWidget(self.btn_ok)
self.btn_cancel = QtWidgets.QPushButton(Dialog)
self.btn_cancel.setObjectName("btn_cancel")
self.horizontalLayout_3.addWidget(self.btn_cancel)
self.verticalLayout.addLayout(self.horizontalLayout_3)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.label.setText(_translate("Dialog", "自定义时间"))
self.label_2.setText(_translate("Dialog", "开始日期"))
self.toolButton_start_time.setText(_translate("Dialog", "请选择时间"))
self.label_3.setText(_translate("Dialog", "结束日期"))
self.toolButton_end_time.setText(_translate("Dialog", "请选择时间"))
self.btn_ok.setText(_translate("Dialog", "确定"))
self.btn_cancel.setText(_translate("Dialog", "取消"))