支持批量导出聊天记录

This commit is contained in:
shuaikangzhou 2024-01-06 13:04:55 +08:00
parent cd08bf3862
commit 15fc176749
9 changed files with 594 additions and 54 deletions

View File

@ -1,6 +1,7 @@
import csv import csv
import os import os
import traceback import traceback
from typing import List
from PyQt5.QtCore import pyqtSignal, QThread from PyQt5.QtCore import pyqtSignal, QThread
from PyQt5.QtWidgets import QFileDialog from PyQt5.QtWidgets import QFileDialog
@ -27,6 +28,8 @@ class Output(QThread):
progressSignal = pyqtSignal(int) progressSignal = pyqtSignal(int)
rangeSignal = pyqtSignal(int) rangeSignal = pyqtSignal(int)
okSignal = pyqtSignal(int) okSignal = pyqtSignal(int)
batchOkSignal = pyqtSignal(int)
nowContact = pyqtSignal(str)
i = 1 i = 1
CSV = 0 CSV = 0
DOCX = 1 DOCX = 1
@ -34,17 +37,18 @@ class Output(QThread):
CSV_ALL = 3 CSV_ALL = 3
CONTACT_CSV = 4 CONTACT_CSV = 4
TXT = 5 TXT = 5
Batch = 10086
def __init__(self, contact, type_=DOCX, message_types={}, parent=None): def __init__(self, contact, type_=DOCX, message_types={}, sub_type=[], parent=None):
super().__init__(parent) super().__init__(parent)
self.Child0 = None self.children = []
self.last_timestamp = 0 self.last_timestamp = 0
self.sub_type = sub_type
self.message_types = message_types self.message_types = message_types
self.sec = 2 # 默认1000秒 self.sec = 2 # 默认1000秒
self.contact = contact self.contact = contact
self.ta_username = contact.wxid if contact else ''
self.msg_id = 0 self.msg_id = 0
self.output_type = type_ self.output_type: int | List[int] = type_
self.total_num = 1 self.total_num = 1
self.num = 0 self.num = 0
@ -123,60 +127,115 @@ class Output(QThread):
gender = '' gender = ''
else: else:
gender = '' gender = ''
writer.writerow([*contact[:9], contact[10], gender,detail.get('telephone'),detail.get('signature'),*detail.get('region')]) writer.writerow([*contact[:9], contact[10], gender, detail.get('telephone'), detail.get('signature'),
*detail.get('region')])
self.okSignal.emit(1) self.okSignal.emit(1)
def batch_export(self):
print('开始批量导出')
print(self.sub_type, self.message_types)
print(len(self.contact))
print([contact.remark for contact in self.contact])
self.batch_num_total = len(self.contact)*len(self.sub_type)
self.batch_num = 0
self.rangeSignal.emit(self.batch_num_total)
for contact in self.contact:
# print('联系人', contact.remark)
for type_ in self.sub_type:
# print('导出类型', type_)
if type_ == self.DOCX:
self.to_docx(contact, self.message_types,True)
elif type_ == self.TXT:
# print('批量导出txt')
self.to_txt(contact, self.message_types,True)
elif type_ == self.CSV:
self.to_csv(contact, self.message_types,True)
elif type_ == self.HTML:
self.to_html(contact, self.message_types,True)
def batch_finish_one(self, num):
self.nowContact.emit(self.contact[self.batch_num//len(self.sub_type)].remark)
self.batch_num += 1
if self.batch_num == self.batch_num_total:
self.okSignal.emit(1)
def to_docx(self, contact, message_types, is_batch=False):
Child = DocxExporter(contact, type_=self.DOCX, message_types=message_types)
self.children.append(Child)
Child.progressSignal.connect(self.progress)
if not is_batch:
Child.rangeSignal.connect(self.rangeSignal)
Child.okSignal.connect(self.okSignal if not is_batch else self.batch_finish_one)
Child.start()
def to_txt(self, contact, message_types, is_batch=False):
Child = TxtExporter(contact, type_=self.TXT, message_types=message_types)
self.children.append(Child)
Child.progressSignal.connect(self.progress)
if not is_batch:
Child.rangeSignal.connect(self.rangeSignal)
Child.okSignal.connect(self.okSignal if not is_batch else self.batch_finish_one)
Child.start()
def to_html(self, contact, message_types, is_batch=False):
Child = HtmlExporter(contact, type_=self.output_type, message_types=message_types)
self.children.append(Child)
Child.progressSignal.connect(self.progress)
if not is_batch:
Child.rangeSignal.connect(self.rangeSignal)
Child.okSignal.connect(self.count_finish_num)
Child.start()
self.total_num = 1
if message_types.get(34):
# 语音消息单独的线程
self.total_num += 1
output_media = OutputMedia(contact)
self.children.append(output_media)
output_media.okSingal.connect(self.count_finish_num)
output_media.progressSignal.connect(self.progressSignal)
output_media.start()
if message_types.get(47):
# emoji消息单独的线程
self.total_num += 1
output_emoji = OutputEmoji(contact)
self.children.append(output_emoji)
output_emoji.okSingal.connect(self.count_finish_num)
output_emoji.progressSignal.connect(self.progressSignal)
output_emoji.start()
if message_types.get(3):
# 图片消息单独的线程
self.total_num += 1
output_image = OutputImage(contact)
self.children.append(output_image)
output_image.okSingal.connect(self.count_finish_num)
output_image.progressSignal.connect(self.progressSignal)
output_image.start()
def to_csv(self, contact, message_types, is_batch=False):
Child = CSVExporter(contact, type_=self.CSV, message_types=message_types)
self.children.append(Child)
Child.progressSignal.connect(self.progress)
if not is_batch:
Child.rangeSignal.connect(self.rangeSignal)
Child.okSignal.connect(self.okSignal if not is_batch else self.batch_finish_one)
Child.start()
def run(self): def run(self):
if self.output_type == self.DOCX: if self.output_type == self.DOCX:
self.Child = DocxExporter(self.contact, type_=self.output_type, message_types=self.message_types) self.to_docx(self.contact, self.message_types)
self.Child.progressSignal.connect(self.progress)
self.Child.rangeSignal.connect(self.rangeSignal)
self.Child.okSignal.connect(self.okSignal)
self.Child.start()
elif self.output_type == self.CSV_ALL: elif self.output_type == self.CSV_ALL:
self.to_csv_all() self.to_csv_all()
elif self.output_type == self.CONTACT_CSV: elif self.output_type == self.CONTACT_CSV:
self.contact_to_csv() self.contact_to_csv()
elif self.output_type == self.TXT: elif self.output_type == self.TXT:
self.Child = TxtExporter(self.contact, type_=self.output_type, message_types=self.message_types) self.to_txt(self.contact, self.message_types)
self.Child.progressSignal.connect(self.progress)
self.Child.rangeSignal.connect(self.rangeSignal)
self.Child.okSignal.connect(self.okSignal)
self.Child.start()
elif self.output_type == self.CSV: elif self.output_type == self.CSV:
self.Child = CSVExporter(self.contact, type_=self.output_type, message_types=self.message_types) self.to_csv(self.contact, self.message_types)
self.Child.progressSignal.connect(self.progress)
self.Child.rangeSignal.connect(self.rangeSignal)
self.Child.okSignal.connect(self.okSignal)
self.Child.start()
elif self.output_type == self.HTML: elif self.output_type == self.HTML:
self.Child = HtmlExporter(self.contact, type_=self.output_type, message_types=self.message_types) self.to_html(self.contact, self.message_types)
self.Child.progressSignal.connect(self.progress) elif self.output_type == self.Batch:
self.Child.rangeSignal.connect(self.rangeSignal) self.batch_export()
self.Child.okSignal.connect(self.count_finish_num)
self.Child.start()
if self.message_types.get(34):
# 语音消息单独的线程
self.total_num += 1
self.output_media = OutputMedia(self.contact)
self.output_media.okSingal.connect(self.count_finish_num)
self.output_media.progressSignal.connect(self.progressSignal)
self.output_media.start()
if self.message_types.get(47):
# emoji消息单独的线程
self.total_num += 1
self.output_emoji = OutputEmoji(self.contact)
self.output_emoji.okSingal.connect(self.count_finish_num)
self.output_emoji.progressSignal.connect(self.progressSignal)
self.output_emoji.start()
if self.message_types.get(3):
# 图片消息单独的线程
self.total_num += 1
self.output_image = OutputImage(self.contact)
self.output_image.okSingal.connect(self.count_finish_num)
self.output_image.progressSignal.connect(self.progressSignal)
self.output_image.start()
def count_finish_num(self, num): def count_finish_num(self, num):
""" """
@ -187,7 +246,11 @@ class Output(QThread):
self.num += 1 self.num += 1
if self.num == self.total_num: if self.num == self.total_num:
# 所有子线程都完成之后就发送完成信号 # 所有子线程都完成之后就发送完成信号
self.okSignal.emit(1) if self.output_type == self.Batch:
self.batch_finish_one(1)
else:
self.okSignal.emit(1)
self.num = 0
def cancel(self): def cancel(self):
self.requestInterruption() self.requestInterruption()

View File

@ -3,7 +3,6 @@ from datetime import datetime
from PyQt5 import QtWidgets, QtGui, QtCore from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtCore import * from PyQt5.QtCore import *
import app.DataBase.data as data
from app import person from app import person

View File

@ -0,0 +1,120 @@
import sys
from PyQt5.Qt import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
try:
from .CAvatar import CAvatar
except:
from CAvatar import CAvatar
Stylesheet = """
QWidget{
background: rgb(238,244,249);
}
"""
Stylesheet_hover = """
QWidget,QLabel{
background: rgb(230, 235, 240);
}
"""
Stylesheet_clicked = """
QWidget,QLabel{
background: rgb(230, 235, 240);
}
"""
class QListWidgetItemWidget(QWidget):
def __init__(self):
super().__init__()
self.is_selected = False
def leaveEvent(self, e): # 鼠标离开label
if self.is_selected:
return
self.setStyleSheet(Stylesheet)
def enterEvent(self, e): # 鼠标移入label
self.setStyleSheet(Stylesheet_hover)
# 自定义的item 继承自QListWidgetItem
class ContactQListWidgetItem(QListWidgetItem):
def __init__(self, name, url, img_bytes=None):
super().__init__()
self.is_select = False
# 自定义item中的widget 用来显示自定义的内容
self.widget = QListWidgetItemWidget()
# 用来显示name
self.nameLabel = QLabel(self.widget)
self.nameLabel.setText(name)
# 用来显示avator(图像)
self.avatorLabel = CAvatar(parent=self.widget, shape=CAvatar.Rectangle, size=QSize(30, 30),
url=url, img_bytes=img_bytes)
# 设置布局用来对nameLabel和avatorLabel进行布局
hbox = QHBoxLayout()
self.checkBox = QCheckBox()
hbox.addWidget(self.checkBox)
hbox.addWidget(self.avatorLabel)
hbox.addWidget(self.nameLabel)
hbox.addStretch(1)
# 设置widget的布局
self.widget.setLayout(hbox)
self.widget.setStyleSheet(Stylesheet)
# 设置自定义的QListWidgetItem的sizeHint不然无法显示
self.setSizeHint(self.widget.sizeHint())
def select(self):
"""
设置选择后的事件
@return:
"""
self.widget.is_selected = True
self.is_select = not self.is_select
# print('选择',self.is_select)
self.checkBox.setChecked(self.is_select)
# self.widget.setStyleSheet(Stylesheet_clicked)
def force_select(self):
self.is_select = True
self.checkBox.setChecked(self.is_select)
def force_dis_select(self):
self.is_select = False
self.checkBox.setChecked(self.is_select)
def dis_select(self):
"""
设置取消选择的事件
@return:
"""
self.widget.is_selected = False
self.widget.setStyleSheet(Stylesheet)
if __name__ == "__main__":
app = QApplication(sys.argv)
# 主窗口
w = QWidget()
w.setWindowTitle("QListWindow")
# 新建QListWidget
listWidget = QListWidget(w)
listWidget.resize(300, 300)
# 新建两个自定义的QListWidgetItem(customQListWidgetItem)
item1 = ContactQListWidgetItem("鲤鱼王", "liyuwang.jpg")
item2 = ContactQListWidgetItem("可达鸭", "kedaya.jpg")
# 在listWidget中加入两个自定义的item
listWidget.addItem(item1)
listWidget.setItemWidget(item1, item1.widget)
listWidget.addItem(item2)
listWidget.setItemWidget(item2, item2.widget)
# 绑定点击槽函数 点击显示对应item中的name
listWidget.itemClicked.connect(lambda item: item.select())
w.show()
sys.exit(app.exec_())

View File

@ -74,7 +74,7 @@ class Contact(Person):
self.nickName = contact_info.get('NickName') self.nickName = contact_info.get('NickName')
if not self.remark: if not self.remark:
self.remark = self.nickName self.remark = self.nickName
self.remark = re.sub(r'[\/:*?"<>|\s]', '_', self.remark) self.remark = re.sub(r'[\/:*?"<>|\s\.]', '_', self.remark)
self.smallHeadImgUrl = contact_info.get('smallHeadImgUrl') self.smallHeadImgUrl = contact_info.get('smallHeadImgUrl')
self.smallHeadImgBLOG = b'' self.smallHeadImgBLOG = b''
self.avatar = QPixmap() self.avatar = QPixmap()

View File

@ -20,6 +20,7 @@ from . import mainwindow
from app.ui.menu.about_dialog import AboutDialog from app.ui.menu.about_dialog import AboutDialog
from .chat import ChatWindow from .chat import ChatWindow
from .contact import ContactWindow from .contact import ContactWindow
from .menu.export import ExportDialog
from .tool.tool_window import ToolWindow from .tool.tool_window import ToolWindow
from ..DataBase.output_pc import Output from ..DataBase.output_pc import Output
from ..components.QCursorGif import QCursorGif from ..components.QCursorGif import QCursorGif
@ -126,6 +127,8 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow,QCursorGif):
self.action_output_CSV.triggered.connect(self.output) self.action_output_CSV.triggered.connect(self.output)
self.action_output_contacts.setIcon(Icon.Output) self.action_output_contacts.setIcon(Icon.Output)
self.action_output_contacts.triggered.connect(self.output) self.action_output_contacts.triggered.connect(self.output)
self.action_batch_export.setIcon(Icon.Output)
self.action_batch_export.triggered.connect(self.output)
self.action_desc.setIcon(Icon.Help_Icon) self.action_desc.setIcon(Icon.Help_Icon)
self.action_help_contact.triggered.connect( self.action_help_contact.triggered.connect(
lambda: QDesktopServices.openUrl(QUrl("https://blog.lc044.love/post/5"))) lambda: QDesktopServices.openUrl(QUrl("https://blog.lc044.love/post/5")))
@ -231,6 +234,9 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow,QCursorGif):
self.outputThread.okSignal.connect( self.outputThread.okSignal.connect(
lambda x: self.message('联系人导出成功')) lambda x: self.message('联系人导出成功'))
self.outputThread.start() self.outputThread.start()
elif self.sender() == self.action_batch_export:
dialog = ExportDialog(None, title='批量导出聊天记录', parent=self)
result = dialog.exec_() # 使用exec_()获取用户的操作结果
def message(self, msg): def message(self, msg):
self.stopBusy() self.stopBusy()

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'mainwindow.ui' # Form implementation generated from reading ui file 'mainwindow.ui'
# #
# Created by: PyQt5 UI code generator 5.15.7 # Created by: PyQt5 UI code generator 5.15.10
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # 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. # run again. Do not edit this file unless you know what you are doing.
@ -94,8 +94,6 @@ class Ui_MainWindow(object):
self.menu_2.setObjectName("menu_2") self.menu_2.setObjectName("menu_2")
self.menu_about = QtWidgets.QMenu(self.menubar) self.menu_about = QtWidgets.QMenu(self.menubar)
self.menu_about.setObjectName("menu_about") self.menu_about.setObjectName("menu_about")
self.menu_3 = QtWidgets.QMenu(self.menubar)
self.menu_3.setObjectName("menu_3")
MainWindow.setMenuBar(self.menubar) MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar = QtWidgets.QStatusBar(MainWindow)
font = QtGui.QFont() font = QtGui.QFont()
@ -125,6 +123,8 @@ class Ui_MainWindow(object):
self.action_output_CSV.setObjectName("action_output_CSV") self.action_output_CSV.setObjectName("action_output_CSV")
self.action_output_contacts = QtWidgets.QAction(MainWindow) self.action_output_contacts = QtWidgets.QAction(MainWindow)
self.action_output_contacts.setObjectName("action_output_contacts") self.action_output_contacts.setObjectName("action_output_contacts")
self.action_batch_export = QtWidgets.QAction(MainWindow)
self.action_batch_export.setObjectName("action_batch_export")
self.menu_F.addSeparator() self.menu_F.addSeparator()
self.menu_F.addSeparator() self.menu_F.addSeparator()
self.menu_F.addAction(self.action_3) self.menu_F.addAction(self.action_3)
@ -132,6 +132,7 @@ class Ui_MainWindow(object):
self.menu_output.addAction(self.action_output_CSV) self.menu_output.addAction(self.action_output_CSV)
self.menu_data.addAction(self.menu_output.menuAction()) self.menu_data.addAction(self.menu_output.menuAction())
self.menu_data.addAction(self.action_output_contacts) self.menu_data.addAction(self.action_output_contacts)
self.menu_data.addAction(self.action_batch_export)
self.menu_2.addAction(self.action_help_decrypt) self.menu_2.addAction(self.action_help_decrypt)
self.menu_2.addAction(self.action_help_chat) self.menu_2.addAction(self.action_help_chat)
self.menu_2.addAction(self.action_help_contact) self.menu_2.addAction(self.action_help_contact)
@ -140,7 +141,6 @@ class Ui_MainWindow(object):
self.menubar.addAction(self.menu_data.menuAction()) self.menubar.addAction(self.menu_data.menuAction())
self.menubar.addAction(self.menu_2.menuAction()) self.menubar.addAction(self.menu_2.menuAction())
self.menubar.addAction(self.menu_about.menuAction()) self.menubar.addAction(self.menu_about.menuAction())
self.menubar.addAction(self.menu_3.menuAction())
self.retranslateUi(MainWindow) self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow)
@ -167,7 +167,6 @@ class Ui_MainWindow(object):
self.menu_output.setTitle(_translate("MainWindow", "导出聊天记录(全部)")) self.menu_output.setTitle(_translate("MainWindow", "导出聊天记录(全部)"))
self.menu_2.setTitle(_translate("MainWindow", "帮助")) self.menu_2.setTitle(_translate("MainWindow", "帮助"))
self.menu_about.setTitle(_translate("MainWindow", "关于")) self.menu_about.setTitle(_translate("MainWindow", "关于"))
self.menu_3.setTitle(_translate("MainWindow", "不显示或者显示异常请重启应用、没反应那就多等一会儿"))
self.action_3.setText(_translate("MainWindow", "保存")) self.action_3.setText(_translate("MainWindow", "保存"))
self.action_4.setText(_translate("MainWindow", "退出")) self.action_4.setText(_translate("MainWindow", "退出"))
self.action_help_decrypt.setText(_translate("MainWindow", "解密教程")) self.action_help_decrypt.setText(_translate("MainWindow", "解密教程"))
@ -176,3 +175,4 @@ class Ui_MainWindow(object):
self.action_help_contact.setText(_translate("MainWindow", "好友相关")) self.action_help_contact.setText(_translate("MainWindow", "好友相关"))
self.action_output_CSV.setText(_translate("MainWindow", "CSV")) self.action_output_CSV.setText(_translate("MainWindow", "CSV"))
self.action_output_contacts.setText(_translate("MainWindow", "导出联系人")) self.action_output_contacts.setText(_translate("MainWindow", "导出联系人"))
self.action_batch_export.setText(_translate("MainWindow", "批量导出"))

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

@ -0,0 +1,233 @@
import time
from typing import List
from PyQt5 import QtWidgets
from PyQt5.QtCore import QTimer, QThread, pyqtSignal
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QDialog, QVBoxLayout, QCheckBox, QHBoxLayout, \
QProgressBar, QLabel, QMessageBox
from app.DataBase import micro_msg_db, misc_db
from app.DataBase.output_pc import Output
from app.components import ScrollBar
from app.components.export_contact_item import ContactQListWidgetItem
from app.person import Contact
from app.ui.menu.exportUi import Ui_Dialog
types = {
'文本': 1,
'图片': 3,
'语音': 34,
'视频': 43,
'表情包': 47,
'音乐与音频': 4903,
'文件': 4906,
'分享卡片': 4905,
'拍一拍等系统消息': 10000
}
file_format = {
'Docx': Output.DOCX,
'TXT': Output.TXT,
'HTML': Output.HTML,
'CSV': Output.CSV,
}
Stylesheet = """
QPushButton{
background-color: #ffffff;
}
QPushButton:hover {
background-color: lightgray;
}
"""
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)
self.export_choices = {"文本": True, "图片": True, "语音": False, "视频": False, "表情包": False,
'音乐与音频': False, '分享卡片': False, '文件': False,
'拍一拍等系统消息': True} # 定义导出的数据类型,默认全部选择
self.setWindowTitle(title)
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
def set_export_date(self):
date_range = self.comboBox_time.currentText()
if date_range == '全部时间':
pass
elif date_range == '最近三个月':
QMessageBox.warning(self,
"别急别急",
"马上就实现该功能"
)
elif date_range == '自定义时间':
QMessageBox.warning(self,
"别急别急",
"马上就实现该功能"
)
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]:
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)
# 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在./data/目录下(跟exe文件在一起)")
reply.addButton("确认", QMessageBox.AcceptRole)
reply.addButton("取消", QMessageBox.RejectRole)
api = reply.exec_()
self.accept()
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_())

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

@ -0,0 +1,118 @@
# -*- 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(553, 394)
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.setObjectName("verticalLayout")
self.label = QtWidgets.QLabel(Dialog)
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)
self.checkBox_txt.setChecked(True)
self.checkBox_txt.setObjectName("checkBox_txt")
self.verticalLayout.addWidget(self.checkBox_txt)
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem1)
self.horizontalLayout_2.addLayout(self.verticalLayout)
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.label_2 = QtWidgets.QLabel(Dialog)
self.label_2.setObjectName("label_2")
self.verticalLayout_2.addWidget(self.label_2)
self.horizontalLayout_2.addLayout(self.verticalLayout_2)
self.listWidget = QtWidgets.QListWidget(Dialog)
self.listWidget.setObjectName("listWidget")
self.horizontalLayout_2.addWidget(self.listWidget)
self.horizontalLayout_2.setStretch(0, 1)
self.horizontalLayout_2.setStretch(1, 1)
self.horizontalLayout_2.setStretch(2, 5)
self.verticalLayout_3.addLayout(self.horizontalLayout_2)
self.progressBar = QtWidgets.QProgressBar(Dialog)
self.progressBar.setProperty("value", 24)
self.progressBar.setObjectName("progressBar")
self.verticalLayout_3.addWidget(self.progressBar)
self.label_process = QtWidgets.QLabel(Dialog)
self.label_process.setText("")
self.label_process.setObjectName("label_process")
self.verticalLayout_3.addWidget(self.label_process)
self.label_time = QtWidgets.QLabel(Dialog)
self.label_time.setText("")
self.label_time.setObjectName("label_time")
self.verticalLayout_3.addWidget(self.label_time)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
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.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.label_2.setText(_translate("Dialog", "消息类型"))
self.btn_start.setText(_translate("Dialog", "开始"))

View File

@ -67,6 +67,7 @@
- 个人年度报告 - 个人年度报告
- 群组年度报告 - 群组年度报告
- 按日期、关键词索引 - 按日期、关键词索引
- 支持企业微信好友
- 小伙伴们想要其他功能可以留言哦📬 - 小伙伴们想要其他功能可以留言哦📬
- 🔥项目正处于并将长期处于发展阶段,给我一些时间♾️,你所期望的未来都会实现(养成系开发者),可关注文末公众号持续获取项目更新动态 - 🔥项目正处于并将长期处于发展阶段,给我一些时间♾️,你所期望的未来都会实现(养成系开发者),可关注文末公众号持续获取项目更新动态