mirror of
https://github.com/LC044/WeChatMsg
synced 2024-11-09 09:31:18 +08:00
支持批量导出聊天记录
This commit is contained in:
parent
cd08bf3862
commit
15fc176749
@ -1,6 +1,7 @@
|
||||
import csv
|
||||
import os
|
||||
import traceback
|
||||
from typing import List
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, QThread
|
||||
from PyQt5.QtWidgets import QFileDialog
|
||||
@ -27,6 +28,8 @@ class Output(QThread):
|
||||
progressSignal = pyqtSignal(int)
|
||||
rangeSignal = pyqtSignal(int)
|
||||
okSignal = pyqtSignal(int)
|
||||
batchOkSignal = pyqtSignal(int)
|
||||
nowContact = pyqtSignal(str)
|
||||
i = 1
|
||||
CSV = 0
|
||||
DOCX = 1
|
||||
@ -34,17 +37,18 @@ class Output(QThread):
|
||||
CSV_ALL = 3
|
||||
CONTACT_CSV = 4
|
||||
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)
|
||||
self.Child0 = None
|
||||
self.children = []
|
||||
self.last_timestamp = 0
|
||||
self.sub_type = sub_type
|
||||
self.message_types = message_types
|
||||
self.sec = 2 # 默认1000秒
|
||||
self.contact = contact
|
||||
self.ta_username = contact.wxid if contact else ''
|
||||
self.msg_id = 0
|
||||
self.output_type = type_
|
||||
self.output_type: int | List[int] = type_
|
||||
self.total_num = 1
|
||||
self.num = 0
|
||||
|
||||
@ -123,60 +127,115 @@ class Output(QThread):
|
||||
gender = '男'
|
||||
else:
|
||||
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)
|
||||
|
||||
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):
|
||||
if self.output_type == self.DOCX:
|
||||
self.Child = DocxExporter(self.contact, type_=self.output_type, message_types=self.message_types)
|
||||
self.Child.progressSignal.connect(self.progress)
|
||||
self.Child.rangeSignal.connect(self.rangeSignal)
|
||||
self.Child.okSignal.connect(self.okSignal)
|
||||
self.Child.start()
|
||||
self.to_docx(self.contact, self.message_types)
|
||||
elif self.output_type == self.CSV_ALL:
|
||||
self.to_csv_all()
|
||||
elif self.output_type == self.CONTACT_CSV:
|
||||
self.contact_to_csv()
|
||||
elif self.output_type == self.TXT:
|
||||
self.Child = TxtExporter(self.contact, type_=self.output_type, message_types=self.message_types)
|
||||
self.Child.progressSignal.connect(self.progress)
|
||||
self.Child.rangeSignal.connect(self.rangeSignal)
|
||||
self.Child.okSignal.connect(self.okSignal)
|
||||
self.Child.start()
|
||||
self.to_txt(self.contact, self.message_types)
|
||||
elif self.output_type == self.CSV:
|
||||
self.Child = CSVExporter(self.contact, type_=self.output_type, message_types=self.message_types)
|
||||
self.Child.progressSignal.connect(self.progress)
|
||||
self.Child.rangeSignal.connect(self.rangeSignal)
|
||||
self.Child.okSignal.connect(self.okSignal)
|
||||
self.Child.start()
|
||||
self.to_csv(self.contact, self.message_types)
|
||||
elif self.output_type == self.HTML:
|
||||
self.Child = HtmlExporter(self.contact, type_=self.output_type, message_types=self.message_types)
|
||||
self.Child.progressSignal.connect(self.progress)
|
||||
self.Child.rangeSignal.connect(self.rangeSignal)
|
||||
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()
|
||||
self.to_html(self.contact, self.message_types)
|
||||
elif self.output_type == self.Batch:
|
||||
self.batch_export()
|
||||
|
||||
def count_finish_num(self, num):
|
||||
"""
|
||||
@ -187,7 +246,11 @@ class Output(QThread):
|
||||
self.num += 1
|
||||
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):
|
||||
self.requestInterruption()
|
||||
|
@ -3,7 +3,6 @@ from datetime import datetime
|
||||
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||
from PyQt5.QtCore import *
|
||||
|
||||
import app.DataBase.data as data
|
||||
from app import person
|
||||
|
||||
|
||||
|
120
app/components/export_contact_item.py
Normal file
120
app/components/export_contact_item.py
Normal 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_())
|
@ -74,7 +74,7 @@ class Contact(Person):
|
||||
self.nickName = contact_info.get('NickName')
|
||||
if not self.remark:
|
||||
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.smallHeadImgBLOG = b''
|
||||
self.avatar = QPixmap()
|
||||
|
@ -20,6 +20,7 @@ from . import mainwindow
|
||||
from app.ui.menu.about_dialog import AboutDialog
|
||||
from .chat import ChatWindow
|
||||
from .contact import ContactWindow
|
||||
from .menu.export import ExportDialog
|
||||
from .tool.tool_window import ToolWindow
|
||||
from ..DataBase.output_pc import Output
|
||||
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_contacts.setIcon(Icon.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_help_contact.triggered.connect(
|
||||
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(
|
||||
lambda x: self.message('联系人导出成功'))
|
||||
self.outputThread.start()
|
||||
elif self.sender() == self.action_batch_export:
|
||||
dialog = ExportDialog(None, title='批量导出聊天记录', parent=self)
|
||||
result = dialog.exec_() # 使用exec_()获取用户的操作结果
|
||||
|
||||
def message(self, msg):
|
||||
self.stopBusy()
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
# 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
|
||||
# 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_about = QtWidgets.QMenu(self.menubar)
|
||||
self.menu_about.setObjectName("menu_about")
|
||||
self.menu_3 = QtWidgets.QMenu(self.menubar)
|
||||
self.menu_3.setObjectName("menu_3")
|
||||
MainWindow.setMenuBar(self.menubar)
|
||||
self.statusbar = QtWidgets.QStatusBar(MainWindow)
|
||||
font = QtGui.QFont()
|
||||
@ -125,6 +123,8 @@ class Ui_MainWindow(object):
|
||||
self.action_output_CSV.setObjectName("action_output_CSV")
|
||||
self.action_output_contacts = QtWidgets.QAction(MainWindow)
|
||||
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.addAction(self.action_3)
|
||||
@ -132,6 +132,7 @@ class Ui_MainWindow(object):
|
||||
self.menu_output.addAction(self.action_output_CSV)
|
||||
self.menu_data.addAction(self.menu_output.menuAction())
|
||||
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_chat)
|
||||
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_2.menuAction())
|
||||
self.menubar.addAction(self.menu_about.menuAction())
|
||||
self.menubar.addAction(self.menu_3.menuAction())
|
||||
|
||||
self.retranslateUi(MainWindow)
|
||||
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||
@ -167,7 +167,6 @@ class Ui_MainWindow(object):
|
||||
self.menu_output.setTitle(_translate("MainWindow", "导出聊天记录(全部)"))
|
||||
self.menu_2.setTitle(_translate("MainWindow", "帮助"))
|
||||
self.menu_about.setTitle(_translate("MainWindow", "关于"))
|
||||
self.menu_3.setTitle(_translate("MainWindow", "不显示或者显示异常请重启应用、没反应那就多等一会儿"))
|
||||
self.action_3.setText(_translate("MainWindow", "保存"))
|
||||
self.action_4.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_output_CSV.setText(_translate("MainWindow", "CSV"))
|
||||
self.action_output_contacts.setText(_translate("MainWindow", "导出联系人"))
|
||||
self.action_batch_export.setText(_translate("MainWindow", "批量导出"))
|
||||
|
233
app/ui/menu/export.py
Normal file
233
app/ui/menu/export.py
Normal 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
118
app/ui/menu/exportUi.py
Normal 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", "开始"))
|
Loading…
Reference in New Issue
Block a user