init
This commit is contained in:
45
app/ui/Icon.py
Normal file
45
app/ui/Icon.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from PyQt5.QtGui import QIcon
|
||||
|
||||
from app.resources import resource_rc
|
||||
|
||||
var = resource_rc.qt_resource_name
|
||||
|
||||
|
||||
class Icon:
|
||||
Default_avatar_path = ':/icons/icons/default_avatar.svg'
|
||||
Default_image_path = ':/icons/icons/404.png'
|
||||
logo_path = ':/icons/icons/logo99.png'
|
||||
logo_ico_path = ':/icons/icons/logo3.0.ico'
|
||||
MainWindow_Icon = QIcon(':/icons/icons/logo.svg')
|
||||
Default_avatar = QIcon(Default_avatar_path)
|
||||
Output = QIcon(':/icons/icons/output.svg')
|
||||
Back = QIcon(':/icons/icons/back.svg')
|
||||
ToDocx = QIcon(':/icons/icons/word.svg')
|
||||
ToCSV = QIcon(':/icons/icons/csv.svg')
|
||||
ToHTML = QIcon(':/icons/icons/html.svg')
|
||||
ToTXT = QIcon(':/icons/icons/txt.svg')
|
||||
Chat_Icon = QIcon(':/icons/icons/chat.svg')
|
||||
Contact_Icon = QIcon(':/icons/icons/contact.svg')
|
||||
MyInfo_Icon = QIcon(':/icons/icons/myinfo.svg')
|
||||
Annual_Report_Icon = QIcon(':/icons/icons/annual_report.svg')
|
||||
Analysis_Icon = QIcon(':/icons/icons/analysis.svg')
|
||||
Emotion_Icon = QIcon(':/icons/icons/emotion.svg')
|
||||
Search_Icon = QIcon(':/icons/icons/search.svg')
|
||||
Tool_Icon = QIcon(':/icons/icons/tool.svg')
|
||||
Home_Icon = QIcon(':/icons/icons/home.svg')
|
||||
Help_Icon = QIcon(':/icons/icons/help.svg')
|
||||
Get_info_Icon = QIcon(':/icons/icons/get_wx_info.svg')
|
||||
Folder_Icon = QIcon(':/icons/icons/folder.svg')
|
||||
Start_Icon = QIcon(':/icons/icons/start.svg')
|
||||
Decrypt_Icon = QIcon(':/icons/icons/decrypt.svg')
|
||||
Man_Icon_path = ':/icons/icons/man.svg'
|
||||
Woman_Icon_path = ':/icons/icons/woman.svg'
|
||||
Man_Icon = QIcon(':/icons/icons/man.svg')
|
||||
Woman_Icon = QIcon(':/icons/icons/woman.svg')
|
||||
Arrow_left_Icon = QIcon(':/icons/icons/arrow-left.svg')
|
||||
Arrow_right_Icon = QIcon(':/icons/icons/arrow-right.svg')
|
||||
Update_Icon = QIcon(':/icons/icons/update.svg')
|
||||
Clear_Icon = QIcon(':/icons/icons/clear.svg')
|
||||
# Man_Icon_pixmap = QPixmap(Man_Icon_path)
|
||||
# Woman_Icon_pixmap = QPixmap(Woman_Icon_path)
|
||||
# Logo_Icon = QIcon(':/icons/icons/logo.png')
|
||||
105
app/ui/QSS/style.qss
Normal file
105
app/ui/QSS/style.qss
Normal file
@@ -0,0 +1,105 @@
|
||||
QWidget{
|
||||
background: rgb(238,244,249);
|
||||
}
|
||||
/*去掉item虚线边框*/
|
||||
QListWidget, QListView, QTreeWidget, QTreeView {
|
||||
outline: 0px;
|
||||
}
|
||||
QMenu::item:selected {
|
||||
color: black;
|
||||
background: rgb(230, 235, 240);
|
||||
}
|
||||
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
|
||||
QListWidget {
|
||||
min-width: 120px;
|
||||
max-width: 380px;
|
||||
color: black;
|
||||
border:none;
|
||||
}
|
||||
QListWidget::item{
|
||||
min-width: 80px;
|
||||
max-width: 380px;
|
||||
min-height: 60px;
|
||||
max-height: 60px;
|
||||
}
|
||||
QListWidget::item:hover {
|
||||
background: rgb(230, 235, 240);
|
||||
}
|
||||
/*被选中时的背景颜色和左边框颜色*/
|
||||
QListWidget::item:selected {
|
||||
background: rgb(230, 235, 240);
|
||||
border-left: 2px solid rgb(62, 62, 62);
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
/*鼠标悬停颜色*/
|
||||
HistoryPanel::item:hover {
|
||||
background: rgb(52, 52, 52);
|
||||
}
|
||||
|
||||
QCheckBox::indicator {
|
||||
background: rgb(255, 255, 255);
|
||||
Width:20px;
|
||||
Height:20px;
|
||||
border-radius: 10px
|
||||
}
|
||||
QCheckBox::indicator:unchecked{
|
||||
Width:20px;
|
||||
Height:20px;
|
||||
image: url(:/icons/icons/unselect.svg);
|
||||
}
|
||||
QCheckBox::indicator:checked{
|
||||
Width:20px;
|
||||
Height:20px;
|
||||
image: url(:/icons/icons/select.svg);
|
||||
}
|
||||
QScrollBar:vertical {
|
||||
border-width: 0px;
|
||||
border: none;
|
||||
background:rgba(133, 135, 138, 0);
|
||||
width:4px;
|
||||
margin: 0px 0px 0px 0px;
|
||||
}
|
||||
QScrollBar::handle:vertical {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||
stop: 0 rgb(133, 135, 138), stop: 0.5 rgb(133, 135, 138), stop:1 rgb(133, 135, 138));
|
||||
min-height: 20px;
|
||||
max-height: 20px;
|
||||
margin: 0 0px 0 0px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
QScrollBar::add-line:vertical {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||
stop: 0 rgba(133, 135, 138, 0), stop: 0.5 rgba(133, 135, 138, 0), stop:1 rgba(133, 135, 138, 0));
|
||||
height: 0px;
|
||||
border: none;
|
||||
subcontrol-position: bottom;
|
||||
subcontrol-origin: margin;
|
||||
}
|
||||
QScrollBar::sub-line:vertical {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||
stop: 0 rgba(133, 135, 138, 0), stop: 0.5 rgba(133, 135, 138, 0), stop:1 rgba(133, 135, 138, 0));
|
||||
height: 0 px;
|
||||
border: none;
|
||||
subcontrol-position: top;
|
||||
subcontrol-origin: margin;
|
||||
}
|
||||
QScrollBar::sub-page:vertical {
|
||||
background: rgba(133, 135, 138, 0);
|
||||
}
|
||||
|
||||
QScrollBar::add-page:vertical {
|
||||
background: rgba(133, 135, 138, 0);
|
||||
}
|
||||
QProgressBar{
|
||||
height:22px;
|
||||
text-align:center;
|
||||
font-size:14px;
|
||||
color:rgb(49, 218, 27);
|
||||
border-radius:11px;
|
||||
background:#EBEEF5;
|
||||
}
|
||||
QProgressBar::chunk{
|
||||
border-radius:11px;
|
||||
background:qlineargradient(spread:pad,x1:0,y1:0,x2:1,y2:0,stop:0 #99ffff,stop:1 #9900ff);
|
||||
}
|
||||
0
app/ui/__init__.py
Normal file
0
app/ui/__init__.py
Normal file
1
app/ui/chat/__init__.py
Normal file
1
app/ui/chat/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .chat_window import ChatWindow
|
||||
217
app/ui/chat/ai_chat.py
Normal file
217
app/ui/chat/ai_chat.py
Normal file
@@ -0,0 +1,217 @@
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import requests
|
||||
from PyQt5.QtCore import QThread, pyqtSignal, QSize, Qt
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QHBoxLayout, QApplication, QTextBrowser, QMessageBox
|
||||
|
||||
from app import config
|
||||
from app.config import SERVER_API_URL
|
||||
from app.log import logger
|
||||
from app.ui.Icon import Icon
|
||||
|
||||
try:
|
||||
from .chatInfoUi import Ui_Form
|
||||
except:
|
||||
from chatInfoUi import Ui_Form
|
||||
from app.components.bubble_message import BubbleMessage
|
||||
from app.person import Me, ContactDefault
|
||||
|
||||
|
||||
class Message(QWidget):
|
||||
def __init__(self, is_send=False, text='', parent=None):
|
||||
super().__init__(parent)
|
||||
self.avatar = QLabel(self)
|
||||
|
||||
self.textBrowser = QTextBrowser(self)
|
||||
self.textBrowser.setText(text)
|
||||
|
||||
layout = QHBoxLayout(self)
|
||||
if is_send:
|
||||
pixmap = Me().avatar.scaled(45, 45)
|
||||
self.textBrowser.setLayoutDirection(Qt.RightToLeft)
|
||||
self.textBrowser.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
self.avatar.setPixmap(pixmap)
|
||||
layout.addWidget(self.textBrowser)
|
||||
layout.addWidget(self.avatar)
|
||||
else:
|
||||
pixmap = QPixmap(Icon.Default_avatar_path).scaled(45, 45)
|
||||
self.avatar.setPixmap(pixmap)
|
||||
layout.addWidget(self.avatar)
|
||||
layout.addWidget(self.textBrowser)
|
||||
# self.textBrowser.setFixedHeight(int(self.textBrowser.document().size().height()))
|
||||
self.textBrowser.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
self.avatar.setFixedSize(QSize(60, 60))
|
||||
|
||||
def append(self, text: str):
|
||||
self.textBrowser.insertPlainText(text)
|
||||
self.textBrowser.setFixedHeight(int(self.textBrowser.document().size().height()))
|
||||
|
||||
|
||||
class AIChat(QWidget, Ui_Form):
|
||||
def __init__(self, contact, parent=None):
|
||||
super().__init__(parent)
|
||||
self.now_message: Message = None
|
||||
self.setupUi(self)
|
||||
self.last_timestamp = 0
|
||||
self.last_str_time = ''
|
||||
self.last_pos = 0
|
||||
self.contact = contact
|
||||
self.init_ui()
|
||||
self.show_chats()
|
||||
self.pushButton.clicked.connect(self.send_msg)
|
||||
self.toolButton.clicked.connect(self.tool)
|
||||
self.btn_clear.clicked.connect(self.clear_dialog)
|
||||
self.btn_clear.setIcon(Icon.Clear_Icon)
|
||||
|
||||
def init_ui(self):
|
||||
self.textEdit.installEventFilter(self)
|
||||
|
||||
def tool(self):
|
||||
QMessageBox.information(self, "温馨提示", "暂未接入聊天数据,您可进行基础的AI对话,后续更新敬请期待")
|
||||
|
||||
def chat(self, text):
|
||||
self.now_message.append(text)
|
||||
self.scrollArea.verticalScrollBar().setValue(self.scrollArea.verticalScrollBar().maximum())
|
||||
|
||||
def send_msg(self):
|
||||
msg = self.textEdit.toPlainText().strip()
|
||||
self.textEdit.setText('')
|
||||
if not msg:
|
||||
return
|
||||
print(msg)
|
||||
bubble_message = BubbleMessage(
|
||||
msg,
|
||||
Me().avatar,
|
||||
1,
|
||||
True,
|
||||
)
|
||||
self.verticalLayout_message.addWidget(bubble_message)
|
||||
message1 = Message(False)
|
||||
self.verticalLayout_message.addWidget(message1)
|
||||
self.show_chat_thread.msg = msg
|
||||
self.now_message = message1
|
||||
self.show_chat_thread.start()
|
||||
self.scrollArea.verticalScrollBar().setValue(self.scrollArea.verticalScrollBar().maximum())
|
||||
|
||||
def clear_dialog(self):
|
||||
self.show_chat_thread.history = []
|
||||
while self.verticalLayout_message.count():
|
||||
item = self.verticalLayout_message.takeAt(0)
|
||||
widget = item.widget()
|
||||
if widget is not None:
|
||||
widget.deleteLater()
|
||||
else:
|
||||
del item
|
||||
|
||||
def show_chats(self):
|
||||
# return
|
||||
self.show_chat_thread = AIChatThread()
|
||||
self.show_chat_thread.msgSignal.connect(self.chat)
|
||||
|
||||
def update_history_messages(self):
|
||||
print('开始发送信息')
|
||||
message1 = Message(False)
|
||||
msg = '你好!'
|
||||
self.verticalLayout_message.addWidget(message1)
|
||||
self.show_chat_thread.msg = msg
|
||||
self.now_message = message1
|
||||
self.show_chat_thread.start()
|
||||
|
||||
def add_message(self, message):
|
||||
print('message', message)
|
||||
# self.textBrowser.append(message)
|
||||
self.textBrowser.insertPlainText(message)
|
||||
self.textBrowser.setFixedHeight(int(self.textBrowser.document().size().height()))
|
||||
|
||||
def eventFilter(self, obj, event):
|
||||
if obj == self.textEdit and event.type() == event.KeyPress:
|
||||
key = event.key()
|
||||
if key == 16777220: # 回车键的键值
|
||||
self.send_msg()
|
||||
self.textEdit.setText('')
|
||||
return True
|
||||
return super().eventFilter(obj, event)
|
||||
|
||||
|
||||
class AIChatThread(QThread):
|
||||
msgSignal = pyqtSignal(str)
|
||||
showSingal = pyqtSignal(tuple)
|
||||
finishSingal = pyqtSignal(int)
|
||||
msg_id = 0
|
||||
|
||||
# heightSingal = pyqtSignal(int)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.msg = ''
|
||||
self.history = []
|
||||
|
||||
def run(self) -> None:
|
||||
url = urljoin(SERVER_API_URL, 'chat')
|
||||
data = {
|
||||
'username': Me().wxid,
|
||||
'token': Me().token,
|
||||
'version': config.version,
|
||||
'messages': [
|
||||
*self.history,
|
||||
{
|
||||
'role': 'user',
|
||||
"content": self.msg
|
||||
}
|
||||
]
|
||||
}
|
||||
message = '''
|
||||
幼儿园三班一共有35人,上个月34人满勤。\n其中1月15日,小明同学感冒了,他的妈妈给他请了一天的病假。
|
||||
'''
|
||||
try:
|
||||
# for s in message:
|
||||
# self.msgSignal.emit(s)
|
||||
# time.sleep(0.05)
|
||||
# return
|
||||
resp = requests.post(url, json=data, stream=True)
|
||||
message = {
|
||||
'role': 'user',
|
||||
'content': self.msg
|
||||
}
|
||||
resp_message = {
|
||||
'role': 'assistant',
|
||||
'content': ''
|
||||
}
|
||||
if resp.status_code == 200:
|
||||
for line in resp.iter_lines():
|
||||
if line:
|
||||
trunk = line.decode('utf-8')
|
||||
try:
|
||||
data = json.loads(trunk.strip('data: '))
|
||||
answer = data.get('answer')
|
||||
print(answer)
|
||||
if isinstance(answer, str):
|
||||
resp_message['content'] += answer
|
||||
self.msgSignal.emit(answer)
|
||||
except:
|
||||
print(trunk)
|
||||
resp_message['content'] += trunk
|
||||
self.msgSignal.emit(trunk)
|
||||
else:
|
||||
print(resp.text)
|
||||
error = resp.json().get('error')
|
||||
logger.error(f'ai请求错误:{error}')
|
||||
self.msgSignal.emit(error)
|
||||
self.history.append(message)
|
||||
self.history.append(resp_message)
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
logger.error(f'ai请求错误:{error}{traceback.format_exc()}')
|
||||
self.msgSignal.emit(error)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
contact = ContactDefault('1')
|
||||
dialog = AIChat(contact)
|
||||
dialog.show()
|
||||
sys.exit(app.exec_())
|
||||
74
app/ui/chat/chatInfoUi.py
Normal file
74
app/ui/chat/chatInfoUi.py
Normal file
@@ -0,0 +1,74 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'chatInfoUi.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_Form(object):
|
||||
def setupUi(self, Form):
|
||||
Form.setObjectName("Form")
|
||||
Form.resize(817, 748)
|
||||
self.horizontalLayout_7 = QtWidgets.QHBoxLayout(Form)
|
||||
self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_7.setSpacing(0)
|
||||
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
|
||||
self.frame = QtWidgets.QFrame(Form)
|
||||
self.frame.setFrameShape(QtWidgets.QFrame.NoFrame)
|
||||
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||
self.frame.setObjectName("frame")
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame)
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.label_reamrk = QtWidgets.QLabel(self.frame)
|
||||
self.label_reamrk.setObjectName("label_reamrk")
|
||||
self.horizontalLayout_2.addWidget(self.label_reamrk)
|
||||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_2.addItem(spacerItem)
|
||||
self.btn_clear = QtWidgets.QPushButton(self.frame)
|
||||
self.btn_clear.setObjectName("btn_clear")
|
||||
self.horizontalLayout_2.addWidget(self.btn_clear)
|
||||
self.toolButton = QtWidgets.QToolButton(self.frame)
|
||||
self.toolButton.setObjectName("toolButton")
|
||||
self.horizontalLayout_2.addWidget(self.toolButton)
|
||||
self.verticalLayout_2.addLayout(self.horizontalLayout_2)
|
||||
self.scrollArea = QtWidgets.QScrollArea(self.frame)
|
||||
self.scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame)
|
||||
self.scrollArea.setWidgetResizable(True)
|
||||
self.scrollArea.setObjectName("scrollArea")
|
||||
self.scrollAreaWidgetContents = QtWidgets.QWidget()
|
||||
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 799, 564))
|
||||
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
|
||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents)
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
self.verticalLayout_message = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout_message.setObjectName("verticalLayout_message")
|
||||
self.verticalLayout_3.addLayout(self.verticalLayout_message)
|
||||
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
|
||||
self.verticalLayout_2.addWidget(self.scrollArea)
|
||||
self.textEdit = QtWidgets.QTextEdit(self.frame)
|
||||
self.textEdit.setMaximumSize(QtCore.QSize(16777215, 100))
|
||||
self.textEdit.setObjectName("textEdit")
|
||||
self.verticalLayout_2.addWidget(self.textEdit)
|
||||
self.pushButton = QtWidgets.QPushButton(self.frame)
|
||||
self.pushButton.setObjectName("pushButton")
|
||||
self.verticalLayout_2.addWidget(self.pushButton)
|
||||
self.horizontalLayout_7.addWidget(self.frame)
|
||||
|
||||
self.retranslateUi(Form)
|
||||
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||
|
||||
def retranslateUi(self, Form):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Form.setWindowTitle(_translate("Form", "Form"))
|
||||
self.label_reamrk.setText(_translate("Form", "EmoAi"))
|
||||
self.btn_clear.setText(_translate("Form", "清除对话"))
|
||||
self.toolButton.setText(_translate("Form", "..."))
|
||||
self.pushButton.setText(_translate("Form", "发送"))
|
||||
66
app/ui/chat/chatUi.py
Normal file
66
app/ui/chat/chatUi.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'chatUi.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_Form(object):
|
||||
def setupUi(self, Form):
|
||||
Form.setObjectName("Form")
|
||||
Form.resize(840, 752)
|
||||
Form.setStyleSheet("background: rgb(240, 240, 240);")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(Form)
|
||||
self.horizontalLayout_2.setSpacing(6)
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout_2.setSpacing(6)
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.label = QtWidgets.QLabel(Form)
|
||||
self.label.setText("")
|
||||
self.label.setObjectName("label")
|
||||
self.horizontalLayout.addWidget(self.label)
|
||||
self.lineEdit = QtWidgets.QLineEdit(Form)
|
||||
self.lineEdit.setMinimumSize(QtCore.QSize(200, 30))
|
||||
self.lineEdit.setMaximumSize(QtCore.QSize(200, 16777215))
|
||||
self.lineEdit.setStyleSheet("")
|
||||
self.lineEdit.setCursorMoveStyle(QtCore.Qt.VisualMoveStyle)
|
||||
self.lineEdit.setObjectName("lineEdit")
|
||||
self.horizontalLayout.addWidget(self.lineEdit)
|
||||
self.label_2 = QtWidgets.QLabel(Form)
|
||||
self.label_2.setMinimumSize(QtCore.QSize(30, 0))
|
||||
self.label_2.setText("")
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.horizontalLayout.addWidget(self.label_2)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
self.verticalLayout_2.addLayout(self.verticalLayout)
|
||||
self.listWidget = QtWidgets.QListWidget(Form)
|
||||
self.listWidget.setMinimumSize(QtCore.QSize(250, 0))
|
||||
self.listWidget.setMaximumSize(QtCore.QSize(250, 16777215))
|
||||
self.listWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
self.listWidget.setObjectName("listWidget")
|
||||
self.verticalLayout_2.addWidget(self.listWidget)
|
||||
self.verticalLayout_2.setStretch(1, 1)
|
||||
self.horizontalLayout_2.addLayout(self.verticalLayout_2)
|
||||
self.stackedWidget = QtWidgets.QStackedWidget(Form)
|
||||
self.stackedWidget.setObjectName("stackedWidget")
|
||||
self.horizontalLayout_2.addWidget(self.stackedWidget)
|
||||
self.horizontalLayout_2.setStretch(1, 1)
|
||||
|
||||
self.retranslateUi(Form)
|
||||
self.stackedWidget.setCurrentIndex(-1)
|
||||
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||
|
||||
def retranslateUi(self, Form):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Form.setWindowTitle(_translate("Form", "Form"))
|
||||
188
app/ui/chat/chat_info.py
Normal file
188
app/ui/chat/chat_info.py
Normal file
@@ -0,0 +1,188 @@
|
||||
import traceback
|
||||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QHBoxLayout
|
||||
|
||||
from app.DataBase import msg_db, hard_link_db
|
||||
from app.components.bubble_message import BubbleMessage, ChatWidget, Notice
|
||||
from app.person import Me
|
||||
from app.util import get_abs_path
|
||||
from app.util.emoji import get_emoji
|
||||
|
||||
|
||||
class ChatInfo(QWidget):
|
||||
def __init__(self, contact, parent=None):
|
||||
super().__init__(parent)
|
||||
self.last_timestamp = 0
|
||||
self.last_str_time = ''
|
||||
self.last_pos = 0
|
||||
self.contact = contact
|
||||
self.init_ui()
|
||||
self.show_chats()
|
||||
|
||||
def init_ui(self):
|
||||
self.label_reamrk = QLabel(self.contact.remark)
|
||||
|
||||
self.hBoxLayout = QHBoxLayout()
|
||||
self.hBoxLayout.addWidget(self.label_reamrk)
|
||||
|
||||
self.vBoxLayout = QVBoxLayout()
|
||||
self.vBoxLayout.setSpacing(0)
|
||||
self.vBoxLayout.addLayout(self.hBoxLayout)
|
||||
|
||||
self.chat_window = ChatWidget()
|
||||
self.chat_window.scrollArea.verticalScrollBar().valueChanged.connect(self.verticalScrollBar)
|
||||
self.vBoxLayout.addWidget(self.chat_window)
|
||||
self.setLayout(self.vBoxLayout)
|
||||
|
||||
def show_chats(self):
|
||||
# Me().save_avatar()
|
||||
# self.contact.save_avatar()
|
||||
self.show_chat_thread = ShowChatThread(self.contact)
|
||||
self.show_chat_thread.showSingal.connect(self.add_message)
|
||||
self.show_chat_thread.finishSingal.connect(self.show_finish)
|
||||
# self.show_chat_thread.start()
|
||||
|
||||
def show_finish(self, ok):
|
||||
self.setScrollBarPos()
|
||||
self.show_chat_thread.quit()
|
||||
|
||||
def verticalScrollBar(self, pos):
|
||||
"""
|
||||
滚动条到0之后自动更新聊天记录
|
||||
:param pos:
|
||||
:return:
|
||||
"""
|
||||
# print(pos)
|
||||
if pos > 0:
|
||||
return
|
||||
|
||||
# 记录当前滚动条最大值
|
||||
self.last_pos = self.chat_window.verticalScrollBar().maximum()
|
||||
self.update_history_messages()
|
||||
|
||||
def update_history_messages(self):
|
||||
self.show_chat_thread.start()
|
||||
|
||||
def setScrollBarPos(self):
|
||||
"""
|
||||
将滚动条位置设置为上次看到的地方
|
||||
:param pos:
|
||||
:return:
|
||||
"""
|
||||
self.chat_window.update()
|
||||
self.chat_window.show()
|
||||
pos = self.chat_window.verticalScrollBar().maximum() - self.last_pos
|
||||
self.chat_window.set_scroll_bar_value(pos)
|
||||
|
||||
def is_5_min(self, timestamp):
|
||||
if abs(timestamp - self.last_timestamp) > 300:
|
||||
self.last_timestamp = timestamp
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_avatar_path(self, is_send, message, is_absolute_path=False) -> str:
|
||||
if self.contact.is_chatroom:
|
||||
avatar = message[13].smallHeadImgUrl
|
||||
else:
|
||||
avatar = Me().smallHeadImgUrl if is_send else self.contact.smallHeadImgUrl
|
||||
if is_absolute_path:
|
||||
if self.contact.is_chatroom:
|
||||
# message[13].save_avatar()
|
||||
avatar = message[13].avatar
|
||||
else:
|
||||
avatar = Me().avatar if is_send else self.contact.avatar
|
||||
return avatar
|
||||
|
||||
def get_display_name(self, is_send, message) -> str:
|
||||
if self.contact.is_chatroom:
|
||||
if is_send:
|
||||
display_name = Me().name
|
||||
else:
|
||||
display_name = message[13].remark
|
||||
else:
|
||||
display_name = None
|
||||
return display_name
|
||||
|
||||
def add_message(self, message):
|
||||
try:
|
||||
type_ = message[2]
|
||||
str_content = message[7]
|
||||
str_time = message[8]
|
||||
# print(type_, type(type_))
|
||||
is_send = message[4]
|
||||
avatar = self.get_avatar_path(is_send, message,True)
|
||||
display_name = self.get_display_name(is_send, message)
|
||||
timestamp = message[5]
|
||||
BytesExtra = message[10]
|
||||
if type_ == 1:
|
||||
if self.is_5_min(timestamp):
|
||||
time_message = Notice(self.last_str_time)
|
||||
self.last_str_time = str_time
|
||||
self.chat_window.add_message_item(time_message, 0)
|
||||
bubble_message = BubbleMessage(
|
||||
str_content,
|
||||
avatar,
|
||||
type_,
|
||||
is_send,
|
||||
display_name=display_name
|
||||
)
|
||||
self.chat_window.add_message_item(bubble_message, 0)
|
||||
elif type_ == 3:
|
||||
# return
|
||||
if self.is_5_min(timestamp):
|
||||
time_message = Notice(self.last_str_time)
|
||||
self.last_str_time = str_time
|
||||
self.chat_window.add_message_item(time_message, 0)
|
||||
image_path = hard_link_db.get_image(content=str_content, bytesExtra=BytesExtra, up_dir=Me().wx_dir,thumb=False)
|
||||
image_path = get_abs_path(image_path)
|
||||
bubble_message = BubbleMessage(
|
||||
image_path,
|
||||
avatar,
|
||||
type_,
|
||||
is_send
|
||||
)
|
||||
self.chat_window.add_message_item(bubble_message, 0)
|
||||
elif type_ == 47:
|
||||
return
|
||||
if self.is_5_min(timestamp):
|
||||
time_message = Notice(self.last_str_time)
|
||||
self.last_str_time = str_time
|
||||
self.chat_window.add_message_item(time_message, 0)
|
||||
image_path = get_emoji(str_content, thumb=True)
|
||||
bubble_message = BubbleMessage(
|
||||
image_path,
|
||||
avatar,
|
||||
3,
|
||||
is_send
|
||||
)
|
||||
self.chat_window.add_message_item(bubble_message, 0)
|
||||
elif type_ == 10000:
|
||||
str_content = str_content.lstrip('<revokemsg>').rstrip('</revokemsg>')
|
||||
message = Notice(str_content)
|
||||
self.chat_window.add_message_item(message, 0)
|
||||
except:
|
||||
print(message)
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
|
||||
class ShowChatThread(QThread):
|
||||
showSingal = pyqtSignal(tuple)
|
||||
finishSingal = pyqtSignal(int)
|
||||
msg_id = 0
|
||||
|
||||
# heightSingal = pyqtSignal(int)
|
||||
def __init__(self, contact):
|
||||
super().__init__()
|
||||
self.last_message_id = 9999999999
|
||||
self.wxid = contact.wxid
|
||||
|
||||
def run(self) -> None:
|
||||
messages = msg_db.get_message_by_num(self.wxid, self.last_message_id)
|
||||
if messages:
|
||||
self.last_message_id = messages[-1][0]
|
||||
for message in messages:
|
||||
self.showSingal.emit(message)
|
||||
self.msg_id += 1
|
||||
self.finishSingal.emit(1)
|
||||
186
app/ui/chat/chat_window.py
Normal file
186
app/ui/chat/chat_window.py
Normal file
@@ -0,0 +1,186 @@
|
||||
import shutil
|
||||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtWidgets import QWidget, QMessageBox, QAction, QLineEdit
|
||||
|
||||
from app.DataBase import micro_msg_db, misc_db, msg_db, close_db
|
||||
from app.components import ContactQListWidgetItem, ScrollBar
|
||||
from app.person import Contact, Me
|
||||
from app.ui.Icon import Icon
|
||||
from app.util import search
|
||||
from .ai_chat import AIChat
|
||||
from .chatUi import Ui_Form
|
||||
from .chat_info import ChatInfo
|
||||
|
||||
# 美化样式表
|
||||
Stylesheet = """
|
||||
|
||||
/*去掉item虚线边框*/
|
||||
QListWidget, QListView, QTreeWidget, QTreeView {
|
||||
outline: 0px;
|
||||
border:none;
|
||||
}
|
||||
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
|
||||
QListWidget {
|
||||
min-width: 250px;
|
||||
max-width: 250px;
|
||||
min-height: 80px;
|
||||
max-height: 1200px;
|
||||
color: black;
|
||||
border:none;
|
||||
}
|
||||
QListWidget::item{
|
||||
height:60px;
|
||||
width:250px;
|
||||
}
|
||||
/*被选中时的背景颜色和左边框颜色*/
|
||||
QListWidget::item:selected {
|
||||
background: rgb(230, 235, 240);
|
||||
border-left:none;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class ChatWindow(QWidget, Ui_Form):
|
||||
load_finish_signal = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.show_thread = None
|
||||
self.setupUi(self)
|
||||
self.ok_flag = False
|
||||
self.setStyleSheet(Stylesheet)
|
||||
self.contacts = [[], []]
|
||||
self.init_ui()
|
||||
self.show_chats()
|
||||
self.visited = set()
|
||||
self.now_index = 0
|
||||
|
||||
def init_ui(self):
|
||||
search_action = QAction(self.lineEdit)
|
||||
search_action.setIcon(Icon.Search_Icon)
|
||||
self.lineEdit.addAction(search_action, QLineEdit.LeadingPosition)
|
||||
self.lineEdit.returnPressed.connect(self.search_contact)
|
||||
self.listWidget.clear()
|
||||
self.listWidget.setVerticalScrollBar(ScrollBar())
|
||||
self.listWidget.currentRowChanged.connect(self.setCurrentIndex)
|
||||
self.listWidget.setCurrentRow(0)
|
||||
self.stackedWidget.setCurrentIndex(0)
|
||||
pixmap = QPixmap(Icon.Default_avatar_path).scaled(45, 45)
|
||||
contact_item = ContactQListWidgetItem('AI小助手', '', pixmap)
|
||||
self.listWidget.addItem(contact_item)
|
||||
self.listWidget.setItemWidget(contact_item, contact_item.widget)
|
||||
chat_info_window = AIChat(Me())
|
||||
self.stackedWidget.addWidget(chat_info_window)
|
||||
|
||||
def show_chats(self):
|
||||
# return
|
||||
if self.ok_flag:
|
||||
return
|
||||
msg_db.init_database()
|
||||
micro_msg_db.init_database()
|
||||
if not msg_db.open_flag:
|
||||
QMessageBox.critical(self, "错误", "数据库不存在\n请先解密数据库")
|
||||
self.show_thread = ShowThread()
|
||||
self.show_thread.load_finish_signal.connect(self.load_finish_signal)
|
||||
self.show_thread.start()
|
||||
return
|
||||
self.show_thread = ShowContactThread()
|
||||
self.show_thread.showSingal.connect(self.show_chat)
|
||||
self.show_thread.load_finish_signal.connect(self.stop_loading)
|
||||
self.show_thread.start()
|
||||
self.ok_flag = True
|
||||
|
||||
def search_contact(self):
|
||||
content = self.lineEdit.text()
|
||||
if not content:
|
||||
return
|
||||
index = self.search_contact_index(content)
|
||||
self.select_contact_by_index(index)
|
||||
|
||||
def search_contact_index(self, content: str) -> int:
|
||||
return search.search_by_content(content, self.contacts)
|
||||
|
||||
def select_contact_by_index(self, index):
|
||||
self.stackedWidget.setCurrentIndex(index)
|
||||
self.listWidget.setCurrentRow(index)
|
||||
|
||||
def show_chat(self, contact):
|
||||
# return
|
||||
self.contacts[0].append(contact.remark)
|
||||
self.contacts[1].append(contact.nickName)
|
||||
contact_item = ContactQListWidgetItem(contact.remark, contact.smallHeadImgUrl, contact.smallHeadImgBLOG)
|
||||
self.listWidget.addItem(contact_item)
|
||||
self.listWidget.setItemWidget(contact_item, contact_item.widget)
|
||||
chat_info_window = ChatInfo(contact)
|
||||
self.stackedWidget.addWidget(chat_info_window)
|
||||
|
||||
def setCurrentIndex(self, row):
|
||||
# print(row)
|
||||
item = self.listWidget.item(self.now_index)
|
||||
item.dis_select()
|
||||
self.stackedWidget.setCurrentIndex(row)
|
||||
item = self.listWidget.item(row)
|
||||
item.select()
|
||||
self.now_index = row
|
||||
if row not in self.visited:
|
||||
chat_info_window = self.stackedWidget.currentWidget()
|
||||
chat_info_window.update_history_messages()
|
||||
self.visited.add(row)
|
||||
|
||||
def stop_loading(self, a0):
|
||||
# self.label.setVisible(False)
|
||||
self.load_finish_signal.emit(True)
|
||||
|
||||
|
||||
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()
|
||||
if not contact_info_lists:
|
||||
self.load_finish_signal.emit(True)
|
||||
# QMessageBox.critical(None, "错误", "数据库错误,请重启电脑后重试")
|
||||
close_db()
|
||||
try:
|
||||
shutil.rmtree('./app/Database/Msg')
|
||||
except:
|
||||
pass
|
||||
return
|
||||
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)
|
||||
# pprint(contact.__dict__)
|
||||
self.load_finish_signal.emit(True)
|
||||
|
||||
|
||||
class ShowThread(QThread):
|
||||
showSingal = pyqtSignal(Contact)
|
||||
load_finish_signal = pyqtSignal(bool)
|
||||
|
||||
# heightSingal = pyqtSignal(int)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def run(self) -> None:
|
||||
QThread.sleep(1)
|
||||
self.load_finish_signal.emit(True)
|
||||
1
app/ui/contact/__init__.py
Normal file
1
app/ui/contact/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .contact_window import ContactWindow
|
||||
155
app/ui/contact/contactInfo.py
Normal file
155
app/ui/contact/contactInfo.py
Normal file
@@ -0,0 +1,155 @@
|
||||
from datetime import datetime
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, QUrl, QThread
|
||||
from PyQt5.QtGui import QDesktopServices
|
||||
from PyQt5.QtWidgets import QWidget, QMenu, QAction, QToolButton, QMessageBox
|
||||
|
||||
from app.ui.Icon import Icon
|
||||
from .contactInfoUi import Ui_Form
|
||||
from .userinfo import userinfo
|
||||
from ..menu.export_time_range import TimeRangeDialog
|
||||
from ...DataBase import msg_db
|
||||
from ...person import Contact, Me
|
||||
from app.ui.contact.export.export_dialog import ExportDialog
|
||||
|
||||
|
||||
class ContactInfo(QWidget, Ui_Form):
|
||||
"""
|
||||
显示联系人信息
|
||||
"""
|
||||
exitSignal = pyqtSignal()
|
||||
urlSignal = pyqtSignal(QUrl)
|
||||
|
||||
# username = ''
|
||||
def __init__(self, contact, parent=None):
|
||||
super(ContactInfo, self).__init__(parent)
|
||||
self.time_range = None
|
||||
self.setupUi(self)
|
||||
self.contact: Contact = contact
|
||||
self.view_userinfo = userinfo.UserinfoController(self.contact)
|
||||
self.btn_back.clicked.connect(self.back)
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
self.btn_back.setIcon(Icon.Back)
|
||||
self.btn_report.setIcon(Icon.Annual_Report_Icon)
|
||||
self.btn_analysis.setIcon(Icon.Analysis_Icon)
|
||||
self.btn_emotion.setIcon(Icon.Emotion_Icon)
|
||||
self.btn_report.clicked.connect(self.annual_report)
|
||||
self.btn_analysis.clicked.connect(self.analysis)
|
||||
self.btn_emotion.clicked.connect(self.emotionale_Analysis)
|
||||
self.stackedWidget.addWidget(self.view_userinfo)
|
||||
self.stackedWidget.setCurrentWidget(self.view_userinfo)
|
||||
menu = QMenu(self)
|
||||
self.toDocxAct = QAction(Icon.ToDocx, '导出Docx', self)
|
||||
self.toCSVAct = QAction(Icon.ToCSV, '导出CSV', self)
|
||||
self.toHtmlAct = QAction(Icon.ToHTML, '导出HTML', self)
|
||||
self.toTxtAct = QAction(Icon.ToTXT, '导出TXT', self)
|
||||
self.toAiTxtAct = QAction(Icon.ToTXT, '导出AI对话专用TXT', self)
|
||||
self.toJsonAct = QAction(Icon.ToTXT, '导出json', self)
|
||||
self.toolButton_output.setPopupMode(QToolButton.MenuButtonPopup)
|
||||
self.toolButton_output.clicked.connect(self.toolButton_show)
|
||||
menu.addAction(self.toDocxAct)
|
||||
menu.addAction(self.toCSVAct)
|
||||
menu.addAction(self.toHtmlAct)
|
||||
menu.addAction(self.toTxtAct)
|
||||
menu.addAction(self.toAiTxtAct)
|
||||
menu.addAction(self.toJsonAct)
|
||||
self.toolButton_output.setMenu(menu)
|
||||
self.toolButton_output.setIcon(Icon.Output)
|
||||
# self.toolButton_output.addSeparator()
|
||||
self.toHtmlAct.triggered.connect(self.output)
|
||||
self.toDocxAct.triggered.connect(self.output)
|
||||
self.toCSVAct.triggered.connect(self.output)
|
||||
self.toTxtAct.triggered.connect(self.output)
|
||||
self.toJsonAct.triggered.connect(self.output)
|
||||
self.toAiTxtAct.triggered.connect(self.output)
|
||||
|
||||
def set_contact(self, contact: Contact):
|
||||
self.view_userinfo.set_contact(contact)
|
||||
self.contact = contact
|
||||
|
||||
def toolButton_show(self):
|
||||
self.toolButton_output.showMenu()
|
||||
|
||||
def analysis(self):
|
||||
# QDesktopServices.openUrl(QUrl("https://memotrace.cn/"))
|
||||
self.report_thread = ReportThread(self.contact)
|
||||
# self.report_thread.okSignal.connect(lambda x: QDesktopServices.openUrl(QUrl("http://127.0.0.1:21314")))
|
||||
self.report_thread.start()
|
||||
QDesktopServices.openUrl(QUrl(f"http://127.0.0.1:21314/charts/{self.contact.wxid}"))
|
||||
|
||||
def annual_report(self):
|
||||
date_range = None
|
||||
chat_calendar = msg_db.get_messages_calendar(self.contact.wxid)
|
||||
if chat_calendar:
|
||||
start_time = datetime.strptime(chat_calendar[0], "%Y-%m-%d")
|
||||
end_time = datetime.strptime(chat_calendar[-1], "%Y-%m-%d")
|
||||
date_range = (start_time.date(), end_time.date())
|
||||
self.time_range_view = TimeRangeDialog(date_range=date_range, parent=self)
|
||||
self.time_range_view.date_range_signal.connect(self.set_time_range)
|
||||
self.time_range_view.show()
|
||||
if 'room' in self.contact.wxid:
|
||||
QMessageBox.warning(
|
||||
self, '警告',
|
||||
'暂不支持群组'
|
||||
)
|
||||
return
|
||||
|
||||
def set_time_range(self, time_range):
|
||||
self.time_range = time_range
|
||||
self.contact.save_avatar()
|
||||
Me().save_avatar()
|
||||
self.report_thread = ReportThread(self.contact, time_range)
|
||||
self.report_thread.start()
|
||||
QDesktopServices.openUrl(QUrl(f"http://127.0.0.1:21314/christmas/{self.contact.wxid}"))
|
||||
|
||||
def emotionale_Analysis(self):
|
||||
QDesktopServices.openUrl(QUrl("https://memotrace.cn/"))
|
||||
|
||||
def back(self):
|
||||
"""
|
||||
将userinfo界面设置为可见,其他界面设置为不可见
|
||||
"""
|
||||
return
|
||||
|
||||
def output(self):
|
||||
"""
|
||||
导出聊天记录
|
||||
:return:
|
||||
"""
|
||||
self.stackedWidget.setCurrentWidget(self.view_userinfo)
|
||||
if self.sender() == self.toDocxAct:
|
||||
dialog = ExportDialog(self.contact, title='选择导出的消息类型', file_type='docx', parent=self)
|
||||
result = dialog.exec_() # 使用exec_()获取用户的操作结果
|
||||
elif self.sender() == self.toCSVAct:
|
||||
# self.outputThread = Output(self.contact, type_=Output.CSV)
|
||||
dialog = ExportDialog(self.contact, title='选择导出的消息类型', file_type='csv', parent=self)
|
||||
result = dialog.exec_() # 使用exec_()获取用户的操作结果
|
||||
elif self.sender() == self.toHtmlAct:
|
||||
dialog = ExportDialog(self.contact, title='选择导出的消息类型', file_type='html', parent=self)
|
||||
result = dialog.exec_() # 使用exec_()获取用户的操作结果
|
||||
elif self.sender() == self.toTxtAct:
|
||||
dialog = ExportDialog(self.contact, title='选择导出的消息类型', file_type='txt', parent=self)
|
||||
result = dialog.exec_() # 使用exec_()获取用户的操作结果
|
||||
elif self.sender() == self.toAiTxtAct:
|
||||
dialog = ExportDialog(self.contact, title='选择导出的消息类型', file_type='ai_txt', parent=self)
|
||||
result = dialog.exec_() # 使用exec_()获取用户的操作结果
|
||||
elif self.sender() == self.toJsonAct:
|
||||
dialog = ExportDialog(self.contact, title='选择导出的消息类型', file_type='json', parent=self)
|
||||
result = dialog.exec_() # 使用exec_()获取用户的操作结果
|
||||
|
||||
class ReportThread(QThread):
|
||||
okSignal = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, contact, time_range=None):
|
||||
super().__init__()
|
||||
self.contact = contact
|
||||
self.time_range = time_range
|
||||
|
||||
def run(self):
|
||||
from app.web_ui import web
|
||||
web.contact = self.contact
|
||||
web.time_range = self.time_range
|
||||
web.run(port='21314')
|
||||
self.okSignal.emit(True)
|
||||
98
app/ui/contact/contactInfoUi.py
Normal file
98
app/ui/contact/contactInfoUi.py
Normal file
@@ -0,0 +1,98 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'contactInfoUi.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_Form(object):
|
||||
def setupUi(self, Form):
|
||||
Form.setObjectName("Form")
|
||||
Form.resize(494, 748)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_3.setSpacing(0)
|
||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||
self.btn_analysis = QtWidgets.QPushButton(Form)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.btn_analysis.sizePolicy().hasHeightForWidth())
|
||||
self.btn_analysis.setSizePolicy(sizePolicy)
|
||||
self.btn_analysis.setStyleSheet("")
|
||||
self.btn_analysis.setFlat(False)
|
||||
self.btn_analysis.setObjectName("btn_analysis")
|
||||
self.horizontalLayout_3.addWidget(self.btn_analysis)
|
||||
self.btn_emotion = QtWidgets.QPushButton(Form)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.btn_emotion.sizePolicy().hasHeightForWidth())
|
||||
self.btn_emotion.setSizePolicy(sizePolicy)
|
||||
self.btn_emotion.setFlat(False)
|
||||
self.btn_emotion.setObjectName("btn_emotion")
|
||||
self.horizontalLayout_3.addWidget(self.btn_emotion)
|
||||
self.btn_report = QtWidgets.QPushButton(Form)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.btn_report.sizePolicy().hasHeightForWidth())
|
||||
self.btn_report.setSizePolicy(sizePolicy)
|
||||
self.btn_report.setFlat(False)
|
||||
self.btn_report.setObjectName("btn_report")
|
||||
self.horizontalLayout_3.addWidget(self.btn_report)
|
||||
self.btn_back = QtWidgets.QPushButton(Form)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.btn_back.sizePolicy().hasHeightForWidth())
|
||||
self.btn_back.setSizePolicy(sizePolicy)
|
||||
self.btn_back.setText("")
|
||||
self.btn_back.setFlat(False)
|
||||
self.btn_back.setObjectName("btn_back")
|
||||
self.horizontalLayout_3.addWidget(self.btn_back)
|
||||
self.toolButton_output = QtWidgets.QToolButton(Form)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.toolButton_output.sizePolicy().hasHeightForWidth())
|
||||
self.toolButton_output.setSizePolicy(sizePolicy)
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap("../../data/icons/output.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.toolButton_output.setIcon(icon)
|
||||
self.toolButton_output.setCheckable(False)
|
||||
self.toolButton_output.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup)
|
||||
self.toolButton_output.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
|
||||
self.toolButton_output.setAutoRaise(True)
|
||||
self.toolButton_output.setArrowType(QtCore.Qt.NoArrow)
|
||||
self.toolButton_output.setObjectName("toolButton_output")
|
||||
self.horizontalLayout_3.addWidget(self.toolButton_output)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_3)
|
||||
self.stackedWidget = QtWidgets.QStackedWidget(Form)
|
||||
self.stackedWidget.setObjectName("stackedWidget")
|
||||
self.page_3 = QtWidgets.QWidget()
|
||||
self.page_3.setObjectName("page_3")
|
||||
self.stackedWidget.addWidget(self.page_3)
|
||||
self.page_4 = QtWidgets.QWidget()
|
||||
self.page_4.setObjectName("page_4")
|
||||
self.stackedWidget.addWidget(self.page_4)
|
||||
self.verticalLayout.addWidget(self.stackedWidget)
|
||||
|
||||
self.retranslateUi(Form)
|
||||
self.stackedWidget.setCurrentIndex(1)
|
||||
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||
|
||||
def retranslateUi(self, Form):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Form.setWindowTitle(_translate("Form", "Form"))
|
||||
self.btn_analysis.setText(_translate("Form", "统计信息"))
|
||||
self.btn_emotion.setText(_translate("Form", "情感分析"))
|
||||
self.btn_report.setText(_translate("Form", "年度报告"))
|
||||
self.toolButton_output.setText(_translate("Form", "导出聊天记录"))
|
||||
66
app/ui/contact/contactUi.py
Normal file
66
app/ui/contact/contactUi.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'contactUi.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_Form(object):
|
||||
def setupUi(self, Form):
|
||||
Form.setObjectName("Form")
|
||||
Form.resize(840, 752)
|
||||
Form.setStyleSheet("background: rgb(240, 240, 240);")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(Form)
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout_2.setSpacing(6)
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.label = QtWidgets.QLabel(Form)
|
||||
self.label.setText("")
|
||||
self.label.setObjectName("label")
|
||||
self.horizontalLayout.addWidget(self.label)
|
||||
self.lineEdit = QtWidgets.QLineEdit(Form)
|
||||
self.lineEdit.setMinimumSize(QtCore.QSize(200, 30))
|
||||
self.lineEdit.setMaximumSize(QtCore.QSize(200, 16777215))
|
||||
self.lineEdit.setStyleSheet("")
|
||||
self.lineEdit.setCursorMoveStyle(QtCore.Qt.VisualMoveStyle)
|
||||
self.lineEdit.setObjectName("lineEdit")
|
||||
self.horizontalLayout.addWidget(self.lineEdit)
|
||||
self.label_2 = QtWidgets.QLabel(Form)
|
||||
self.label_2.setMinimumSize(QtCore.QSize(30, 0))
|
||||
self.label_2.setMaximumSize(QtCore.QSize(30, 16777215))
|
||||
self.label_2.setText("")
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.horizontalLayout.addWidget(self.label_2)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
self.verticalLayout_2.addLayout(self.verticalLayout)
|
||||
self.listWidget = QtWidgets.QListWidget(Form)
|
||||
self.listWidget.setMinimumSize(QtCore.QSize(250, 0))
|
||||
self.listWidget.setMaximumSize(QtCore.QSize(250, 16777215))
|
||||
self.listWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
self.listWidget.setObjectName("listWidget")
|
||||
self.verticalLayout_2.addWidget(self.listWidget)
|
||||
self.verticalLayout_2.setStretch(1, 1)
|
||||
self.horizontalLayout_2.addLayout(self.verticalLayout_2)
|
||||
self.stackedWidget = QtWidgets.QStackedWidget(Form)
|
||||
self.stackedWidget.setObjectName("stackedWidget")
|
||||
self.horizontalLayout_2.addWidget(self.stackedWidget)
|
||||
self.horizontalLayout_2.setStretch(1, 1)
|
||||
|
||||
self.retranslateUi(Form)
|
||||
self.stackedWidget.setCurrentIndex(-1)
|
||||
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||
|
||||
def retranslateUi(self, Form):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Form.setWindowTitle(_translate("Form", "Form"))
|
||||
196
app/ui/contact/contact_window.py
Normal file
196
app/ui/contact/contact_window.py
Normal file
@@ -0,0 +1,196 @@
|
||||
from typing import List
|
||||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from PyQt5.QtWidgets import QWidget, QMessageBox, QAction, QLineEdit, QLabel
|
||||
|
||||
from app.DataBase import micro_msg_db, misc_db, close_db
|
||||
from app.components import ContactQListWidgetItem, ScrollBar
|
||||
from app.person import Contact
|
||||
from app.ui.Icon import Icon
|
||||
from .contactInfo import ContactInfo
|
||||
from .contactUi import Ui_Form
|
||||
from ...DataBase.hard_link import decodeExtraBuf
|
||||
from ...util import search
|
||||
|
||||
# 美化样式表
|
||||
Stylesheet = """
|
||||
QPushButton{
|
||||
background-color: transparent;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: lightgray;
|
||||
}
|
||||
/*去掉item虚线边框*/
|
||||
QListWidget, QListView, QTreeWidget, QTreeView {
|
||||
outline: 0px;
|
||||
border:none;
|
||||
}
|
||||
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
|
||||
QListWidget {
|
||||
min-width: 250px;
|
||||
max-width: 250px;
|
||||
min-height: 80px;
|
||||
max-height: 1200px;
|
||||
color: black;
|
||||
border:none;
|
||||
}
|
||||
QListWidget::item{
|
||||
height:60px;
|
||||
width:250px;
|
||||
}
|
||||
/*被选中时的背景颜色和左边框颜色*/
|
||||
QListWidget::item:selected {
|
||||
background: rgb(230, 235, 240);
|
||||
border-left:none;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
/*鼠标悬停颜色*/
|
||||
HistoryPanel::item:hover {
|
||||
background: rgb(52, 52, 52);
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class ContactWindow(QWidget, Ui_Form):
|
||||
load_finish_signal = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.now_index = 0
|
||||
self.show_thread = None
|
||||
self.setupUi(self)
|
||||
self.ok_flag = False
|
||||
self.setStyleSheet(Stylesheet)
|
||||
self.init_ui()
|
||||
self.contacts = [[], []]
|
||||
self.contacts_list:List[Contact] = []
|
||||
self.show_contacts()
|
||||
self.contact_info_window = None
|
||||
|
||||
def init_ui(self):
|
||||
search_action = QAction(self.lineEdit)
|
||||
search_action.setIcon(Icon.Search_Icon)
|
||||
self.lineEdit.addAction(search_action, QLineEdit.LeadingPosition)
|
||||
self.lineEdit.returnPressed.connect(self.search_contact)
|
||||
self.listWidget.clear()
|
||||
self.listWidget.setVerticalScrollBar(ScrollBar())
|
||||
self.listWidget.currentRowChanged.connect(self.setCurrentIndex)
|
||||
self.listWidget.setCurrentRow(0)
|
||||
self.stackedWidget.setCurrentIndex(0)
|
||||
|
||||
def show_contacts(self):
|
||||
"""
|
||||
创建一个子线程来获取联系人并通过信号传递联系人信息
|
||||
@return:
|
||||
"""
|
||||
# return
|
||||
if self.ok_flag:
|
||||
return
|
||||
micro_msg_db.init_database()
|
||||
if not micro_msg_db.open_flag:
|
||||
QMessageBox.critical(self, "错误", "数据库不存在\n请先解密数据库")
|
||||
self.show_thread = ShowThread()
|
||||
self.show_thread.showSingal.connect(self.show_contact)
|
||||
self.show_thread.load_finish_signal.connect(self.load_finish_signal)
|
||||
self.show_thread.start()
|
||||
return
|
||||
|
||||
self.show_thread = ShowContactThread()
|
||||
self.show_thread.showSingal.connect(self.show_contact)
|
||||
self.show_thread.load_finish_signal.connect(self.load_finish_signal)
|
||||
self.show_thread.start()
|
||||
self.ok_flag = True
|
||||
|
||||
def search_contact(self):
|
||||
"""
|
||||
搜索联系人
|
||||
@return:
|
||||
"""
|
||||
keyword = self.lineEdit.text()
|
||||
if keyword:
|
||||
index = search.search_by_content(keyword, self.contacts)
|
||||
self.listWidget.setCurrentRow(index)
|
||||
self.stackedWidget.setCurrentIndex(index)
|
||||
|
||||
def show_contact(self, contact: Contact):
|
||||
"""
|
||||
显示联系人
|
||||
@param contact:联系人对象
|
||||
@return:
|
||||
"""
|
||||
# return
|
||||
self.contacts[0].append(contact.remark)
|
||||
self.contacts[1].append(contact.nickName)
|
||||
contact_item = ContactQListWidgetItem(contact.remark, contact.smallHeadImgUrl, contact.smallHeadImgBLOG)
|
||||
self.listWidget.addItem(contact_item)
|
||||
self.listWidget.setItemWidget(contact_item, contact_item.widget)
|
||||
self.contacts_list.append(contact)
|
||||
if self.contact_info_window is None:
|
||||
self.contact_info_window = ContactInfo(contact)
|
||||
self.stackedWidget.addWidget(self.contact_info_window)
|
||||
|
||||
def setCurrentIndex(self, row):
|
||||
# print(row)
|
||||
item = self.listWidget.item(self.now_index)
|
||||
item.dis_select()
|
||||
self.stackedWidget.setCurrentIndex(row)
|
||||
item = self.listWidget.item(row)
|
||||
item.select()
|
||||
self.now_index = row
|
||||
# self.stackedWidget.setCurrentIndex(row)
|
||||
self.contact_info_window.set_contact(self.contacts_list[row])
|
||||
|
||||
|
||||
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()
|
||||
if not contact_info_lists:
|
||||
self.load_finish_signal.emit(True)
|
||||
# QMessageBox.critical(None, "错误", "数据库错误,请重启电脑后重试")
|
||||
close_db()
|
||||
import shutil
|
||||
try:
|
||||
shutil.rmtree('./app/Database/Msg')
|
||||
except:
|
||||
pass
|
||||
return
|
||||
for contact_info_list in contact_info_lists:
|
||||
# UserName, Alias,Type,Remark,NickName,PYInitial,RemarkPYInitial,ContactHeadImgUrl.smallHeadImgUrl,ContactHeadImgUrl,bigHeadImgUrl,ExtraBuf
|
||||
detail = decodeExtraBuf(contact_info_list[9])
|
||||
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],
|
||||
'detail': detail,
|
||||
'label_name': contact_info_list[10],
|
||||
}
|
||||
contact = Contact(contact_info)
|
||||
contact.smallHeadImgBLOG = misc_db.get_avatar_buffer(contact.wxid)
|
||||
contact.set_avatar(contact.smallHeadImgBLOG)
|
||||
self.showSingal.emit(contact)
|
||||
# pprint(contact.__dict__)
|
||||
self.load_finish_signal.emit(True)
|
||||
|
||||
|
||||
class ShowThread(QThread):
|
||||
showSingal = pyqtSignal(Contact)
|
||||
load_finish_signal = pyqtSignal(bool)
|
||||
|
||||
# heightSingal = pyqtSignal(int)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def run(self) -> None:
|
||||
QThread.sleep(1)
|
||||
self.load_finish_signal.emit(True)
|
||||
0
app/ui/contact/export/__init__.py
Normal file
0
app/ui/contact/export/__init__.py
Normal file
112
app/ui/contact/export/exportUi.py
Normal file
112
app/ui/contact/export/exportUi.py
Normal file
@@ -0,0 +1,112 @@
|
||||
# -*- 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 = QtWidgets.QVBoxLayout(Dialog)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
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.addLayout(self.horizontalLayout)
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
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.horizontalLayout_2.setStretch(0, 1)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_2)
|
||||
self.textBrowser = QtWidgets.QTextBrowser(Dialog)
|
||||
self.textBrowser.setObjectName("textBrowser")
|
||||
self.verticalLayout.addWidget(self.textBrowser)
|
||||
self.progressBar = QtWidgets.QProgressBar(Dialog)
|
||||
self.progressBar.setProperty("value", 24)
|
||||
self.progressBar.setObjectName("progressBar")
|
||||
self.verticalLayout.addWidget(self.progressBar)
|
||||
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)
|
||||
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_3.addItem(spacerItem1)
|
||||
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.setObjectName("btn_start")
|
||||
self.horizontalLayout_3.addWidget(self.btn_start)
|
||||
self.btn_cancel = QtWidgets.QPushButton(Dialog)
|
||||
self.btn_cancel.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_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_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_2.setText(_translate("Dialog", "消息类型"))
|
||||
self.btn_start.setText(_translate("Dialog", "开始"))
|
||||
self.btn_cancel.setText(_translate("Dialog", "取消"))
|
||||
229
app/ui/contact/export/export_dialog.py
Normal file
229
app/ui/contact/export/export_dialog.py
Normal file
@@ -0,0 +1,229 @@
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
from PyQt5.QtCore import QTimer, QObject, pyqtSignal
|
||||
from PyQt5.QtGui import QTextCursor
|
||||
from PyQt5.QtWidgets import QApplication, QDialog, QCheckBox, QMessageBox
|
||||
|
||||
from app.DataBase import msg_db
|
||||
from app.components import ScrollBar
|
||||
from app.config import OUTPUT_DIR
|
||||
from app.ui.menu.export_time_range import TimeRangeDialog
|
||||
from .exportUi import Ui_Dialog
|
||||
from app.util.exporter.output import Output
|
||||
|
||||
types = {
|
||||
'文本': 1,
|
||||
'图片': 3,
|
||||
'语音': 34,
|
||||
'视频': 43,
|
||||
'表情包': 47,
|
||||
'音乐与音频': 4903,
|
||||
'文件': 4906,
|
||||
'分享卡片': 4905,
|
||||
'转账': 492000,
|
||||
'音视频通话': 50,
|
||||
'拍一拍等系统消息': 10000,
|
||||
}
|
||||
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="csv", parent=None):
|
||||
super(ExportDialog, self).__init__(parent)
|
||||
self.select_all_flag = False
|
||||
self.setupUi(self)
|
||||
self.setStyleSheet(Stylesheet)
|
||||
# 下面将输出重定向到textBrowser中
|
||||
sys.stdout = EmittingStr(textWritten=self.outputWritten)
|
||||
sys.stderr = EmittingStr(textWritten=self.outputWritten)
|
||||
scroll_bar = ScrollBar()
|
||||
self.textBrowser.setVerticalScrollBar(scroll_bar)
|
||||
self.contact = contact
|
||||
if file_type == 'html':
|
||||
self.export_type = Output.HTML
|
||||
self.export_choices = {"文本": True, "图片": True, "语音": False, "视频": False, "表情包": False,
|
||||
'音乐与音频': False, '分享卡片': False, '文件': False,
|
||||
'转账': False, '音视频通话': False, '拍一拍等系统消息': True} # 定义导出的数据类型,默认全部选择
|
||||
elif file_type == 'csv':
|
||||
self.export_type = Output.CSV
|
||||
self.export_choices = {"文本": True, "图片": True, "视频": True, "表情包": True} # 定义导出的数据类型,默认全部选择
|
||||
elif file_type == 'txt':
|
||||
self.export_type = Output.TXT
|
||||
self.export_choices = {"文本": True, "图片": True, "语音": True, "视频": True, "表情包": True,
|
||||
'音乐与音频': True, '分享卡片': True, '文件': True,
|
||||
'拍一拍等系统消息': True} # 定义导出的数据类型,默认全部选择
|
||||
elif file_type == 'ai_txt':
|
||||
self.export_type = Output.AI_TXT
|
||||
self.export_choices = {"文本": True} # 定义导出的数据类型,默认全部选择
|
||||
elif file_type == 'docx':
|
||||
self.export_type = Output.DOCX
|
||||
self.export_choices = {"文本": True, "图片": False, "语音": False, "视频": False,
|
||||
"表情包": False, '拍一拍等系统消息': True} # 定义导出的数据类型,默认全部选择
|
||||
elif file_type == 'json':
|
||||
self.export_type = Output.JSON
|
||||
self.export_choices = {} # 定义导出的数据类型,默认全部选择
|
||||
else:
|
||||
self.export_choices = {"文本": True, "图片": True, "视频": True, "表情包": True} # 定义导出的数据类型,默认全部选择
|
||||
self.setWindowTitle(title)
|
||||
self.resize(400, 300)
|
||||
self.worker = None # 导出线程
|
||||
|
||||
for export_type, default_state in self.export_choices.items():
|
||||
checkbox = QCheckBox(export_type)
|
||||
checkbox.setChecked(default_state)
|
||||
self.verticalLayout_2.addWidget(checkbox)
|
||||
|
||||
self.btn_select_all.clicked.connect(self.select_all)
|
||||
self.btn_start.clicked.connect(self.export_data)
|
||||
self.btn_cancel.clicked.connect(self.reject) # 使用reject关闭对话框
|
||||
self.comboBox_time.activated.connect(self.set_export_date)
|
||||
self.timer = QTimer(self)
|
||||
self.time = 0
|
||||
self.total_msg_num = 99999 # 总的消息个数
|
||||
self.num = 0 # 当前完成的消息个数
|
||||
self.timer.timeout.connect(self.update_elapsed_time)
|
||||
self.time_range = None
|
||||
|
||||
def export_data(self):
|
||||
self.btn_start.setEnabled(False)
|
||||
self.btn_cancel.setEnabled(False)
|
||||
# 在这里获取用户选择的导出数据类型
|
||||
selected_types = {types[export_type]: checkbox.isChecked() for export_type, checkbox in
|
||||
zip(self.export_choices.keys(), self.findChildren(QCheckBox))}
|
||||
|
||||
# 在这里根据用户选择的数据类型执行导出操作
|
||||
print("选择的数据类型:", selected_types)
|
||||
self.worker = Output(self.contact, type_=self.export_type, message_types=selected_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.start()
|
||||
# 启动定时器,每1000毫秒更新一次任务进度
|
||||
self.timer.start(1000)
|
||||
self.start_time = time.time()
|
||||
# self.accept() # 使用accept关闭对话框
|
||||
|
||||
def outputWritten(self, text):
|
||||
cursor = self.textBrowser.textCursor()
|
||||
cursor.movePosition(QTextCursor.End)
|
||||
cursor.insertText(text)
|
||||
self.textBrowser.setTextCursor(cursor)
|
||||
self.textBrowser.ensureCursorVisible()
|
||||
|
||||
def set_export_date(self):
|
||||
date_range = self.comboBox_time.currentText()
|
||||
if date_range == '全部时间':
|
||||
pass
|
||||
elif date_range == '最近三个月':
|
||||
|
||||
# 获取今天的日期和时间
|
||||
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 == '自定义时间':
|
||||
date_range = None
|
||||
chat_calendar = msg_db.get_messages_calendar(self.contact.wxid)
|
||||
if chat_calendar:
|
||||
start_time = datetime.strptime(chat_calendar[0], "%Y-%m-%d")
|
||||
end_time = datetime.strptime(chat_calendar[-1], "%Y-%m-%d")
|
||||
date_range = (start_time.date(), end_time.date())
|
||||
self.time_range_view = TimeRangeDialog(date_range=date_range, 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 set_total_msg_num(self, num):
|
||||
self.total_msg_num = num
|
||||
# b''+num +(1,1)
|
||||
|
||||
def export_finished(self):
|
||||
self.btn_start.setEnabled(True)
|
||||
self.btn_cancel.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 select_all(self):
|
||||
self.select_all_flag = not self.select_all_flag
|
||||
print('全选', self.select_all_flag)
|
||||
if self.select_all_flag:
|
||||
for checkbox in self.findChildren(QCheckBox):
|
||||
checkbox.setChecked(True)
|
||||
self.btn_select_all.setText('全不选')
|
||||
else:
|
||||
for checkbox in self.findChildren(QCheckBox):
|
||||
checkbox.setChecked(False)
|
||||
self.btn_select_all.setText('全选')
|
||||
|
||||
def update_elapsed_time(self):
|
||||
self.time += 1
|
||||
self.label_time.setText(f"耗时: {self.time}s")
|
||||
|
||||
def update_progress(self, progress_percentage):
|
||||
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}%")
|
||||
|
||||
def close(self):
|
||||
sys.stdout = sys.__stdout__
|
||||
del self.worker
|
||||
super().close()
|
||||
|
||||
|
||||
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_())
|
||||
9
app/ui/contact/userinfo/__init__.py
Normal file
9
app/ui/contact/userinfo/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@File : __init__.py.py
|
||||
@Author : Shuaikang Zhou
|
||||
@Time : 2022/12/24 10:34
|
||||
@IDE : Pycharm
|
||||
@Version : Python3.10
|
||||
@comment : ···
|
||||
"""
|
||||
62
app/ui/contact/userinfo/userinfo.py
Normal file
62
app/ui/contact/userinfo/userinfo.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
from app.person import Contact
|
||||
from app.util.region_conversion import conversion_region_to_chinese
|
||||
from .userinfoUi import Ui_Frame
|
||||
from ...Icon import Icon
|
||||
|
||||
|
||||
class UserinfoController(QWidget, Ui_Frame):
|
||||
def __init__(self, contact, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
self.l_remark.setText(contact.remark)
|
||||
self.l_avatar.setPixmap(contact.avatar)
|
||||
self.l_nickname.setText(f'昵称:{contact.nickName}')
|
||||
self.l_username.setText(f'微信号:{contact.alias}')
|
||||
self.lineEdit.setText(contact.remark)
|
||||
# self.l_region.setVisible(False)
|
||||
self.l_contact_label.setText(contact.label_name)
|
||||
if contact.detail:
|
||||
self.l_signature.setText(contact.detail.get('signature'))
|
||||
self.l_tel.setText(contact.detail.get('telephone'))
|
||||
region = contact.detail.get('region')
|
||||
area = conversion_region_to_chinese(region)
|
||||
self.l_region.setText(f'地区:{area}')
|
||||
gender_code = contact.detail.get('gender')
|
||||
gender = ''
|
||||
pixmap =QPixmap()
|
||||
if gender_code == 1:
|
||||
gender = '男'
|
||||
pixmap = QPixmap(Icon.Man_Icon_path)
|
||||
elif gender_code == 2:
|
||||
gender = '女'
|
||||
pixmap = QPixmap(Icon.Woman_Icon_path)
|
||||
self.l_gender.setPixmap(pixmap)
|
||||
# self.l_gender.setText()
|
||||
def set_contact(self,contact:Contact):
|
||||
self.l_remark.setText(contact.remark)
|
||||
self.l_avatar.setPixmap(contact.avatar)
|
||||
self.l_nickname.setText(f'昵称:{contact.nickName}')
|
||||
self.l_username.setText(f'微信号:{contact.alias}')
|
||||
self.lineEdit.setText(contact.remark)
|
||||
# self.l_region.setVisible(False)
|
||||
self.l_contact_label.setText(contact.label_name)
|
||||
if contact.detail:
|
||||
self.l_signature.setText(contact.detail.get('signature'))
|
||||
self.l_tel.setText(contact.detail.get('telephone'))
|
||||
region = contact.detail.get('region')
|
||||
area = conversion_region_to_chinese(region)
|
||||
self.l_region.setText(f'地区:{area}')
|
||||
gender_code = contact.detail.get('gender')
|
||||
gender = ''
|
||||
pixmap = QPixmap()
|
||||
if gender_code == 1:
|
||||
gender = '男'
|
||||
pixmap = QPixmap(Icon.Man_Icon_path)
|
||||
elif gender_code == 2:
|
||||
gender = '女'
|
||||
pixmap = QPixmap(Icon.Woman_Icon_path)
|
||||
self.l_gender.setPixmap(pixmap)
|
||||
# self.l_gender.setText()
|
||||
168
app/ui/contact/userinfo/userinfoUi.py
Normal file
168
app/ui/contact/userinfo/userinfoUi.py
Normal file
@@ -0,0 +1,168 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'userinfoUi.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_Frame(object):
|
||||
def setupUi(self, Frame):
|
||||
Frame.setObjectName("Frame")
|
||||
Frame.resize(624, 720)
|
||||
Frame.setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor))
|
||||
Frame.setMouseTracking(True)
|
||||
Frame.setTabletTracking(True)
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(Frame)
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
spacerItem = QtWidgets.QSpacerItem(162, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_2.addItem(spacerItem)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.verticalLayout.addItem(spacerItem1)
|
||||
self.gridLayout_2 = QtWidgets.QGridLayout()
|
||||
self.gridLayout_2.setVerticalSpacing(2)
|
||||
self.gridLayout_2.setObjectName("gridLayout_2")
|
||||
self.l_avatar = QtWidgets.QLabel(Frame)
|
||||
self.l_avatar.setMinimumSize(QtCore.QSize(80, 80))
|
||||
self.l_avatar.setMaximumSize(QtCore.QSize(80, 80))
|
||||
self.l_avatar.setText("")
|
||||
self.l_avatar.setPixmap(QtGui.QPixmap("../../../a_img/be0fa6c0c4707fb5f7b37b660de826d3.jpg"))
|
||||
self.l_avatar.setScaledContents(True)
|
||||
self.l_avatar.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.l_avatar.setObjectName("l_avatar")
|
||||
self.gridLayout_2.addWidget(self.l_avatar, 0, 0, 4, 1)
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.l_remark = QtWidgets.QLabel(Frame)
|
||||
self.l_remark.setMinimumSize(QtCore.QSize(0, 30))
|
||||
self.l_remark.setMaximumSize(QtCore.QSize(16777215, 30))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(15)
|
||||
self.l_remark.setFont(font)
|
||||
self.l_remark.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse)
|
||||
self.l_remark.setObjectName("l_remark")
|
||||
self.horizontalLayout.addWidget(self.l_remark)
|
||||
self.l_gender = QtWidgets.QLabel(Frame)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.l_gender.sizePolicy().hasHeightForWidth())
|
||||
self.l_gender.setSizePolicy(sizePolicy)
|
||||
self.l_gender.setText("")
|
||||
self.l_gender.setObjectName("l_gender")
|
||||
self.horizontalLayout.addWidget(self.l_gender)
|
||||
self.gridLayout_2.addLayout(self.horizontalLayout, 0, 1, 1, 1)
|
||||
self.l_nickname = QtWidgets.QLabel(Frame)
|
||||
self.l_nickname.setMinimumSize(QtCore.QSize(0, 20))
|
||||
self.l_nickname.setMaximumSize(QtCore.QSize(16777215, 16777215))
|
||||
self.l_nickname.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse)
|
||||
self.l_nickname.setObjectName("l_nickname")
|
||||
self.gridLayout_2.addWidget(self.l_nickname, 1, 1, 1, 1)
|
||||
self.l_username = QtWidgets.QLabel(Frame)
|
||||
self.l_username.setMinimumSize(QtCore.QSize(0, 20))
|
||||
self.l_username.setMaximumSize(QtCore.QSize(16777215, 16777215))
|
||||
self.l_username.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse)
|
||||
self.l_username.setObjectName("l_username")
|
||||
self.gridLayout_2.addWidget(self.l_username, 2, 1, 1, 1)
|
||||
self.l_region = QtWidgets.QLabel(Frame)
|
||||
self.l_region.setText("")
|
||||
self.l_region.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse)
|
||||
self.l_region.setObjectName("l_region")
|
||||
self.gridLayout_2.addWidget(self.l_region, 3, 1, 1, 1)
|
||||
self.verticalLayout.addLayout(self.gridLayout_2)
|
||||
spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.verticalLayout.addItem(spacerItem2)
|
||||
self.gridLayout = QtWidgets.QGridLayout()
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.label = QtWidgets.QLabel(Frame)
|
||||
self.label.setMinimumSize(QtCore.QSize(80, 0))
|
||||
self.label.setMaximumSize(QtCore.QSize(100, 16777215))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(15)
|
||||
self.label.setFont(font)
|
||||
self.label.setObjectName("label")
|
||||
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
|
||||
self.lineEdit = QtWidgets.QLineEdit(Frame)
|
||||
self.lineEdit.setMinimumSize(QtCore.QSize(0, 25))
|
||||
self.lineEdit.setMaximumSize(QtCore.QSize(16777215, 25))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(15)
|
||||
self.lineEdit.setFont(font)
|
||||
self.lineEdit.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
|
||||
self.lineEdit.setAutoFillBackground(False)
|
||||
self.lineEdit.setStyleSheet("\n"
|
||||
" background:transparent;border-width:0;border-style:outset\n"
|
||||
" ")
|
||||
self.lineEdit.setObjectName("lineEdit")
|
||||
self.gridLayout.addWidget(self.lineEdit, 0, 1, 1, 1)
|
||||
self.label_4 = QtWidgets.QLabel(Frame)
|
||||
self.label_4.setMinimumSize(QtCore.QSize(80, 0))
|
||||
self.label_4.setMaximumSize(QtCore.QSize(100, 16777215))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(15)
|
||||
self.label_4.setFont(font)
|
||||
self.label_4.setObjectName("label_4")
|
||||
self.gridLayout.addWidget(self.label_4, 1, 0, 1, 1)
|
||||
self.l_tel = QtWidgets.QLabel(Frame)
|
||||
self.l_tel.setText("")
|
||||
self.l_tel.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse)
|
||||
self.l_tel.setObjectName("l_tel")
|
||||
self.gridLayout.addWidget(self.l_tel, 1, 1, 1, 1)
|
||||
self.label_3 = QtWidgets.QLabel(Frame)
|
||||
self.label_3.setMinimumSize(QtCore.QSize(80, 0))
|
||||
self.label_3.setMaximumSize(QtCore.QSize(100, 16777215))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(15)
|
||||
self.label_3.setFont(font)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1)
|
||||
self.l_contact_label = QtWidgets.QLabel(Frame)
|
||||
self.l_contact_label.setText("")
|
||||
self.l_contact_label.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse)
|
||||
self.l_contact_label.setObjectName("l_contact_label")
|
||||
self.gridLayout.addWidget(self.l_contact_label, 2, 1, 1, 1)
|
||||
self.label_2 = QtWidgets.QLabel(Frame)
|
||||
self.label_2.setMinimumSize(QtCore.QSize(0, 0))
|
||||
self.label_2.setMaximumSize(QtCore.QSize(100, 16777215))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(15)
|
||||
self.label_2.setFont(font)
|
||||
self.label_2.setWordWrap(False)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.gridLayout.addWidget(self.label_2, 3, 0, 1, 1)
|
||||
self.l_signature = QtWidgets.QLabel(Frame)
|
||||
self.l_signature.setMinimumSize(QtCore.QSize(300, 0))
|
||||
self.l_signature.setMaximumSize(QtCore.QSize(300, 100))
|
||||
self.l_signature.setText("")
|
||||
self.l_signature.setWordWrap(True)
|
||||
self.l_signature.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse)
|
||||
self.l_signature.setObjectName("l_signature")
|
||||
self.gridLayout.addWidget(self.l_signature, 3, 1, 1, 1)
|
||||
self.verticalLayout.addLayout(self.gridLayout)
|
||||
spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.verticalLayout.addItem(spacerItem3)
|
||||
self.horizontalLayout_2.addLayout(self.verticalLayout)
|
||||
spacerItem4 = QtWidgets.QSpacerItem(162, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_2.addItem(spacerItem4)
|
||||
|
||||
self.retranslateUi(Frame)
|
||||
QtCore.QMetaObject.connectSlotsByName(Frame)
|
||||
|
||||
def retranslateUi(self, Frame):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Frame.setWindowTitle(_translate("Frame", "Frame"))
|
||||
self.l_remark.setText(_translate("Frame", "曹雨萱"))
|
||||
self.l_nickname.setText(_translate("Frame", "昵称:997"))
|
||||
self.l_username.setText(_translate("Frame", "账号:TextLabel"))
|
||||
self.label.setText(_translate("Frame", "备注名"))
|
||||
self.lineEdit.setText(_translate("Frame", "曹雨萱"))
|
||||
self.label_4.setText(_translate("Frame", "电话"))
|
||||
self.label_3.setText(_translate("Frame", "标签"))
|
||||
self.label_2.setText(_translate("Frame", "个性签名"))
|
||||
0
app/ui/home/__init__.py
Normal file
0
app/ui/home/__init__.py
Normal file
79
app/ui/home/home_window.py
Normal file
79
app/ui/home/home_window.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, QThread, QUrl
|
||||
from PyQt5.QtGui import QFont, QDesktopServices
|
||||
from PyQt5.QtWidgets import QWidget, QMessageBox
|
||||
|
||||
from app.ui.Icon import Icon
|
||||
|
||||
from .home_windowUi import Ui_Dialog
|
||||
from ...person import Me
|
||||
|
||||
Stylesheet = """
|
||||
QPushButton{
|
||||
border-radius: 5px;
|
||||
padding: 8px;
|
||||
border-right: 2px solid #888888; /* 按钮边框,2px宽,白色 */
|
||||
border-bottom: 2px solid #888888; /* 按钮边框,2px宽,白色 */
|
||||
border-left: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */
|
||||
border-top: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: lightgray;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class HomeWindow(QWidget, Ui_Dialog):
|
||||
load_finish_signal = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
self.init_ui()
|
||||
self.setStyleSheet(Stylesheet)
|
||||
self.load_finish_signal.emit(True)
|
||||
self.btn_report.clicked.connect(self.report)
|
||||
self.btn_save.clicked.connect(self.save_info)
|
||||
|
||||
def init_ui(self):
|
||||
self.label_wxid.setText(Me().wxid)
|
||||
self.lineEdit_name.setText(Me().name)
|
||||
self.lineEdit_phone.setText(Me().mobile)
|
||||
|
||||
def save_info(self):
|
||||
if self.lineEdit_name.text():
|
||||
Me().name = self.lineEdit_name.text()
|
||||
else:
|
||||
QMessageBox.critical(self, "错误",
|
||||
"昵称不能为空")
|
||||
return
|
||||
if self.lineEdit_phone.text():
|
||||
Me().mobile = self.lineEdit_phone.text()
|
||||
else:
|
||||
QMessageBox.critical(self, "错误",
|
||||
"手机号不能为空")
|
||||
return
|
||||
Me().save_info()
|
||||
QMessageBox.information(self, "修改成功",
|
||||
"个人信息修改成功")
|
||||
|
||||
def report(self):
|
||||
time_range = ['2023-01-01 00:00:00', '2024-02-10 00:00:00']
|
||||
self.report_thread = ReportThread(Me(), time_range)
|
||||
self.report_thread.start()
|
||||
QDesktopServices.openUrl(QUrl(f"http://127.0.0.1:21314/"))
|
||||
|
||||
|
||||
class ReportThread(QThread):
|
||||
okSignal = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, contact, time_range=None):
|
||||
super().__init__()
|
||||
self.contact = contact
|
||||
self.time_range = time_range
|
||||
|
||||
def run(self):
|
||||
from app.web_ui import web
|
||||
web.contact = self.contact
|
||||
web.time_range = self.time_range
|
||||
web.run(port='21314')
|
||||
self.okSignal.emit(True)
|
||||
109
app/ui/home/home_windowUi.py
Normal file
109
app/ui/home/home_windowUi.py
Normal file
@@ -0,0 +1,109 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'home_windowUi.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(590, 547)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("微软雅黑")
|
||||
Dialog.setFont(font)
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout(Dialog)
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
spacerItem = QtWidgets.QSpacerItem(20, 157, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.verticalLayout_2.addItem(spacerItem)
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout.addItem(spacerItem1)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.btn_report = QtWidgets.QPushButton(Dialog)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("微软雅黑")
|
||||
font.setPointSize(30)
|
||||
self.btn_report.setFont(font)
|
||||
self.btn_report.setObjectName("btn_report")
|
||||
self.verticalLayout.addWidget(self.btn_report)
|
||||
self.label = QtWidgets.QLabel(Dialog)
|
||||
self.label.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.label.setObjectName("label")
|
||||
self.verticalLayout.addWidget(self.label)
|
||||
self.gridLayout = QtWidgets.QGridLayout()
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.label_4 = QtWidgets.QLabel(Dialog)
|
||||
self.label_4.setObjectName("label_4")
|
||||
self.gridLayout.addWidget(self.label_4, 0, 0, 1, 1)
|
||||
self.lineEdit_phone = QtWidgets.QLineEdit(Dialog)
|
||||
self.lineEdit_phone.setStyleSheet("background:transparent;\n"
|
||||
"\n"
|
||||
" border-radius:5px;\n"
|
||||
" border-top: 0px solid #b2e281;\n"
|
||||
" border-bottom: 2px solid black;\n"
|
||||
" border-right: 0px solid #b2e281;\n"
|
||||
" border-left: 0px solid #b2e281;\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" border-style:outset\n"
|
||||
" ")
|
||||
self.lineEdit_phone.setFrame(False)
|
||||
self.lineEdit_phone.setObjectName("lineEdit_phone")
|
||||
self.gridLayout.addWidget(self.lineEdit_phone, 0, 1, 1, 1)
|
||||
self.lineEdit_name = QtWidgets.QLineEdit(Dialog)
|
||||
self.lineEdit_name.setStyleSheet("background:transparent;\n"
|
||||
"\n"
|
||||
" border-radius:5px;\n"
|
||||
" border-top: 0px solid #b2e281;\n"
|
||||
" border-bottom: 2px solid black;\n"
|
||||
" border-right: 0px solid #b2e281;\n"
|
||||
" border-left: 0px solid #b2e281;\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" border-style:outset\n"
|
||||
" ")
|
||||
self.lineEdit_name.setFrame(False)
|
||||
self.lineEdit_name.setObjectName("lineEdit_name")
|
||||
self.gridLayout.addWidget(self.lineEdit_name, 1, 1, 1, 1)
|
||||
self.label_wxid = QtWidgets.QLabel(Dialog)
|
||||
self.label_wxid.setText("")
|
||||
self.label_wxid.setObjectName("label_wxid")
|
||||
self.gridLayout.addWidget(self.label_wxid, 2, 1, 1, 1)
|
||||
self.label_5 = QtWidgets.QLabel(Dialog)
|
||||
self.label_5.setObjectName("label_5")
|
||||
self.gridLayout.addWidget(self.label_5, 1, 0, 1, 1)
|
||||
self.label_6 = QtWidgets.QLabel(Dialog)
|
||||
self.label_6.setObjectName("label_6")
|
||||
self.gridLayout.addWidget(self.label_6, 2, 0, 1, 1)
|
||||
self.verticalLayout.addLayout(self.gridLayout)
|
||||
self.btn_save = QtWidgets.QPushButton(Dialog)
|
||||
self.btn_save.setObjectName("btn_save")
|
||||
self.verticalLayout.addWidget(self.btn_save)
|
||||
self.horizontalLayout.addLayout(self.verticalLayout)
|
||||
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout.addItem(spacerItem2)
|
||||
self.verticalLayout_2.addLayout(self.horizontalLayout)
|
||||
spacerItem3 = QtWidgets.QSpacerItem(20, 157, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.verticalLayout_2.addItem(spacerItem3)
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||
self.btn_report.setText(_translate("Dialog", "我的年度聊天报告"))
|
||||
self.label.setText(_translate("Dialog", "修改个人信息"))
|
||||
self.label_4.setText(_translate("Dialog", "手机号"))
|
||||
self.label_5.setText(_translate("Dialog", "微信昵称"))
|
||||
self.label_6.setText(_translate("Dialog", "wxid"))
|
||||
self.btn_save.setText(_translate("Dialog", "保存"))
|
||||
524
app/ui/mainview.py
Normal file
524
app/ui/mainview.py
Normal file
@@ -0,0 +1,524 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@File : mainview.py
|
||||
@Author : Shuaikang Zhou
|
||||
@Time : 2022/12/13 15:07
|
||||
@IDE : Pycharm
|
||||
@Version : Python3.10
|
||||
@comment : 主窗口
|
||||
"""
|
||||
import json
|
||||
import os.path
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import requests
|
||||
from PyQt5.QtCore import pyqtSignal, QThread, QSize, QUrl, Qt
|
||||
from PyQt5.QtGui import QPixmap, QIcon, QDesktopServices
|
||||
from PyQt5.QtWidgets import QMainWindow, QLabel, QMessageBox, QPushButton
|
||||
|
||||
from app.DataBase import misc_db, micro_msg_db, close_db
|
||||
from app.ui.Icon import Icon
|
||||
from . import mainwindow
|
||||
# 不能删,删了会出错
|
||||
from app.ui.chat import ChatWindow
|
||||
from app.ui.contact import ContactWindow
|
||||
from app.ui.tool.tool_window import ToolWindow
|
||||
from app.ui.home.home_window import HomeWindow
|
||||
from .menu.export import ExportDialog
|
||||
from app.util.exporter.output import Output
|
||||
from ..components.QCursorGif import QCursorGif
|
||||
from ..config import INFO_FILE_PATH, DB_DIR, SERVER_API_URL, version
|
||||
from ..log import logger
|
||||
from ..person import Me
|
||||
|
||||
try:
|
||||
from app.ui.menu.about_dialog import AboutDialog
|
||||
except ModuleNotFoundError:
|
||||
logger.error(f'Python版本错误:Python>=3.10,仅支持3.10、3.11、3.12')
|
||||
raise ValueError('Python版本错误:Python>=3.10,仅支持3.10、3.11、3.12')
|
||||
# 美化样式表
|
||||
Stylesheet = """
|
||||
QMessageBox QPushButton{
|
||||
background-color: rgb(250,252,253);
|
||||
border-radius: 5px;
|
||||
padding: 8px;
|
||||
border-right: 2px solid #888888; /* 按钮边框,2px宽,白色 */
|
||||
border-bottom: 2px solid #888888; /* 按钮边框,2px宽,白色 */
|
||||
border-left: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */
|
||||
border-top: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */
|
||||
}
|
||||
QPushButton{
|
||||
background-color: rgb(238,244,249);
|
||||
border-radius: 5px;
|
||||
padding: 8px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: lightgray;
|
||||
}
|
||||
QWidget{
|
||||
background: rgb(238,244,249);
|
||||
}
|
||||
/*去掉item虚线边框*/
|
||||
QListWidget, QListView, QTreeWidget, QTreeView {
|
||||
outline: 0px;
|
||||
}
|
||||
|
||||
QMenu::item:selected {
|
||||
color: black;
|
||||
background: rgb(230, 235, 240);
|
||||
}
|
||||
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
|
||||
QListWidget {
|
||||
min-width: 120px;
|
||||
max-width: 380px;
|
||||
color: black;
|
||||
border:none;
|
||||
}
|
||||
QListWidget::item{
|
||||
min-width: 80px;
|
||||
max-width: 380px;
|
||||
min-height: 60px;
|
||||
max-height: 60px;
|
||||
}
|
||||
QListWidget::item:hover {
|
||||
background: rgb(230, 235, 240);
|
||||
}
|
||||
/*被选中时的背景颜色和左边框颜色*/
|
||||
QListWidget::item:selected {
|
||||
background: rgb(230, 235, 240);
|
||||
border-left: 2px solid rgb(62, 62, 62);
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
/*鼠标悬停颜色*/
|
||||
HistoryPanel::item:hover {
|
||||
background: rgb(52, 52, 52);
|
||||
}
|
||||
|
||||
QCheckBox::indicator {
|
||||
background: rgb(255, 255, 255);
|
||||
Width:20px;
|
||||
Height:20px;
|
||||
border-radius: 10px
|
||||
}
|
||||
QCheckBox::indicator:unchecked{
|
||||
Width:20px;
|
||||
Height:20px;
|
||||
image: url(:/icons/icons/unselect.svg);
|
||||
}
|
||||
QCheckBox::indicator:checked{
|
||||
Width:20px;
|
||||
Height:20px;
|
||||
image: url(:/icons/icons/select.svg);
|
||||
}
|
||||
QScrollBar:vertical {
|
||||
border-width: 0px;
|
||||
border: none;
|
||||
background:rgba(133, 135, 138, 0);
|
||||
width:4px;
|
||||
margin: 0px 0px 0px 0px;
|
||||
}
|
||||
QScrollBar::handle:vertical {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||
stop: 0 rgb(133, 135, 138), stop: 0.5 rgb(133, 135, 138), stop:1 rgb(133, 135, 138));
|
||||
min-height: 20px;
|
||||
max-height: 20px;
|
||||
margin: 0 0px 0 0px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
QScrollBar::add-line:vertical {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||
stop: 0 rgba(133, 135, 138, 0), stop: 0.5 rgba(133, 135, 138, 0), stop:1 rgba(133, 135, 138, 0));
|
||||
height: 0px;
|
||||
border: none;
|
||||
subcontrol-position: bottom;
|
||||
subcontrol-origin: margin;
|
||||
}
|
||||
QScrollBar::sub-line:vertical {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||
stop: 0 rgba(133, 135, 138, 0), stop: 0.5 rgba(133, 135, 138, 0), stop:1 rgba(133, 135, 138, 0));
|
||||
height: 0 px;
|
||||
border: none;
|
||||
subcontrol-position: top;
|
||||
subcontrol-origin: margin;
|
||||
}
|
||||
QScrollBar::sub-page:vertical {
|
||||
background: rgba(133, 135, 138, 0);
|
||||
}
|
||||
|
||||
QScrollBar::add-page:vertical {
|
||||
background: rgba(133, 135, 138, 0);
|
||||
}
|
||||
QProgressBar{
|
||||
height:22px;
|
||||
text-align:center;
|
||||
font-size:14px;
|
||||
color:black;
|
||||
border-radius:11px;
|
||||
background:#EBEEF5;
|
||||
}
|
||||
QProgressBar::chunk{
|
||||
border-radius:11px;
|
||||
background:qlineargradient(spread:pad,x1:0,y1:0,x2:1,y2:0,stop:0 #99ffff,stop:1 #9900ff);
|
||||
}
|
||||
QComboBox
|
||||
{
|
||||
border-radius:3px;
|
||||
border:0px ;
|
||||
padding-top: 2px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
QComboBox:disabled
|
||||
{
|
||||
background-color:rgba(50,50,50,200);
|
||||
color:rgb(160,160,160);
|
||||
}
|
||||
QComboBox:hover
|
||||
{
|
||||
background-color:rgba(230,230,230,200);
|
||||
border:1px solid rgb(31,156,220) ;
|
||||
}
|
||||
/*下拉箭头的边框*/
|
||||
QComboBox::drop-down
|
||||
{
|
||||
border:none;
|
||||
}
|
||||
|
||||
/*下拉箭头样式*/
|
||||
QComboBox::down-arrow
|
||||
{
|
||||
right:0px;/*控制箭头左右偏移*/
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
image: url(:/icons/icons/down.svg);
|
||||
}
|
||||
/*下拉箭头点击样式*/
|
||||
QComboBox::down-arrow:on
|
||||
{
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
image: url(:/icons/icons/up.svg);
|
||||
}
|
||||
QLineEdit
|
||||
{
|
||||
background:transparent;
|
||||
border-radius:10px;
|
||||
border-top: 0px solid #b2e281;
|
||||
border-bottom: 1px solid rgb(227,228,222);
|
||||
border-right: 1px solid rgb(227,228,222);
|
||||
border-left: 0px solid #b2e281;
|
||||
border-style:outset;
|
||||
background-color:rgb(247,248,252);
|
||||
}
|
||||
QLineEdit:hover
|
||||
{
|
||||
background-color:rgb(238,241,248);
|
||||
}
|
||||
"""
|
||||
|
||||
'''
|
||||
|
||||
|
||||
/*点击combox的样式*/
|
||||
QComboBox:on
|
||||
{
|
||||
border-radius:3px;
|
||||
background-color:rgba(35,35,35);
|
||||
font: 75 9pt "Microsoft YaHei";
|
||||
color:rgb(255,255,255);
|
||||
border:1px solid rgb(31,156,220) ;
|
||||
}
|
||||
/*下拉框的样式*/
|
||||
QComboBox QAbstractItemView
|
||||
{
|
||||
outline: 0px solid gray; /*取消选中虚线*/
|
||||
border: 1px solid rgb(31,156,220);
|
||||
font: 75 9pt "Microsoft YaHei";
|
||||
color: rgb(255,255,255);
|
||||
background-color: rgb(45,45,45);
|
||||
selection-background-color: rgb(90,90,90);
|
||||
}
|
||||
/*选中每一项高度*/
|
||||
QComboBox QAbstractItemView::item
|
||||
{
|
||||
height: 25px;
|
||||
}
|
||||
/*选中每一项的字体颜色和背景颜色*/
|
||||
QComboBox QAbstractItemView::item:selected
|
||||
{
|
||||
color: rgb(31,163,246);
|
||||
background-color: rgb(90,90,90);
|
||||
}
|
||||
|
||||
'''
|
||||
|
||||
|
||||
class Avatar(QLabel):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
def mouseDoubleClickEvent(self, e): # 双击
|
||||
super().mouseDoubleClickEvent()
|
||||
QDesktopServices.openUrl(QUrl("https://blog.lc044.love/post/7"))
|
||||
|
||||
def mousePressEvent(self, e): # 单击
|
||||
super().mousePressEvent(e)
|
||||
QDesktopServices.openUrl(QUrl("https://blog.lc044.love/post/7"))
|
||||
|
||||
|
||||
class MainWinController(QMainWindow, mainwindow.Ui_MainWindow, QCursorGif):
|
||||
exitSignal = pyqtSignal(bool)
|
||||
okSignal = pyqtSignal(bool)
|
||||
|
||||
# username = ''
|
||||
def __init__(self, username, parent=None):
|
||||
super(MainWinController, self).__init__(parent)
|
||||
self.outputThread0 = None
|
||||
self.outputThread = None
|
||||
self.setupUi(self)
|
||||
# self.myavatar = Avatar(self)
|
||||
# self.setWindowIcon(Icon.MainWindow_Icon)
|
||||
pixmap = QPixmap(Icon.logo_ico_path)
|
||||
icon = QIcon(pixmap)
|
||||
self.setWindowIcon(icon)
|
||||
self.setStyleSheet(Stylesheet)
|
||||
self.listWidget.clear()
|
||||
self.resize(QSize(800, 600))
|
||||
self.info = QLabel(self)
|
||||
self.info.setText('Tips ')
|
||||
self.info.setAlignment(Qt.AlignRight)
|
||||
self.statusbar.addPermanentWidget(self.info)
|
||||
self.statusbar.showMessage('遇到问题可添加QQ群咨询', 5000)
|
||||
self.load_flag = False
|
||||
self.load_data()
|
||||
self.load_num = 0
|
||||
self.label = QLabel(self)
|
||||
self.label.setGeometry((self.width() - 300) // 2, (self.height() - 100) // 2, 300, 100)
|
||||
self.label.setPixmap(QPixmap(':/icons/icons/loading.svg'))
|
||||
self.menu_output.setIcon(Icon.Output)
|
||||
self.action_output_CSV.setIcon(Icon.ToCSV)
|
||||
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_update.setIcon(Icon.Update_Icon)
|
||||
|
||||
def load_data(self, flag=True):
|
||||
if os.path.exists(INFO_FILE_PATH):
|
||||
with open(INFO_FILE_PATH, 'r', encoding='utf-8') as f:
|
||||
dic = json.loads(f.read())
|
||||
wxid = dic.get('wxid')
|
||||
if wxid:
|
||||
me = Me()
|
||||
me.wxid = dic.get('wxid')
|
||||
me.name = dic.get('name')
|
||||
me.nickName = dic.get('name')
|
||||
me.remark = dic.get('name')
|
||||
me.mobile = dic.get('mobile')
|
||||
me.wx_dir = dic.get('wx_dir')
|
||||
me.token = dic.get('token')
|
||||
self.set_my_info(wxid)
|
||||
self.load_flag = True
|
||||
else:
|
||||
pass
|
||||
|
||||
def init_ui(self):
|
||||
# 设置忙碌光标图片数组
|
||||
self.initCursor([':/icons/icons/Cursors/%d.png' %
|
||||
i for i in range(8)])
|
||||
self.setCursorTimeout(100)
|
||||
self.startBusy()
|
||||
self.action_update.triggered.connect(self.update)
|
||||
self.action_help_faq.triggered.connect(
|
||||
lambda: QDesktopServices.openUrl(QUrl("https://memotrace.cn/doc/posts/error/")))
|
||||
self.about_view = AboutDialog(main_window=self, parent=self)
|
||||
self.update_thread = UpdateThread(check_time=True)
|
||||
self.update_thread.updateSignal.connect(self.show_update)
|
||||
self.update_thread.start()
|
||||
|
||||
def setCurrentIndex(self, row):
|
||||
self.stackedWidget.setCurrentIndex(row)
|
||||
if row == 2:
|
||||
self.stackedWidget.currentWidget().show_contacts()
|
||||
if row == 1:
|
||||
self.stackedWidget.currentWidget().show_chats()
|
||||
|
||||
def setWindow(self, window):
|
||||
try:
|
||||
window.load_finish_signal.connect(self.loading)
|
||||
except:
|
||||
pass
|
||||
self.stackedWidget.addWidget(window)
|
||||
|
||||
def set_my_info(self, wxid):
|
||||
self.avatar = QPixmap()
|
||||
img_bytes = misc_db.get_avatar_buffer(wxid)
|
||||
if not img_bytes:
|
||||
return
|
||||
if img_bytes[:4] == b'\x89PNG':
|
||||
self.avatar.loadFromData(img_bytes, format='PNG')
|
||||
else:
|
||||
self.avatar.loadFromData(img_bytes, format='jfif')
|
||||
self.avatar.scaled(60, 60)
|
||||
contact_info_list = micro_msg_db.get_contact_by_username(wxid)
|
||||
if not contact_info_list:
|
||||
close_db()
|
||||
import shutil
|
||||
try:
|
||||
shutil.rmtree(DB_DIR)
|
||||
except:
|
||||
pass
|
||||
QMessageBox.critical(self, "数据库错误", "数据库错误,请删除app文件夹后重启电脑再运行软件")
|
||||
return
|
||||
me = Me()
|
||||
me.set_avatar(img_bytes)
|
||||
me.smallHeadImgUrl = contact_info_list[7]
|
||||
self.myavatar.setScaledContents(True)
|
||||
self.myavatar.setPixmap(self.avatar)
|
||||
|
||||
def stop_loading(self, a0):
|
||||
self.label.setVisible(False)
|
||||
self.stopBusy()
|
||||
|
||||
def loading(self, a0):
|
||||
self.load_num += 1
|
||||
if self.load_num == 1:
|
||||
self.label.clear()
|
||||
self.label.hide()
|
||||
self.okSignal.emit(True)
|
||||
self.listWidget.setVisible(True)
|
||||
self.stackedWidget.setVisible(True)
|
||||
self.stopBusy()
|
||||
if self.load_flag:
|
||||
self.listWidget.setCurrentRow(1)
|
||||
self.stackedWidget.setCurrentIndex(1)
|
||||
else:
|
||||
self.listWidget.setCurrentRow(0)
|
||||
self.stackedWidget.setCurrentIndex(0)
|
||||
|
||||
def output(self):
|
||||
# self.startBusy()
|
||||
if self.sender() == self.action_output_CSV:
|
||||
self.outputThread = Output(None, type_=Output.CSV_ALL)
|
||||
self.outputThread.startSignal.connect(lambda x: self.startBusy())
|
||||
self.outputThread.okSignal.connect(
|
||||
lambda x: self.message('聊天记录导出成功'))
|
||||
self.outputThread.start()
|
||||
elif self.sender() == self.action_output_contacts:
|
||||
self.outputThread = Output(None, type_=Output.CONTACT_CSV)
|
||||
self.outputThread.startSignal.connect(lambda x: self.startBusy())
|
||||
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()
|
||||
QMessageBox.about(self, "提醒", msg)
|
||||
|
||||
def update(self):
|
||||
self.update_thread = UpdateThread()
|
||||
self.update_thread.updateSignal.connect(self.show_update)
|
||||
self.update_thread.start()
|
||||
|
||||
def show_update(self, update_info):
|
||||
if not update_info.get('update_available'):
|
||||
QMessageBox.information(self, '更新通知', "当前已是最新版本")
|
||||
return
|
||||
detail = f'''
|
||||
当前版本:{version},最新版本:{update_info.get('latest_version')}<br>
|
||||
更新内容:
|
||||
{update_info.get('description')}
|
||||
<br><a href='https://memotrace.cn/'>查看详情</a>
|
||||
'''
|
||||
|
||||
# 创建一个 QMessageBox 对象
|
||||
error_box = QMessageBox()
|
||||
|
||||
# 设置对话框的标题
|
||||
error_box.setWindowTitle("更新通知")
|
||||
pixmap = QPixmap(Icon.logo_ico_path)
|
||||
icon = QIcon(pixmap)
|
||||
error_box.setWindowIcon(icon)
|
||||
# 设置对话框的文本消息
|
||||
error_box.setText(detail)
|
||||
# 设置对话框的图标,使用 QMessageBox.Critical 作为图标类型
|
||||
error_box.setIcon(QMessageBox.Information)
|
||||
# 添加一个“确定”按钮
|
||||
# 添加自定义按钮
|
||||
custom_button = error_box.addButton('更新', QMessageBox.ActionRole)
|
||||
is_update_online = update_info.get('is_update_online')
|
||||
custom_button.clicked.connect(lambda x: self.update_(update_info.get('download_url'), is_update_online))
|
||||
error_box.addButton(QMessageBox.Cancel)
|
||||
# 显示对话框
|
||||
error_box.exec_()
|
||||
|
||||
def update_(self, url, is_update_online):
|
||||
QDesktopServices.openUrl(QUrl("https://memotrace.cn/"))
|
||||
|
||||
def about(self):
|
||||
"""
|
||||
关于
|
||||
"""
|
||||
self.about_view.show()
|
||||
|
||||
def decrypt_success(self):
|
||||
QMessageBox.about(self, "解密成功", "请重新启动")
|
||||
self.close()
|
||||
|
||||
def closeEvent(self, event):
|
||||
close_db()
|
||||
|
||||
def close(self) -> bool:
|
||||
close_db()
|
||||
self.contact_window.close()
|
||||
|
||||
super().close()
|
||||
self.exitSignal.emit(True)
|
||||
|
||||
|
||||
class UpdateThread(QThread):
|
||||
updateSignal = pyqtSignal(dict)
|
||||
|
||||
def __init__(self, check_time=False):
|
||||
super().__init__()
|
||||
self.check_time = check_time
|
||||
|
||||
def run(self):
|
||||
now_time = time.time()
|
||||
try:
|
||||
with open(INFO_FILE_PATH, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
update_time = data.get('update_time')
|
||||
if update_time:
|
||||
if now_time - update_time < 14400 and self.check_time:
|
||||
return
|
||||
except:
|
||||
os.makedirs(os.path.dirname(INFO_FILE_PATH), exist_ok=True)
|
||||
data = {
|
||||
'update_time': now_time
|
||||
}
|
||||
data['update_time'] = now_time
|
||||
|
||||
with open(INFO_FILE_PATH, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=4)
|
||||
server_url = urljoin(SERVER_API_URL, 'update')
|
||||
data = {'version': version}
|
||||
try:
|
||||
response = requests.post(server_url, json=data)
|
||||
if response.status_code == 200:
|
||||
update_info = response.json()
|
||||
self.updateSignal.emit(update_info)
|
||||
else:
|
||||
print("检查更新失败")
|
||||
except:
|
||||
update_info = {'update_available': False}
|
||||
self.updateSignal.emit(update_info)
|
||||
191
app/ui/mainwindow.py
Normal file
191
app/ui/mainwindow.py
Normal file
@@ -0,0 +1,191 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'mainwindow.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_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
MainWindow.setObjectName("MainWindow")
|
||||
MainWindow.resize(605, 565)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("微软雅黑")
|
||||
font.setPointSize(12)
|
||||
font.setBold(False)
|
||||
font.setWeight(50)
|
||||
MainWindow.setFont(font)
|
||||
MainWindow.setMouseTracking(True)
|
||||
MainWindow.setStyleSheet("")
|
||||
MainWindow.setIconSize(QtCore.QSize(50, 24))
|
||||
MainWindow.setDockOptions(QtWidgets.QMainWindow.AllowTabbedDocks|QtWidgets.QMainWindow.AnimatedDocks)
|
||||
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
||||
self.centralwidget.setMouseTracking(True)
|
||||
self.centralwidget.setObjectName("centralwidget")
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
|
||||
self.horizontalLayout.setContentsMargins(10, 0, 0, 0)
|
||||
self.horizontalLayout.setSpacing(0)
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.frame_info = QtWidgets.QFrame(self.centralwidget)
|
||||
self.frame_info.setMinimumSize(QtCore.QSize(80, 500))
|
||||
self.frame_info.setMaximumSize(QtCore.QSize(16777215, 16777215))
|
||||
self.frame_info.setStyleSheet("")
|
||||
self.frame_info.setFrameShape(QtWidgets.QFrame.NoFrame)
|
||||
self.frame_info.setFrameShadow(QtWidgets.QFrame.Plain)
|
||||
self.frame_info.setLineWidth(5)
|
||||
self.frame_info.setObjectName("frame_info")
|
||||
self.myavatar = QtWidgets.QLabel(self.frame_info)
|
||||
self.myavatar.setGeometry(QtCore.QRect(10, 40, 60, 60))
|
||||
self.myavatar.setObjectName("myavatar")
|
||||
self.listWidget = QtWidgets.QListWidget(self.frame_info)
|
||||
self.listWidget.setGeometry(QtCore.QRect(0, 230, 120, 331))
|
||||
self.listWidget.setMinimumSize(QtCore.QSize(0, 0))
|
||||
self.listWidget.setMaximumSize(QtCore.QSize(16777215, 16777215))
|
||||
self.listWidget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
self.listWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
self.listWidget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored)
|
||||
self.listWidget.setObjectName("listWidget")
|
||||
item = QtWidgets.QListWidgetItem()
|
||||
self.listWidget.addItem(item)
|
||||
item = QtWidgets.QListWidgetItem()
|
||||
self.listWidget.addItem(item)
|
||||
item = QtWidgets.QListWidgetItem()
|
||||
self.listWidget.addItem(item)
|
||||
item = QtWidgets.QListWidgetItem()
|
||||
self.listWidget.addItem(item)
|
||||
item = QtWidgets.QListWidgetItem()
|
||||
self.listWidget.addItem(item)
|
||||
self.horizontalLayout.addWidget(self.frame_info)
|
||||
self.stackedWidget = QtWidgets.QStackedWidget(self.centralwidget)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Microsoft YaHei UI")
|
||||
font.setPointSize(15)
|
||||
font.setBold(False)
|
||||
font.setWeight(50)
|
||||
self.stackedWidget.setFont(font)
|
||||
self.stackedWidget.setObjectName("stackedWidget")
|
||||
self.horizontalLayout.addWidget(self.stackedWidget)
|
||||
MainWindow.setCentralWidget(self.centralwidget)
|
||||
self.menubar = QtWidgets.QMenuBar(MainWindow)
|
||||
self.menubar.setGeometry(QtCore.QRect(0, 0, 605, 33))
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("微软雅黑")
|
||||
font.setPointSize(12)
|
||||
font.setBold(False)
|
||||
font.setWeight(50)
|
||||
self.menubar.setFont(font)
|
||||
self.menubar.setObjectName("menubar")
|
||||
self.menu_F = QtWidgets.QMenu(self.menubar)
|
||||
self.menu_F.setObjectName("menu_F")
|
||||
self.menu_data = QtWidgets.QMenu(self.menubar)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("微软雅黑")
|
||||
font.setPointSize(12)
|
||||
font.setBold(False)
|
||||
font.setWeight(50)
|
||||
self.menu_data.setFont(font)
|
||||
self.menu_data.setObjectName("menu_data")
|
||||
self.menu_output = QtWidgets.QMenu(self.menu_data)
|
||||
self.menu_output.setObjectName("menu_output")
|
||||
self.menu_2 = QtWidgets.QMenu(self.menubar)
|
||||
self.menu_2.setObjectName("menu_2")
|
||||
self.menu_about = QtWidgets.QMenu(self.menubar)
|
||||
self.menu_about.setObjectName("menu_about")
|
||||
MainWindow.setMenuBar(self.menubar)
|
||||
self.statusbar = QtWidgets.QStatusBar(MainWindow)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("微软雅黑")
|
||||
font.setPointSize(12)
|
||||
font.setBold(False)
|
||||
font.setWeight(50)
|
||||
self.statusbar.setFont(font)
|
||||
self.statusbar.setObjectName("statusbar")
|
||||
MainWindow.setStatusBar(self.statusbar)
|
||||
self.action_3 = QtWidgets.QAction(MainWindow)
|
||||
self.action_3.setObjectName("action_3")
|
||||
self.action_4 = QtWidgets.QAction(MainWindow)
|
||||
self.action_4.setObjectName("action_4")
|
||||
self.action_help_decrypt = QtWidgets.QAction(MainWindow)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Microsoft YaHei UI")
|
||||
self.action_help_decrypt.setFont(font)
|
||||
self.action_help_decrypt.setObjectName("action_help_decrypt")
|
||||
self.action_desc = QtWidgets.QAction(MainWindow)
|
||||
self.action_desc.setObjectName("action_desc")
|
||||
self.action_help_chat = QtWidgets.QAction(MainWindow)
|
||||
self.action_help_chat.setObjectName("action_help_chat")
|
||||
self.action_help_contact = QtWidgets.QAction(MainWindow)
|
||||
self.action_help_contact.setObjectName("action_help_contact")
|
||||
self.action_output_CSV = QtWidgets.QAction(MainWindow)
|
||||
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.action_update = QtWidgets.QAction(MainWindow)
|
||||
self.action_update.setObjectName("action_update")
|
||||
self.action_help_faq = QtWidgets.QAction(MainWindow)
|
||||
self.action_help_faq.setObjectName("action_help_faq")
|
||||
self.menu_F.addSeparator()
|
||||
self.menu_F.addSeparator()
|
||||
self.menu_F.addAction(self.action_3)
|
||||
self.menu_F.addAction(self.action_4)
|
||||
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_faq)
|
||||
self.menu_2.addSeparator()
|
||||
self.menu_2.addAction(self.action_help_decrypt)
|
||||
self.menu_2.addAction(self.action_help_chat)
|
||||
self.menu_2.addAction(self.action_help_contact)
|
||||
self.menu_about.addAction(self.action_update)
|
||||
self.menu_about.addSeparator()
|
||||
self.menu_about.addAction(self.action_desc)
|
||||
self.menubar.addAction(self.menu_F.menuAction())
|
||||
self.menubar.addAction(self.menu_data.menuAction())
|
||||
self.menubar.addAction(self.menu_2.menuAction())
|
||||
self.menubar.addAction(self.menu_about.menuAction())
|
||||
|
||||
self.retranslateUi(MainWindow)
|
||||
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||
|
||||
def retranslateUi(self, MainWindow):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
|
||||
self.myavatar.setText(_translate("MainWindow", "avatar"))
|
||||
__sortingEnabled = self.listWidget.isSortingEnabled()
|
||||
self.listWidget.setSortingEnabled(False)
|
||||
item = self.listWidget.item(0)
|
||||
item.setText(_translate("MainWindow", "新建项目"))
|
||||
item = self.listWidget.item(1)
|
||||
item.setText(_translate("MainWindow", "新建项目"))
|
||||
item = self.listWidget.item(2)
|
||||
item.setText(_translate("MainWindow", "新建项目"))
|
||||
item = self.listWidget.item(3)
|
||||
item.setText(_translate("MainWindow", "新建项目"))
|
||||
item = self.listWidget.item(4)
|
||||
item.setText(_translate("MainWindow", "新建项目"))
|
||||
self.listWidget.setSortingEnabled(__sortingEnabled)
|
||||
self.menu_F.setTitle(_translate("MainWindow", "文件(F)"))
|
||||
self.menu_data.setTitle(_translate("MainWindow", "数据"))
|
||||
self.menu_output.setTitle(_translate("MainWindow", "导出聊天记录(全部)"))
|
||||
self.menu_2.setTitle(_translate("MainWindow", "帮助"))
|
||||
self.menu_about.setTitle(_translate("MainWindow", "关于"))
|
||||
self.action_3.setText(_translate("MainWindow", "保存"))
|
||||
self.action_4.setText(_translate("MainWindow", "退出"))
|
||||
self.action_help_decrypt.setText(_translate("MainWindow", "解密教程"))
|
||||
self.action_desc.setText(_translate("MainWindow", "关于软件"))
|
||||
self.action_help_chat.setText(_translate("MainWindow", "聊天相关"))
|
||||
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", "批量导出"))
|
||||
self.action_update.setText(_translate("MainWindow", "检查更新"))
|
||||
self.action_help_faq.setText(_translate("MainWindow", "常见问题解答"))
|
||||
0
app/ui/menu/__init__.py
Normal file
0
app/ui/menu/__init__.py
Normal file
BIN
app/ui/menu/about_dialog.cp310-win_amd64.pyd
Normal file
BIN
app/ui/menu/about_dialog.cp310-win_amd64.pyd
Normal file
Binary file not shown.
BIN
app/ui/menu/about_dialog.cp311-win_amd64.pyd
Normal file
BIN
app/ui/menu/about_dialog.cp311-win_amd64.pyd
Normal file
Binary file not shown.
BIN
app/ui/menu/about_dialog.cp312-win_amd64.pyd
Normal file
BIN
app/ui/menu/about_dialog.cp312-win_amd64.pyd
Normal file
Binary file not shown.
61
app/ui/menu/dialog.py
Normal file
61
app/ui/menu/dialog.py
Normal 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
288
app/ui/menu/export.py
Normal 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
166
app/ui/menu/exportUi.py
Normal 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", "开始"))
|
||||
109
app/ui/menu/export_time_range.py
Normal file
109
app/ui/menu/export_time_range.py
Normal 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
73
app/ui/menu/time_range.py
Normal 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", "取消"))
|
||||
1
app/ui/tool/__init__.py
Normal file
1
app/ui/tool/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
206
app/ui/tool/get_bias_addr/getBiasAddrUi.py
Normal file
206
app/ui/tool/get_bias_addr/getBiasAddrUi.py
Normal file
@@ -0,0 +1,206 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'getBiasAddrUi.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_Form(object):
|
||||
def setupUi(self, Form):
|
||||
Form.setObjectName("Form")
|
||||
Form.resize(650, 580)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.scrollArea = QtWidgets.QScrollArea(Form)
|
||||
self.scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame)
|
||||
self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
|
||||
self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
self.scrollArea.setWidgetResizable(True)
|
||||
self.scrollArea.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
|
||||
self.scrollArea.setObjectName("scrollArea")
|
||||
self.scrollAreaWidgetContents = QtWidgets.QWidget()
|
||||
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 632, 562))
|
||||
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
|
||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents)
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
self.label_4 = QtWidgets.QLabel(self.scrollAreaWidgetContents)
|
||||
self.label_4.setMaximumSize(QtCore.QSize(16777215, 20))
|
||||
self.label_4.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.label_4.setObjectName("label_4")
|
||||
self.verticalLayout_3.addWidget(self.label_4)
|
||||
self.widget = QtWidgets.QWidget(self.scrollAreaWidgetContents)
|
||||
self.widget.setStyleSheet("QWidget{\n"
|
||||
" background-color:rgb(251,251,251);\n"
|
||||
" border-radius: 10px;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"QPushButton{\n"
|
||||
" background-color: rgb(250,252,253);\n"
|
||||
" border-radius: 5px;\n"
|
||||
" padding: 8px;\n"
|
||||
" border-right: 2px solid #888888; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-bottom: 2px solid #888888; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-left: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-top: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */\n"
|
||||
"}\n"
|
||||
"QPushButton:hover { \n"
|
||||
" background-color: lightgray;\n"
|
||||
"}")
|
||||
self.widget.setObjectName("widget")
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget)
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.label = QtWidgets.QLabel(self.widget)
|
||||
self.label.setMinimumSize(QtCore.QSize(80, 0))
|
||||
self.label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label.setObjectName("label")
|
||||
self.horizontalLayout.addWidget(self.label)
|
||||
self.lineEdit_tel = QtWidgets.QLineEdit(self.widget)
|
||||
self.lineEdit_tel.setObjectName("lineEdit_tel")
|
||||
self.horizontalLayout.addWidget(self.lineEdit_tel)
|
||||
self.verticalLayout_3.addWidget(self.widget)
|
||||
self.widget_3 = QtWidgets.QWidget(self.scrollAreaWidgetContents)
|
||||
self.widget_3.setStyleSheet("QWidget{\n"
|
||||
" background-color:rgb(251,251,251);\n"
|
||||
" border-radius: 10px;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"QPushButton{\n"
|
||||
" background-color: rgb(250,252,253);\n"
|
||||
" border-radius: 5px;\n"
|
||||
" padding: 8px;\n"
|
||||
" border-right: 2px solid #888888; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-bottom: 2px solid #888888; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-left: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-top: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */\n"
|
||||
"}\n"
|
||||
"QPushButton:hover { \n"
|
||||
" background-color: lightgray;\n"
|
||||
"}")
|
||||
self.widget_3.setObjectName("widget_3")
|
||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.widget_3)
|
||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||
self.label_2 = QtWidgets.QLabel(self.widget_3)
|
||||
self.label_2.setMinimumSize(QtCore.QSize(80, 0))
|
||||
self.label_2.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.horizontalLayout_3.addWidget(self.label_2)
|
||||
self.lineEdit_wx_alias = QtWidgets.QLineEdit(self.widget_3)
|
||||
self.lineEdit_wx_alias.setObjectName("lineEdit_wx_alias")
|
||||
self.horizontalLayout_3.addWidget(self.lineEdit_wx_alias)
|
||||
self.verticalLayout_3.addWidget(self.widget_3)
|
||||
self.widget_4 = QtWidgets.QWidget(self.scrollAreaWidgetContents)
|
||||
self.widget_4.setStyleSheet("QWidget{\n"
|
||||
" background-color:rgb(251,251,251);\n"
|
||||
" border-radius: 10px;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"QPushButton{\n"
|
||||
" background-color: rgb(250,252,253);\n"
|
||||
" border-radius: 5px;\n"
|
||||
" padding: 8px;\n"
|
||||
" border-right: 2px solid #888888; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-bottom: 2px solid #888888; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-left: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-top: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */\n"
|
||||
"}\n"
|
||||
"QPushButton:hover { \n"
|
||||
" background-color: lightgray;\n"
|
||||
"}")
|
||||
self.widget_4.setObjectName("widget_4")
|
||||
self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.widget_4)
|
||||
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
|
||||
self.label_3 = QtWidgets.QLabel(self.widget_4)
|
||||
self.label_3.setMinimumSize(QtCore.QSize(80, 0))
|
||||
self.label_3.setLayoutDirection(QtCore.Qt.LeftToRight)
|
||||
self.label_3.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.horizontalLayout_4.addWidget(self.label_3)
|
||||
self.lineEdit_wx_name = QtWidgets.QLineEdit(self.widget_4)
|
||||
self.lineEdit_wx_name.setObjectName("lineEdit_wx_name")
|
||||
self.horizontalLayout_4.addWidget(self.lineEdit_wx_name)
|
||||
self.verticalLayout_3.addWidget(self.widget_4)
|
||||
self.btn_get_bias_addr = QtWidgets.QPushButton(self.scrollAreaWidgetContents)
|
||||
self.btn_get_bias_addr.setObjectName("btn_get_bias_addr")
|
||||
self.verticalLayout_3.addWidget(self.btn_get_bias_addr)
|
||||
self.widget_2 = QtWidgets.QWidget(self.scrollAreaWidgetContents)
|
||||
self.widget_2.setStyleSheet("QWidget{\n"
|
||||
" background-color:rgb(251,251,251);\n"
|
||||
" border-radius: 10px;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"QPushButton{\n"
|
||||
" background-color: rgb(250,252,253);\n"
|
||||
" border-radius: 5px;\n"
|
||||
" padding: 8px;\n"
|
||||
" border-right: 2px solid #888888; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-bottom: 2px solid #888888; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-left: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-top: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */\n"
|
||||
"}\n"
|
||||
"QPushButton:hover { \n"
|
||||
" background-color: lightgray;\n"
|
||||
"}")
|
||||
self.widget_2.setObjectName("widget_2")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.widget_2)
|
||||
self.horizontalLayout_2.setContentsMargins(9, -1, -1, -1)
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.commandLinkButton = QtWidgets.QCommandLinkButton(self.widget_2)
|
||||
self.commandLinkButton.setEnabled(True)
|
||||
self.commandLinkButton.setTabletTracking(False)
|
||||
self.commandLinkButton.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
self.commandLinkButton.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)
|
||||
self.commandLinkButton.setToolTipDuration(-1)
|
||||
self.commandLinkButton.setLayoutDirection(QtCore.Qt.LeftToRight)
|
||||
self.commandLinkButton.setAutoFillBackground(False)
|
||||
self.commandLinkButton.setCheckable(False)
|
||||
self.commandLinkButton.setChecked(False)
|
||||
self.commandLinkButton.setAutoRepeat(False)
|
||||
self.commandLinkButton.setAutoExclusive(False)
|
||||
self.commandLinkButton.setAutoDefault(False)
|
||||
self.commandLinkButton.setDefault(False)
|
||||
self.commandLinkButton.setObjectName("commandLinkButton")
|
||||
self.horizontalLayout_2.addWidget(self.commandLinkButton)
|
||||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_2.addItem(spacerItem)
|
||||
self.label_error_log = QtWidgets.QLabel(self.widget_2)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.label_error_log.sizePolicy().hasHeightForWidth())
|
||||
self.label_error_log.setSizePolicy(sizePolicy)
|
||||
self.label_error_log.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label_error_log.setObjectName("label_error_log")
|
||||
self.horizontalLayout_2.addWidget(self.label_error_log)
|
||||
self.checkBox_send_error_log = QtWidgets.QCheckBox(self.widget_2)
|
||||
self.checkBox_send_error_log.setText("")
|
||||
self.checkBox_send_error_log.setIconSize(QtCore.QSize(64, 64))
|
||||
self.checkBox_send_error_log.setChecked(True)
|
||||
self.checkBox_send_error_log.setObjectName("checkBox_send_error_log")
|
||||
self.horizontalLayout_2.addWidget(self.checkBox_send_error_log)
|
||||
self.verticalLayout_3.addWidget(self.widget_2)
|
||||
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
|
||||
self.verticalLayout.addWidget(self.scrollArea)
|
||||
|
||||
self.retranslateUi(Form)
|
||||
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||
|
||||
def retranslateUi(self, Form):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Form.setWindowTitle(_translate("Form", "Form"))
|
||||
self.label_4.setText(_translate("Form", "为避免输入错误,下面信息请从微信里复制"))
|
||||
self.label.setText(_translate("Form", "手机号:"))
|
||||
self.lineEdit_tel.setPlaceholderText(_translate("Form", "填入微信绑定的手机号"))
|
||||
self.label_2.setText(_translate("Form", "微信号:"))
|
||||
self.lineEdit_wx_alias.setPlaceholderText(_translate("Form", "填入您的微信号"))
|
||||
self.label_3.setText(_translate("Form", "微信昵称:"))
|
||||
self.lineEdit_wx_name.setPlaceholderText(_translate("Form", "填入您的微信昵称"))
|
||||
self.btn_get_bias_addr.setText(_translate("Form", "获取信息"))
|
||||
self.commandLinkButton.setText(_translate("Form", "收集版本信息"))
|
||||
self.commandLinkButton.setDescription(_translate("Form", "需要收集微信版本信息以支持更多用户"))
|
||||
self.label_error_log.setText(_translate("Form", "开"))
|
||||
146
app/ui/tool/get_bias_addr/get_bias_addr.py
Normal file
146
app/ui/tool/get_bias_addr/get_bias_addr.py
Normal file
@@ -0,0 +1,146 @@
|
||||
import json
|
||||
import os.path
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import requests
|
||||
from PyQt5.QtCore import pyqtSignal, QThread
|
||||
from PyQt5.QtWidgets import QWidget, QMessageBox
|
||||
|
||||
from app.components.QCursorGif import QCursorGif
|
||||
from app.config import SERVER_API_URL
|
||||
from app.decrypt.get_bias_addr import BiasAddr
|
||||
from .getBiasAddrUi import Ui_Form
|
||||
|
||||
Stylesheet = """
|
||||
QPushButton{
|
||||
background-color: rgb(250,252,253);
|
||||
border-radius: 5px;
|
||||
padding: 8px;
|
||||
border-right: 2px solid #888888; /* 按钮边框,2px宽,白色 */
|
||||
border-bottom: 2px solid #888888; /* 按钮边框,2px宽,白色 */
|
||||
border-left: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */
|
||||
border-top: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: lightgray;
|
||||
}
|
||||
/*去掉item虚线边框*/
|
||||
QListWidget, QListView, QTreeWidget, QTreeView {
|
||||
outline: 0px;
|
||||
border:none;
|
||||
}
|
||||
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
|
||||
QListWidget {
|
||||
min-width: 400px;
|
||||
max-width: 400px;
|
||||
min-height: 80px;
|
||||
max-height: 80px;
|
||||
color: black;
|
||||
border:none;
|
||||
}
|
||||
QListWidget::item{
|
||||
min-width: 80px;
|
||||
max-width: 400px;
|
||||
min-height: 80px;
|
||||
max-height: 80px;
|
||||
}
|
||||
/*被选中时的背景颜色和左边框颜色*/
|
||||
QListWidget::item:selected {
|
||||
border-left:none;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
QCheckBox::indicator {
|
||||
background: rgb(251, 251, 251);
|
||||
Width:60px;
|
||||
Height:60px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
QCheckBox::indicator:unchecked{
|
||||
Width:60px;
|
||||
Height:60px;
|
||||
image: url(:/icons/icons/按钮_关闭.svg);
|
||||
}
|
||||
QCheckBox::indicator:checked{
|
||||
Width:60px;
|
||||
Height:60px;
|
||||
image: url(:/icons/icons/按钮_开启.svg);
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class GetBiasAddrControl(QWidget, Ui_Form, QCursorGif):
|
||||
biasAddrSignal = pyqtSignal(dict)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(GetBiasAddrControl, self).__init__(parent)
|
||||
self.thread = None
|
||||
self.setStyleSheet(Stylesheet)
|
||||
self.setupUi(self)
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
self.initCursor([':/icons/icons/Cursors/%d.png' %
|
||||
i for i in range(8)], self)
|
||||
self.setCursorTimeout(100)
|
||||
self.btn_get_bias_addr.clicked.connect(self.get_bias_addr)
|
||||
self.commandLinkButton.clicked.connect(self.show_info)
|
||||
self.checkBox_send_error_log.clicked.connect(self.set_error_log)
|
||||
|
||||
def set_error_log(self):
|
||||
if self.checkBox_send_error_log.isChecked():
|
||||
self.label_error_log.setText('开')
|
||||
else:
|
||||
self.label_error_log.setText('关')
|
||||
|
||||
def show_info(self):
|
||||
QMessageBox.information(self, "收集版本信息",
|
||||
"为了适配更多版本,需要收集微信的版本信息,该操作不会上传包括手机号、微信号、昵称等在内的任何信息\n示例数据:\n\"3.9.9.27\": [68065304, 0, 68065112, 0, 68066576]"
|
||||
)
|
||||
|
||||
def upload(self, version_data):
|
||||
url = urljoin(SERVER_API_URL, 'wxBiasAddr')
|
||||
try:
|
||||
requests.post(url, json={'bias_dict': version_data})
|
||||
print('版本信息上传成功')
|
||||
except:
|
||||
pass
|
||||
|
||||
def get_bias_addr(self):
|
||||
account = self.lineEdit_wx_alias.text()
|
||||
mobile = self.lineEdit_tel.text()
|
||||
name = self.lineEdit_wx_name.text()
|
||||
if not all([account, mobile, name]):
|
||||
QMessageBox.critical(self, "错误",
|
||||
"请把所有信息填写完整")
|
||||
return
|
||||
key = None
|
||||
db_path = "test"
|
||||
self.startBusy()
|
||||
self.thread = MyThread(account, mobile, name, key, db_path)
|
||||
self.thread.signal.connect(self.set_bias_addr)
|
||||
self.thread.start()
|
||||
|
||||
def set_bias_addr(self, data):
|
||||
if self.checkBox_send_error_log.isChecked():
|
||||
self.upload(data)
|
||||
self.stopBusy()
|
||||
self.biasAddrSignal.emit(data)
|
||||
|
||||
|
||||
class MyThread(QThread):
|
||||
signal = pyqtSignal(dict)
|
||||
|
||||
def __init__(self, account, mobile, name, key, db_path):
|
||||
super(MyThread, self).__init__()
|
||||
self.account = account
|
||||
self.mobile = mobile
|
||||
self.name = name
|
||||
self.key = key
|
||||
self.db_path = db_path
|
||||
|
||||
def run(self):
|
||||
bias_addr = BiasAddr(self.account, self.mobile, self.name, self.key, self.db_path)
|
||||
data = bias_addr.run(logging_path=True)
|
||||
self.signal.emit(data)
|
||||
3
app/ui/tool/pc_decrypt/__init__.py
Normal file
3
app/ui/tool/pc_decrypt/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .pc_decrypt import DecryptControl
|
||||
|
||||
__all__ = ['DecryptControl']
|
||||
206
app/ui/tool/pc_decrypt/decryptUi.py
Normal file
206
app/ui/tool/pc_decrypt/decryptUi.py
Normal file
@@ -0,0 +1,206 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'decryptUi.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(611, 519)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("微软雅黑")
|
||||
font.setPointSize(12)
|
||||
Dialog.setFont(font)
|
||||
Dialog.setLayoutDirection(QtCore.Qt.LeftToRight)
|
||||
Dialog.setStyleSheet("QPushButton {\n"
|
||||
" background: rgb(238,244,249);\n"
|
||||
"}\n"
|
||||
"QPushButton:hover{\n"
|
||||
" background: rgb(230, 235, 240);\n"
|
||||
"}")
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout(Dialog)
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
spacerItem = QtWidgets.QSpacerItem(20, 79, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.verticalLayout_2.addItem(spacerItem)
|
||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||
spacerItem1 = QtWidgets.QSpacerItem(78, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_3.addItem(spacerItem1)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
|
||||
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_4.addItem(spacerItem2)
|
||||
self.btn_help = QtWidgets.QPushButton(Dialog)
|
||||
self.btn_help.setMinimumSize(QtCore.QSize(0, 40))
|
||||
self.btn_help.setMaximumSize(QtCore.QSize(200, 16777215))
|
||||
self.btn_help.setStyleSheet("")
|
||||
self.btn_help.setObjectName("btn_help")
|
||||
self.horizontalLayout_4.addWidget(self.btn_help)
|
||||
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_4.addItem(spacerItem3)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_4)
|
||||
self.label_3 = QtWidgets.QLabel(Dialog)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("一纸情书")
|
||||
font.setPointSize(20)
|
||||
self.label_3.setFont(font)
|
||||
self.label_3.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.verticalLayout.addWidget(self.label_3)
|
||||
self.label_9 = QtWidgets.QLabel(Dialog)
|
||||
self.label_9.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.label_9.setObjectName("label_9")
|
||||
self.verticalLayout.addWidget(self.label_9)
|
||||
self.gridLayout = QtWidgets.QGridLayout()
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.label = QtWidgets.QLabel(Dialog)
|
||||
self.label.setObjectName("label")
|
||||
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
|
||||
self.label_pid = QtWidgets.QLabel(Dialog)
|
||||
self.label_pid.setText("")
|
||||
self.label_pid.setObjectName("label_pid")
|
||||
self.gridLayout.addWidget(self.label_pid, 0, 1, 1, 1)
|
||||
self.label_7 = QtWidgets.QLabel(Dialog)
|
||||
self.label_7.setObjectName("label_7")
|
||||
self.gridLayout.addWidget(self.label_7, 1, 0, 1, 1)
|
||||
self.label_version = QtWidgets.QLabel(Dialog)
|
||||
self.label_version.setText("")
|
||||
self.label_version.setObjectName("label_version")
|
||||
self.gridLayout.addWidget(self.label_version, 1, 1, 1, 1)
|
||||
self.btn_getinfo = QtWidgets.QPushButton(Dialog)
|
||||
self.btn_getinfo.setMinimumSize(QtCore.QSize(0, 40))
|
||||
self.btn_getinfo.setObjectName("btn_getinfo")
|
||||
self.gridLayout.addWidget(self.btn_getinfo, 1, 2, 2, 1)
|
||||
self.checkBox = QtWidgets.QCheckBox(Dialog)
|
||||
self.checkBox.setText("")
|
||||
self.checkBox.setCheckable(False)
|
||||
self.checkBox.setObjectName("checkBox")
|
||||
self.gridLayout.addWidget(self.checkBox, 1, 3, 2, 1)
|
||||
self.label_2 = QtWidgets.QLabel(Dialog)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1)
|
||||
self.lineEdit_phone = QtWidgets.QLineEdit(Dialog)
|
||||
self.lineEdit_phone.setStyleSheet("background:transparent;\n"
|
||||
"\n"
|
||||
" border-radius:5px;\n"
|
||||
" border-top: 0px solid #b2e281;\n"
|
||||
" border-bottom: 2px solid black;\n"
|
||||
" border-right: 0px solid #b2e281;\n"
|
||||
" border-left: 0px solid #b2e281;\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" border-style:outset\n"
|
||||
" ")
|
||||
self.lineEdit_phone.setFrame(False)
|
||||
self.lineEdit_phone.setObjectName("lineEdit_phone")
|
||||
self.gridLayout.addWidget(self.lineEdit_phone, 2, 1, 1, 1)
|
||||
self.label_5 = QtWidgets.QLabel(Dialog)
|
||||
self.label_5.setObjectName("label_5")
|
||||
self.gridLayout.addWidget(self.label_5, 3, 0, 1, 1)
|
||||
self.lineEdit_name = QtWidgets.QLineEdit(Dialog)
|
||||
self.lineEdit_name.setStyleSheet("background:transparent;\n"
|
||||
"\n"
|
||||
" border-radius:5px;\n"
|
||||
" border-top: 0px solid #b2e281;\n"
|
||||
" border-bottom: 2px solid black;\n"
|
||||
" border-right: 0px solid #b2e281;\n"
|
||||
" border-left: 0px solid #b2e281;\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" border-style:outset\n"
|
||||
" ")
|
||||
self.lineEdit_name.setFrame(False)
|
||||
self.lineEdit_name.setObjectName("lineEdit_name")
|
||||
self.gridLayout.addWidget(self.lineEdit_name, 3, 1, 1, 1)
|
||||
self.label_4 = QtWidgets.QLabel(Dialog)
|
||||
self.label_4.setObjectName("label_4")
|
||||
self.gridLayout.addWidget(self.label_4, 4, 0, 1, 1)
|
||||
self.label_wxid = QtWidgets.QLabel(Dialog)
|
||||
self.label_wxid.setText("")
|
||||
self.label_wxid.setObjectName("label_wxid")
|
||||
self.gridLayout.addWidget(self.label_wxid, 4, 1, 1, 1)
|
||||
self.btn_db_dir = QtWidgets.QPushButton(Dialog)
|
||||
self.btn_db_dir.setMinimumSize(QtCore.QSize(0, 40))
|
||||
self.btn_db_dir.setObjectName("btn_db_dir")
|
||||
self.gridLayout.addWidget(self.btn_db_dir, 4, 2, 3, 1)
|
||||
self.label_6 = QtWidgets.QLabel(Dialog)
|
||||
self.label_6.setObjectName("label_6")
|
||||
self.gridLayout.addWidget(self.label_6, 5, 0, 1, 1)
|
||||
self.label_key = QtWidgets.QLabel(Dialog)
|
||||
self.label_key.setMaximumSize(QtCore.QSize(400, 16777215))
|
||||
self.label_key.setText("")
|
||||
self.label_key.setObjectName("label_key")
|
||||
self.gridLayout.addWidget(self.label_key, 5, 1, 1, 1)
|
||||
self.checkBox_2 = QtWidgets.QCheckBox(Dialog)
|
||||
self.checkBox_2.setText("")
|
||||
self.checkBox_2.setCheckable(False)
|
||||
self.checkBox_2.setObjectName("checkBox_2")
|
||||
self.gridLayout.addWidget(self.checkBox_2, 5, 3, 1, 1)
|
||||
self.label_8 = QtWidgets.QLabel(Dialog)
|
||||
self.label_8.setObjectName("label_8")
|
||||
self.gridLayout.addWidget(self.label_8, 6, 0, 1, 1)
|
||||
self.label_db_dir = QtWidgets.QLabel(Dialog)
|
||||
self.label_db_dir.setMaximumSize(QtCore.QSize(400, 300))
|
||||
self.label_db_dir.setText("")
|
||||
self.label_db_dir.setObjectName("label_db_dir")
|
||||
self.gridLayout.addWidget(self.label_db_dir, 6, 1, 1, 1)
|
||||
self.verticalLayout.addLayout(self.gridLayout)
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_2.addItem(spacerItem4)
|
||||
self.btn_start = QtWidgets.QPushButton(Dialog)
|
||||
self.btn_start.setMinimumSize(QtCore.QSize(80, 40))
|
||||
self.btn_start.setMaximumSize(QtCore.QSize(200, 16777215))
|
||||
self.btn_start.setObjectName("btn_start")
|
||||
self.horizontalLayout_2.addWidget(self.btn_start)
|
||||
spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_2.addItem(spacerItem5)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_2)
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.label_ready = QtWidgets.QLabel(Dialog)
|
||||
self.label_ready.setObjectName("label_ready")
|
||||
self.horizontalLayout.addWidget(self.label_ready)
|
||||
self.progressBar = QtWidgets.QProgressBar(Dialog)
|
||||
self.progressBar.setProperty("value", 0)
|
||||
self.progressBar.setObjectName("progressBar")
|
||||
self.horizontalLayout.addWidget(self.progressBar)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
self.horizontalLayout_3.addLayout(self.verticalLayout)
|
||||
spacerItem6 = QtWidgets.QSpacerItem(128, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_3.addItem(spacerItem6)
|
||||
self.verticalLayout_2.addLayout(self.horizontalLayout_3)
|
||||
spacerItem7 = QtWidgets.QSpacerItem(20, 79, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.verticalLayout_2.addItem(spacerItem7)
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||
self.btn_help.setText(_translate("Dialog", "使用说明"))
|
||||
self.label_3.setText(_translate("Dialog", "解密数据库"))
|
||||
self.label_9.setText(_translate("Dialog", "以下内容为自动获取,如获取失败请手动填写"))
|
||||
self.label.setText(_translate("Dialog", "PID"))
|
||||
self.label_7.setText(_translate("Dialog", "版本"))
|
||||
self.btn_getinfo.setText(_translate("Dialog", "获取信息"))
|
||||
self.label_2.setText(_translate("Dialog", "手机号"))
|
||||
self.label_5.setText(_translate("Dialog", "微信昵称"))
|
||||
self.label_4.setText(_translate("Dialog", "wxid"))
|
||||
self.btn_db_dir.setText(_translate("Dialog", "设置微信路径"))
|
||||
self.label_6.setText(_translate("Dialog", "密钥"))
|
||||
self.label_8.setText(_translate("Dialog", "微信路径"))
|
||||
self.btn_start.setText(_translate("Dialog", "开始启动"))
|
||||
self.label_ready.setText(_translate("Dialog", "未就绪"))
|
||||
340
app/ui/tool/pc_decrypt/pc_decrypt.py
Normal file
340
app/ui/tool/pc_decrypt/pc_decrypt.py
Normal file
@@ -0,0 +1,340 @@
|
||||
import json
|
||||
import os.path
|
||||
import sys
|
||||
import traceback
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import requests
|
||||
from PyQt5.QtCore import pyqtSignal, QThread, QUrl
|
||||
from PyQt5.QtGui import QDesktopServices
|
||||
from PyQt5.QtWidgets import QWidget, QMessageBox, QFileDialog
|
||||
|
||||
from app.DataBase import msg_db, misc_db, close_db
|
||||
from app.DataBase.merge import merge_databases, merge_MediaMSG_databases
|
||||
from app.components.QCursorGif import QCursorGif
|
||||
from app.config import INFO_FILE_PATH, DB_DIR, SERVER_API_URL
|
||||
from app.decrypt import get_wx_info, decrypt
|
||||
from app.log import logger
|
||||
from app.util import path
|
||||
from . import decryptUi
|
||||
from ...Icon import Icon
|
||||
from ...menu.about_dialog import Decrypt
|
||||
|
||||
|
||||
class DecryptControl(QWidget, decryptUi.Ui_Dialog, QCursorGif):
|
||||
DecryptSignal = pyqtSignal(bool)
|
||||
get_wxidSignal = pyqtSignal(str)
|
||||
versionErrorSignal = pyqtSignal(str)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(DecryptControl, self).__init__(parent)
|
||||
self.max_val = 0
|
||||
self.setupUi(self)
|
||||
# 设置忙碌光标图片数组
|
||||
self.initCursor([':/icons/icons/Cursors/%d.png' %
|
||||
i for i in range(8)], self)
|
||||
self.setCursorTimeout(100)
|
||||
self.version_list = None
|
||||
self.btn_start.clicked.connect(self.decrypt)
|
||||
self.btn_getinfo.clicked.connect(self.get_info)
|
||||
self.btn_db_dir.clicked.connect(self.select_db_dir)
|
||||
# self.lineEdit.returnPressed.connect(self.set_wxid)
|
||||
# self.lineEdit.textChanged.connect(self.set_wxid_)
|
||||
self.lineEdit_name.returnPressed.connect(self.set_wxid)
|
||||
self.lineEdit_name.textChanged.connect(self.set_wxid_)
|
||||
self.lineEdit_phone.returnPressed.connect(self.set_wxid)
|
||||
self.lineEdit_phone.textChanged.connect(self.set_wxid_)
|
||||
self.btn_help.clicked.connect(self.show_help)
|
||||
self.btn_getinfo.setIcon(Icon.Get_info_Icon)
|
||||
self.btn_db_dir.setIcon(Icon.Folder_Icon)
|
||||
self.btn_start.setIcon(Icon.Start_Icon)
|
||||
self.btn_help.setIcon(Icon.Help_Icon)
|
||||
self.info = {}
|
||||
self.lineEdit_name.setFocus()
|
||||
self.ready = False
|
||||
self.wx_dir = None
|
||||
|
||||
def show_help(self):
|
||||
# 定义网页链接
|
||||
url = QUrl("https://blog.lc044.love/post/4")
|
||||
# 使用QDesktopServices打开网页
|
||||
QDesktopServices.openUrl(url)
|
||||
|
||||
# @log
|
||||
def get_info(self):
|
||||
self.startBusy()
|
||||
self.get_info_thread = MyThread(self.version_list)
|
||||
self.get_info_thread.signal.connect(self.set_info)
|
||||
self.get_info_thread.start()
|
||||
|
||||
def set_info(self, result):
|
||||
# print(result)
|
||||
if result[0] == -1:
|
||||
QMessageBox.critical(self, "错误", "请登录微信")
|
||||
elif result[0] == -2:
|
||||
self.versionErrorSignal.emit(result[1])
|
||||
QMessageBox.critical(self, "错误",
|
||||
"微信版本不匹配\n请手动填写信息")
|
||||
|
||||
elif result[0] == -3:
|
||||
QMessageBox.critical(self, "错误", "WeChat WeChatWin.dll Not Found")
|
||||
elif result[0] == -10086:
|
||||
QMessageBox.critical(self, "错误", "未知错误,请收集错误信息")
|
||||
else:
|
||||
self.ready = True
|
||||
self.info = result[0]
|
||||
self.label_key.setText(self.info['key'])
|
||||
self.label_wxid.setText(self.info['wxid'])
|
||||
self.lineEdit_name.setText(self.info['name'])
|
||||
self.lineEdit_phone.setText(self.info['mobile'])
|
||||
self.label_pid.setText(str(self.info['pid']))
|
||||
self.label_version.setText(self.info['version'])
|
||||
self.lineEdit_name.setFocus()
|
||||
self.checkBox.setCheckable(True)
|
||||
self.checkBox.setChecked(True)
|
||||
self.get_wxidSignal.emit(self.info['wxid'])
|
||||
directory = os.path.join(path.wx_path(), self.info['wxid'])
|
||||
if os.path.exists(directory):
|
||||
self.label_db_dir.setText(directory)
|
||||
self.wx_dir = directory
|
||||
self.checkBox_2.setCheckable(True)
|
||||
self.checkBox_2.setChecked(True)
|
||||
self.ready = True
|
||||
if self.ready:
|
||||
self.label_ready.setText('已就绪')
|
||||
if self.wx_dir and os.path.exists(os.path.join(self.wx_dir)):
|
||||
self.label_ready.setText('已就绪')
|
||||
self.stopBusy()
|
||||
|
||||
def set_wxid_(self):
|
||||
if self.sender() == self.lineEdit_name:
|
||||
self.info['name'] = self.lineEdit_name.text()
|
||||
elif self.sender() == self.lineEdit_phone:
|
||||
self.info['mobel'] = self.lineEdit_phone.text()
|
||||
|
||||
def set_wxid(self):
|
||||
if self.sender() == self.lineEdit_name:
|
||||
self.info['name'] = self.lineEdit_name.text()
|
||||
QMessageBox.information(self, "ok", f"昵称修改成功{self.info['name']}")
|
||||
elif self.sender() == self.lineEdit_phone:
|
||||
self.info['mobile'] = self.lineEdit_phone.text()
|
||||
QMessageBox.information(self, "ok", f"手机号修改成功{self.info['mobile']}")
|
||||
|
||||
def select_db_dir(self):
|
||||
directory = QFileDialog.getExistingDirectory(
|
||||
self, "选取微信文件保存目录——能看到Msg文件夹",
|
||||
path.wx_path()
|
||||
) # 起始路径
|
||||
db_dir = os.path.join(directory, 'Msg')
|
||||
if not os.path.exists(db_dir):
|
||||
QMessageBox.critical(self, "错误", "文件夹选择错误\n一般以wxid_xxx结尾")
|
||||
return
|
||||
|
||||
self.label_db_dir.setText(directory)
|
||||
self.wx_dir = directory
|
||||
self.checkBox_2.setCheckable(True)
|
||||
self.checkBox_2.setChecked(True)
|
||||
if self.ready:
|
||||
self.label_ready.setText('已就绪')
|
||||
|
||||
def decrypt(self):
|
||||
if not self.ready:
|
||||
QMessageBox.critical(self, "错误", "请先获取信息")
|
||||
return
|
||||
if not self.wx_dir:
|
||||
QMessageBox.critical(self, "错误", "请先选择微信安装路径")
|
||||
return
|
||||
if self.label_wxid.text() == 'None':
|
||||
QMessageBox.critical(self, "错误", "请填入wxid")
|
||||
return
|
||||
db_dir = os.path.join(self.wx_dir, 'Msg')
|
||||
if self.ready:
|
||||
if not os.path.exists(db_dir):
|
||||
QMessageBox.critical(self, "错误", "文件夹选择错误\n一般以wxid_xxx结尾")
|
||||
return
|
||||
if self.info.get('key') == 'None':
|
||||
QMessageBox.critical(self, "错误",
|
||||
"密钥错误\n请查看教程解决相关问题")
|
||||
close_db()
|
||||
self.thread2 = DecryptThread(db_dir, self.info['key'])
|
||||
self.thread2.maxNumSignal.connect(self.setProgressBarMaxNum)
|
||||
self.thread2.signal.connect(self.progressBar_view)
|
||||
self.thread2.okSignal.connect(self.btnExitClicked)
|
||||
self.thread2.errorSignal.connect(
|
||||
lambda x: QMessageBox.critical(self, "错误",
|
||||
"错误\n请检查微信版本是否为最新和微信路径是否正确\n或者关闭微信多开")
|
||||
)
|
||||
self.thread2.start()
|
||||
|
||||
def btnEnterClicked(self):
|
||||
# print("enter clicked")
|
||||
# 中间可以添加处理逻辑
|
||||
# QMessageBox.about(self, "解密成功", "数据库文件存储在app/DataBase/Msg文件夹下")
|
||||
self.progressBar_view(self.max_val)
|
||||
self.DecryptSignal.emit(True)
|
||||
# self.close()
|
||||
|
||||
def setProgressBarMaxNum(self, max_val):
|
||||
self.max_val = max_val
|
||||
self.progressBar.setRange(0, max_val)
|
||||
|
||||
def progressBar_view(self, value):
|
||||
"""
|
||||
进度条显示
|
||||
:param value: 进度0-100
|
||||
:return: None
|
||||
"""
|
||||
self.progressBar.setProperty('value', value)
|
||||
# self.btnExitClicked()
|
||||
# data.init_database()
|
||||
|
||||
def btnExitClicked(self):
|
||||
# print("Exit clicked")
|
||||
dic = {
|
||||
'wxid': self.info['wxid'],
|
||||
'wx_dir': self.wx_dir,
|
||||
'name': self.info['name'],
|
||||
'mobile': self.info['mobile'],
|
||||
'token': Decrypt.decrypt(self.info['wxid'])
|
||||
}
|
||||
try:
|
||||
with open(INFO_FILE_PATH, "w", encoding="utf-8") as f:
|
||||
json.dump(dic, f, ensure_ascii=False, indent=4)
|
||||
except:
|
||||
with open('./info.json', 'w', encoding='utf-8') as f:
|
||||
f.write(json.dumps(dic))
|
||||
self.progressBar_view(self.max_val)
|
||||
self.DecryptSignal.emit(True)
|
||||
self.close()
|
||||
|
||||
|
||||
class DecryptThread(QThread):
|
||||
signal = pyqtSignal(str)
|
||||
maxNumSignal = pyqtSignal(int)
|
||||
okSignal = pyqtSignal(str)
|
||||
errorSignal = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, db_path, key):
|
||||
super(DecryptThread, self).__init__()
|
||||
self.db_path = db_path
|
||||
self.key = key
|
||||
self.textBrowser = None
|
||||
|
||||
def __del__(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
close_db()
|
||||
output_dir = DB_DIR
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
tasks = []
|
||||
if os.path.exists(self.db_path):
|
||||
for root, dirs, files in os.walk(self.db_path):
|
||||
for file in files:
|
||||
if '.db' == file[-3:]:
|
||||
if 'xInfo.db' == file:
|
||||
continue
|
||||
inpath = os.path.join(root, file)
|
||||
# print(inpath)
|
||||
output_path = os.path.join(output_dir, file)
|
||||
tasks.append([self.key, inpath, output_path])
|
||||
else:
|
||||
try:
|
||||
name, suffix = file.split('.')
|
||||
if suffix.startswith('db_SQLITE'):
|
||||
inpath = os.path.join(root, file)
|
||||
# print(inpath)
|
||||
output_path = os.path.join(output_dir, name + '.db')
|
||||
tasks.append([self.key, inpath, output_path])
|
||||
except:
|
||||
continue
|
||||
self.maxNumSignal.emit(len(tasks))
|
||||
for i, task in enumerate(tasks):
|
||||
if decrypt.decrypt(*task) == -1:
|
||||
self.errorSignal.emit(True)
|
||||
self.signal.emit(str(i))
|
||||
# print(self.db_path)
|
||||
# 目标数据库文件
|
||||
target_database = os.path.join(DB_DIR, 'MSG.db')
|
||||
# 源数据库文件列表
|
||||
source_databases = [os.path.join(DB_DIR, f"MSG{i}.db") for i in range(1, 50)]
|
||||
import shutil
|
||||
if os.path.exists(target_database):
|
||||
os.remove(target_database)
|
||||
shutil.copy2(os.path.join(DB_DIR, 'MSG0.db'), target_database) # 使用一个数据库文件作为模板
|
||||
# 合并数据库
|
||||
merge_databases(source_databases, target_database)
|
||||
|
||||
# 音频数据库文件
|
||||
target_database = os.path.join(DB_DIR, 'MediaMSG.db')
|
||||
# 源数据库文件列表
|
||||
if os.path.exists(target_database):
|
||||
os.remove(target_database)
|
||||
source_databases = [os.path.join(DB_DIR, f"MediaMSG{i}.db") for i in range(1, 50)]
|
||||
shutil.copy2(os.path.join(DB_DIR, 'MediaMSG0.db'), target_database) # 使用一个数据库文件作为模板
|
||||
|
||||
# 合并数据库
|
||||
merge_MediaMSG_databases(source_databases, target_database)
|
||||
self.okSignal.emit('ok')
|
||||
# self.signal.emit('100')
|
||||
|
||||
|
||||
class MyThread(QThread):
|
||||
signal = pyqtSignal(list)
|
||||
|
||||
def __init__(self, version_list=None):
|
||||
super(MyThread, self).__init__()
|
||||
self.version_list = version_list
|
||||
|
||||
def __del__(self):
|
||||
pass
|
||||
|
||||
def get_bias_add(self, version):
|
||||
url = urljoin(SERVER_API_URL, 'wxBiasAddr')
|
||||
data = {
|
||||
'version': version
|
||||
}
|
||||
try:
|
||||
response = requests.get(url, json=data)
|
||||
print(response)
|
||||
print(response.text)
|
||||
if response.status_code == 200:
|
||||
update_info = response.json()
|
||||
return update_info
|
||||
else:
|
||||
return {}
|
||||
except:
|
||||
return {}
|
||||
|
||||
def run(self):
|
||||
if self.version_list:
|
||||
VERSION_LIST = self.version_list
|
||||
else:
|
||||
file_path = './app/resources/data/version_list.json'
|
||||
if not os.path.exists(file_path):
|
||||
resource_dir = getattr(sys, '_MEIPASS', os.path.abspath(os.path.dirname(__file__)))
|
||||
file_path = os.path.join(resource_dir, 'app', 'resources', 'data', 'version_list.json')
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
VERSION_LIST = json.loads(f.read())
|
||||
try:
|
||||
result = get_wx_info.get_info(VERSION_LIST)
|
||||
if result == -1:
|
||||
result = [result]
|
||||
elif result == -2:
|
||||
result = [result]
|
||||
elif result == -3:
|
||||
result = [result]
|
||||
elif isinstance(result, str):
|
||||
version = result
|
||||
# version = '3.9.9.43'
|
||||
version_bias = self.get_bias_add(version)
|
||||
if version_bias.get(version):
|
||||
logger.info(f"从云端获取内存基址:{version_bias}")
|
||||
result = get_wx_info.get_info(version_bias)
|
||||
else:
|
||||
logger.info(f"从云端获取内存基址失败:{version}")
|
||||
result = [-2, version]
|
||||
except:
|
||||
logger.error(traceback.format_exc())
|
||||
result = [-10086]
|
||||
self.signal.emit(result)
|
||||
208
app/ui/tool/setting/setting.py
Normal file
208
app/ui/tool/setting/setting.py
Normal file
@@ -0,0 +1,208 @@
|
||||
import json
|
||||
import os.path
|
||||
import time
|
||||
|
||||
import requests
|
||||
from PyQt5.QtCore import pyqtSignal, QThread
|
||||
from PyQt5.QtWidgets import QWidget, QMessageBox
|
||||
from app.config import SEND_LOG_FLAG
|
||||
from app.person import Me
|
||||
from .settingUi import Ui_Form
|
||||
|
||||
Stylesheet = """
|
||||
QPushButton{
|
||||
background-color: rgb(250,252,253);
|
||||
border-radius: 5px;
|
||||
padding: 8px;
|
||||
border-right: 2px solid #888888; /* 按钮边框,2px宽,白色 */
|
||||
border-bottom: 2px solid #888888; /* 按钮边框,2px宽,白色 */
|
||||
border-left: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */
|
||||
border-top: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: lightgray;
|
||||
}
|
||||
/*去掉item虚线边框*/
|
||||
QListWidget, QListView, QTreeWidget, QTreeView {
|
||||
outline: 0px;
|
||||
border:none;
|
||||
}
|
||||
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
|
||||
QListWidget {
|
||||
min-width: 400px;
|
||||
max-width: 400px;
|
||||
min-height: 80px;
|
||||
max-height: 80px;
|
||||
color: black;
|
||||
border:none;
|
||||
}
|
||||
QListWidget::item{
|
||||
min-width: 80px;
|
||||
max-width: 400px;
|
||||
min-height: 80px;
|
||||
max-height: 80px;
|
||||
}
|
||||
/*被选中时的背景颜色和左边框颜色*/
|
||||
QListWidget::item:selected {
|
||||
border-left:none;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
QCheckBox::indicator {
|
||||
background: rgb(251, 251, 251);
|
||||
Width:60px;
|
||||
Height:60px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
QCheckBox::indicator:unchecked{
|
||||
Width:60px;
|
||||
Height:60px;
|
||||
image: url(:/icons/icons/按钮_关闭.svg);
|
||||
}
|
||||
QCheckBox::indicator:checked{
|
||||
Width:60px;
|
||||
Height:60px;
|
||||
image: url(:/icons/icons/按钮_开启.svg);
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def set_SEND_LOG_FLAG(flag):
|
||||
# noinspection PyGlobalUndefined
|
||||
global SEND_LOG_FLAG
|
||||
SEND_LOG_FLAG = flag
|
||||
|
||||
|
||||
class SettingControl(QWidget, Ui_Form):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(SettingControl, self).__init__(parent)
|
||||
self.setStyleSheet(Stylesheet)
|
||||
self.setupUi(self)
|
||||
|
||||
self.btn_addstopword.clicked.connect(self.add_stopwords)
|
||||
self.btn_addnewword_2.clicked.connect(self.add_new_words)
|
||||
self.commandLinkButton_send_error_log.clicked.connect(self.show_info)
|
||||
self.btn_send_error_log.clicked.connect(self.send_error_log)
|
||||
self.init_ui()
|
||||
self.read_data()
|
||||
|
||||
def init_ui(self):
|
||||
self.checkBox.setText('是')
|
||||
self.checkBox_send_error_log.clicked.connect(self.set_error_log)
|
||||
|
||||
def show_info(self):
|
||||
QMessageBox.information(self, "收集错误信息",
|
||||
"为了更好的解决用户问题,需要收集软件崩溃导致的错误信息,该操作不会上传包括手机号、微信号、昵称等在内的任何信息\n"
|
||||
)
|
||||
|
||||
def set_error_log(self):
|
||||
if self.checkBox_send_error_log.isChecked():
|
||||
self.label_error_log.setText('开')
|
||||
set_SEND_LOG_FLAG(True)
|
||||
else:
|
||||
self.label_error_log.setText('关')
|
||||
set_SEND_LOG_FLAG(False)
|
||||
print('SEND_LOG_FLAG:', SEND_LOG_FLAG)
|
||||
|
||||
def read_data(self):
|
||||
os.makedirs('./app/data', exist_ok=True)
|
||||
stopwords = ['裂开', '苦涩', '叹气', '凋谢', '让我看看', '酷', '奋斗', '疑问', '擦汗', '抠鼻', '鄙视', '勾引',
|
||||
'奸笑', '嘿哈', '捂脸', '机智', '加油', '吃瓜', '尴尬', '炸弹', '旺柴']
|
||||
new_words = ['YYDS', '666', '显眼包', '遥遥领先']
|
||||
if os.path.exists('./app/data/stopwords.txt'):
|
||||
with open('./app/data/stopwords.txt', 'r', encoding='utf-8') as f:
|
||||
stopwords = set(f.read().splitlines())
|
||||
self.plainTextEdit.setPlainText(' '.join(stopwords))
|
||||
else:
|
||||
self.plainTextEdit.setPlainText(' '.join(stopwords))
|
||||
stopwords = '\n'.join(stopwords)
|
||||
with open('./app/data/stopwords.txt', 'w', encoding='utf-8') as f:
|
||||
f.write(stopwords)
|
||||
if os.path.exists('./app/data/new_words.txt'):
|
||||
with open('./app/data/new_words.txt', 'r', encoding='utf-8') as f:
|
||||
new_words = set(f.read().splitlines())
|
||||
self.plainTextEdit_newword.setPlainText(' '.join(new_words))
|
||||
else:
|
||||
self.plainTextEdit_newword.setPlainText(' '.join(new_words))
|
||||
stopwords = '\n'.join(new_words)
|
||||
with open('./app/data/new_words.txt', 'w', encoding='utf-8') as f:
|
||||
f.write(stopwords)
|
||||
|
||||
def add_stopwords(self):
|
||||
text = self.plainTextEdit.toPlainText()
|
||||
stopwords = '\n'.join(text.split())
|
||||
with open('./app/data/stopwords.txt', 'w', encoding='utf-8') as f:
|
||||
f.write(stopwords)
|
||||
QMessageBox.about(self, "添加成功", "停用词添加成功")
|
||||
|
||||
def add_new_words(self):
|
||||
text = self.plainTextEdit_newword.toPlainText()
|
||||
new_words = '\n'.join(text.split())
|
||||
with open('./app/data/new_words.txt', 'w', encoding='utf-8') as f:
|
||||
f.write(new_words)
|
||||
QMessageBox.about(self, "添加成功", "自定义词添加成功")
|
||||
|
||||
def send_error_log(self):
|
||||
self.send_thread = MyThread()
|
||||
self.send_thread.signal.connect(self.show_resp)
|
||||
self.send_thread.start()
|
||||
|
||||
def show_resp(self, message):
|
||||
if message.get('code') == 200:
|
||||
QMessageBox.about(self, "发送结果", f"日志发送成功\n{message.get('message')}")
|
||||
else:
|
||||
QMessageBox.about(self, "发送结果", f"{message.get('code')}:{message.get('errmsg')}")
|
||||
|
||||
|
||||
class MyThread(QThread):
|
||||
signal = pyqtSignal(dict)
|
||||
|
||||
def __init__(self, message=''):
|
||||
super(MyThread, self).__init__()
|
||||
if message:
|
||||
self.message = message
|
||||
else:
|
||||
filename = time.strftime("%Y-%m-%d", time.localtime(time.time()))
|
||||
file_path = f'{filename}-log.log'
|
||||
if os.path.exists(file_path):
|
||||
with open(file_path, 'r', encoding='gbk') as f:
|
||||
self.message = f.read()
|
||||
elif os.path.exists(f'./app/log/logs/{filename}-log.log'):
|
||||
with open(f'./app/log/logs/{filename}-log.log', 'r', encoding='gbk') as f:
|
||||
self.message = f.read()
|
||||
|
||||
def __del__(self):
|
||||
pass
|
||||
|
||||
def send_error_msg(self, message):
|
||||
url = "http://api.lc044.love/error"
|
||||
if not message:
|
||||
return {
|
||||
'code': 201,
|
||||
'errmsg': '日志为空'
|
||||
}
|
||||
data = {
|
||||
'username': Me().wxid,
|
||||
'error': message
|
||||
}
|
||||
try:
|
||||
response = requests.post(url, json=data)
|
||||
if response.status_code == 200:
|
||||
resp_info = response.json()
|
||||
return resp_info
|
||||
else:
|
||||
return {
|
||||
'code': 503,
|
||||
'errmsg': '服务器错误'
|
||||
}
|
||||
except:
|
||||
return {
|
||||
'code': 404,
|
||||
'errmsg': '客户端错误'
|
||||
}
|
||||
|
||||
def run(self):
|
||||
resp_info = self.send_error_msg(self.message)
|
||||
self.signal.emit(resp_info)
|
||||
204
app/ui/tool/setting/settingUi.py
Normal file
204
app/ui/tool/setting/settingUi.py
Normal file
@@ -0,0 +1,204 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'settingUi.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_Form(object):
|
||||
def setupUi(self, Form):
|
||||
Form.setObjectName("Form")
|
||||
Form.resize(638, 696)
|
||||
self.verticalLayout_6 = QtWidgets.QVBoxLayout(Form)
|
||||
self.verticalLayout_6.setObjectName("verticalLayout_6")
|
||||
self.scrollArea = QtWidgets.QScrollArea(Form)
|
||||
self.scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame)
|
||||
self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
|
||||
self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
self.scrollArea.setWidgetResizable(True)
|
||||
self.scrollArea.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
|
||||
self.scrollArea.setObjectName("scrollArea")
|
||||
self.scrollAreaWidgetContents = QtWidgets.QWidget()
|
||||
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, -20, 595, 728))
|
||||
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
|
||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents)
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
self.widget = QtWidgets.QWidget(self.scrollAreaWidgetContents)
|
||||
self.widget.setStyleSheet("QWidget{\n"
|
||||
" background-color:rgb(251,251,251);\n"
|
||||
" border-radius: 10px;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"QPushButton{\n"
|
||||
" background-color: rgb(250,252,253);\n"
|
||||
" border-radius: 5px;\n"
|
||||
" padding: 8px;\n"
|
||||
" border-right: 2px solid #888888; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-bottom: 2px solid #888888; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-left: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-top: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */\n"
|
||||
"}\n"
|
||||
"QPushButton:hover { \n"
|
||||
" background-color: lightgray;\n"
|
||||
"}")
|
||||
self.widget.setObjectName("widget")
|
||||
self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.widget)
|
||||
self.verticalLayout_4.setObjectName("verticalLayout_4")
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.label = QtWidgets.QLabel(self.widget)
|
||||
self.label.setObjectName("label")
|
||||
self.verticalLayout.addWidget(self.label)
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.plainTextEdit = QtWidgets.QPlainTextEdit(self.widget)
|
||||
self.plainTextEdit.setFrameShape(QtWidgets.QFrame.Box)
|
||||
self.plainTextEdit.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
self.plainTextEdit.setObjectName("plainTextEdit")
|
||||
self.horizontalLayout.addWidget(self.plainTextEdit)
|
||||
self.btn_addstopword = QtWidgets.QPushButton(self.widget)
|
||||
self.btn_addstopword.setObjectName("btn_addstopword")
|
||||
self.horizontalLayout.addWidget(self.btn_addstopword)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
self.verticalLayout_4.addLayout(self.verticalLayout)
|
||||
self.verticalLayout_3.addWidget(self.widget)
|
||||
self.widget_3 = QtWidgets.QWidget(self.scrollAreaWidgetContents)
|
||||
self.widget_3.setStyleSheet("QWidget{\n"
|
||||
" background-color:rgb(251,251,251);\n"
|
||||
" border-radius: 10px;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"QPushButton{\n"
|
||||
" background-color: rgb(250,252,253);\n"
|
||||
" border-radius: 5px;\n"
|
||||
" padding: 8px;\n"
|
||||
" border-right: 2px solid #888888; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-bottom: 2px solid #888888; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-left: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-top: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */\n"
|
||||
"}\n"
|
||||
"QPushButton:hover { \n"
|
||||
" background-color: lightgray;\n"
|
||||
"}")
|
||||
self.widget_3.setObjectName("widget_3")
|
||||
self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.widget_3)
|
||||
self.verticalLayout_5.setObjectName("verticalLayout_5")
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.label_2 = QtWidgets.QLabel(self.widget_3)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.verticalLayout_2.addWidget(self.label_2)
|
||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||
self.plainTextEdit_newword = QtWidgets.QPlainTextEdit(self.widget_3)
|
||||
self.plainTextEdit_newword.setFrameShape(QtWidgets.QFrame.Box)
|
||||
self.plainTextEdit_newword.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
self.plainTextEdit_newword.setPlainText("")
|
||||
self.plainTextEdit_newword.setObjectName("plainTextEdit_newword")
|
||||
self.horizontalLayout_3.addWidget(self.plainTextEdit_newword)
|
||||
self.btn_addnewword_2 = QtWidgets.QPushButton(self.widget_3)
|
||||
self.btn_addnewword_2.setObjectName("btn_addnewword_2")
|
||||
self.horizontalLayout_3.addWidget(self.btn_addnewword_2)
|
||||
self.verticalLayout_2.addLayout(self.horizontalLayout_3)
|
||||
self.verticalLayout_5.addLayout(self.verticalLayout_2)
|
||||
self.verticalLayout_3.addWidget(self.widget_3)
|
||||
self.widget_2 = QtWidgets.QWidget(self.scrollAreaWidgetContents)
|
||||
self.widget_2.setStyleSheet("QWidget{\n"
|
||||
" background-color:rgb(251,251,251);\n"
|
||||
" border-radius: 10px;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"QPushButton{\n"
|
||||
" background-color: rgb(250,252,253);\n"
|
||||
" border-radius: 5px;\n"
|
||||
" padding: 8px;\n"
|
||||
" border-right: 2px solid #888888; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-bottom: 2px solid #888888; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-left: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */\n"
|
||||
" border-top: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */\n"
|
||||
"}\n"
|
||||
"QPushButton:hover { \n"
|
||||
" background-color: lightgray;\n"
|
||||
"}")
|
||||
self.widget_2.setObjectName("widget_2")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.widget_2)
|
||||
self.horizontalLayout_2.setContentsMargins(9, -1, -1, -1)
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.commandLinkButton_send_error_log = QtWidgets.QCommandLinkButton(self.widget_2)
|
||||
self.commandLinkButton_send_error_log.setEnabled(True)
|
||||
self.commandLinkButton_send_error_log.setTabletTracking(False)
|
||||
self.commandLinkButton_send_error_log.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
self.commandLinkButton_send_error_log.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)
|
||||
self.commandLinkButton_send_error_log.setToolTipDuration(-1)
|
||||
self.commandLinkButton_send_error_log.setLayoutDirection(QtCore.Qt.LeftToRight)
|
||||
self.commandLinkButton_send_error_log.setAutoFillBackground(False)
|
||||
self.commandLinkButton_send_error_log.setCheckable(False)
|
||||
self.commandLinkButton_send_error_log.setChecked(False)
|
||||
self.commandLinkButton_send_error_log.setAutoRepeat(False)
|
||||
self.commandLinkButton_send_error_log.setAutoExclusive(False)
|
||||
self.commandLinkButton_send_error_log.setAutoDefault(False)
|
||||
self.commandLinkButton_send_error_log.setDefault(False)
|
||||
self.commandLinkButton_send_error_log.setObjectName("commandLinkButton_send_error_log")
|
||||
self.horizontalLayout_2.addWidget(self.commandLinkButton_send_error_log)
|
||||
self.btn_send_error_log = QtWidgets.QPushButton(self.widget_2)
|
||||
self.btn_send_error_log.setObjectName("btn_send_error_log")
|
||||
self.horizontalLayout_2.addWidget(self.btn_send_error_log)
|
||||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_2.addItem(spacerItem)
|
||||
self.label_error_log = QtWidgets.QLabel(self.widget_2)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.label_error_log.sizePolicy().hasHeightForWidth())
|
||||
self.label_error_log.setSizePolicy(sizePolicy)
|
||||
self.label_error_log.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.label_error_log.setObjectName("label_error_log")
|
||||
self.horizontalLayout_2.addWidget(self.label_error_log)
|
||||
self.checkBox_send_error_log = QtWidgets.QCheckBox(self.widget_2)
|
||||
self.checkBox_send_error_log.setText("")
|
||||
self.checkBox_send_error_log.setIconSize(QtCore.QSize(64, 64))
|
||||
self.checkBox_send_error_log.setChecked(True)
|
||||
self.checkBox_send_error_log.setObjectName("checkBox_send_error_log")
|
||||
self.horizontalLayout_2.addWidget(self.checkBox_send_error_log)
|
||||
self.verticalLayout_3.addWidget(self.widget_2)
|
||||
self.checkBox_2 = QtWidgets.QCheckBox(self.scrollAreaWidgetContents)
|
||||
self.checkBox_2.setObjectName("checkBox_2")
|
||||
self.verticalLayout_3.addWidget(self.checkBox_2)
|
||||
self.checkBox = QtWidgets.QCheckBox(self.scrollAreaWidgetContents)
|
||||
self.checkBox.setObjectName("checkBox")
|
||||
self.verticalLayout_3.addWidget(self.checkBox)
|
||||
self.commandLinkButton_2 = QtWidgets.QCommandLinkButton(self.scrollAreaWidgetContents)
|
||||
self.commandLinkButton_2.setCheckable(True)
|
||||
self.commandLinkButton_2.setObjectName("commandLinkButton_2")
|
||||
self.verticalLayout_3.addWidget(self.commandLinkButton_2)
|
||||
self.radioButton = QtWidgets.QRadioButton(self.scrollAreaWidgetContents)
|
||||
self.radioButton.setObjectName("radioButton")
|
||||
self.verticalLayout_3.addWidget(self.radioButton)
|
||||
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
|
||||
self.verticalLayout_6.addWidget(self.scrollArea)
|
||||
|
||||
self.retranslateUi(Form)
|
||||
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||
|
||||
def retranslateUi(self, Form):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Form.setWindowTitle(_translate("Form", "Form"))
|
||||
self.label.setText(_translate("Form", "文本框里输入年度报告词云停用词,每个词之间用空格隔开"))
|
||||
self.plainTextEdit.setPlainText(_translate("Form", "哈哈哈 发呆"))
|
||||
self.btn_addstopword.setText(_translate("Form", "添加停用词"))
|
||||
self.label_2.setText(_translate("Form", "文本框里输入年度报告词云自定义词,每个词之间用空格隔开"))
|
||||
self.btn_addnewword_2.setText(_translate("Form", "添加自定义词"))
|
||||
self.commandLinkButton_send_error_log.setText(_translate("Form", "收集错误日志"))
|
||||
self.commandLinkButton_send_error_log.setDescription(_translate("Form", "收集错误信息以帮助改进"))
|
||||
self.btn_send_error_log.setText(_translate("Form", "手动发送"))
|
||||
self.label_error_log.setText(_translate("Form", "开"))
|
||||
self.checkBox_2.setText(_translate("Form", "CheckBox"))
|
||||
self.checkBox.setText(_translate("Form", "CheckBox"))
|
||||
self.commandLinkButton_2.setText(_translate("Form", "CommandLinkButton"))
|
||||
self.radioButton.setText(_translate("Form", "RadioButton"))
|
||||
85
app/ui/tool/toolUI.py
Normal file
85
app/ui/tool/toolUI.py
Normal file
@@ -0,0 +1,85 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'toolUI.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(590, 547)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("微软雅黑")
|
||||
Dialog.setFont(font)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
|
||||
self.horizontalLayout.setSpacing(0)
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.label = QtWidgets.QLabel(Dialog)
|
||||
self.label.setMaximumSize(QtCore.QSize(80, 80))
|
||||
self.label.setText("")
|
||||
self.label.setObjectName("label")
|
||||
self.horizontalLayout.addWidget(self.label)
|
||||
self.listWidget = QtWidgets.QListWidget(Dialog)
|
||||
self.listWidget.setMinimumSize(QtCore.QSize(100, 80))
|
||||
self.listWidget.setMaximumSize(QtCore.QSize(500, 80))
|
||||
self.listWidget.setFrameShape(QtWidgets.QFrame.NoFrame)
|
||||
self.listWidget.setFrameShadow(QtWidgets.QFrame.Plain)
|
||||
self.listWidget.setLineWidth(0)
|
||||
self.listWidget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
self.listWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
self.listWidget.setFlow(QtWidgets.QListView.LeftToRight)
|
||||
self.listWidget.setObjectName("listWidget")
|
||||
item = QtWidgets.QListWidgetItem()
|
||||
self.listWidget.addItem(item)
|
||||
item = QtWidgets.QListWidgetItem()
|
||||
self.listWidget.addItem(item)
|
||||
item = QtWidgets.QListWidgetItem()
|
||||
self.listWidget.addItem(item)
|
||||
item = QtWidgets.QListWidgetItem()
|
||||
self.listWidget.addItem(item)
|
||||
item = QtWidgets.QListWidgetItem()
|
||||
self.listWidget.addItem(item)
|
||||
self.horizontalLayout.addWidget(self.listWidget)
|
||||
self.label_2 = QtWidgets.QLabel(Dialog)
|
||||
self.label_2.setMaximumSize(QtCore.QSize(80, 80))
|
||||
self.label_2.setText("")
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.horizontalLayout.addWidget(self.label_2)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
self.stackedWidget = QtWidgets.QStackedWidget(Dialog)
|
||||
self.stackedWidget.setFrameShape(QtWidgets.QFrame.NoFrame)
|
||||
self.stackedWidget.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||
self.stackedWidget.setObjectName("stackedWidget")
|
||||
self.verticalLayout.addWidget(self.stackedWidget)
|
||||
self.verticalLayout.setStretch(1, 1)
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
self.stackedWidget.setCurrentIndex(-1)
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||
__sortingEnabled = self.listWidget.isSortingEnabled()
|
||||
self.listWidget.setSortingEnabled(False)
|
||||
item = self.listWidget.item(0)
|
||||
item.setText(_translate("Dialog", "新建项目"))
|
||||
item = self.listWidget.item(1)
|
||||
item.setText(_translate("Dialog", "新建项目"))
|
||||
item = self.listWidget.item(2)
|
||||
item.setText(_translate("Dialog", "新建项目"))
|
||||
item = self.listWidget.item(3)
|
||||
item.setText(_translate("Dialog", "新建项目"))
|
||||
item = self.listWidget.item(4)
|
||||
item.setText(_translate("Dialog", "新建项目"))
|
||||
self.listWidget.setSortingEnabled(__sortingEnabled)
|
||||
111
app/ui/tool/tool_window.py
Normal file
111
app/ui/tool/tool_window.py
Normal file
@@ -0,0 +1,111 @@
|
||||
from PyQt5.QtCore import Qt, pyqtSignal
|
||||
from PyQt5.QtGui import QFont
|
||||
from PyQt5.QtWidgets import QWidget, QListWidgetItem, QLabel
|
||||
|
||||
from app.ui.Icon import Icon
|
||||
from .pc_decrypt import DecryptControl
|
||||
from .setting.setting import SettingControl
|
||||
from .get_bias_addr.get_bias_addr import GetBiasAddrControl
|
||||
from .toolUI import Ui_Dialog
|
||||
|
||||
# 美化样式表
|
||||
Stylesheet = """
|
||||
QPushButton{
|
||||
background-color: rgb(250,252,253);
|
||||
border-radius: 5px;
|
||||
padding: 8px;
|
||||
border-right: 2px solid #888888; /* 按钮边框,2px宽,白色 */
|
||||
border-bottom: 2px solid #888888; /* 按钮边框,2px宽,白色 */
|
||||
border-left: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */
|
||||
border-top: 1px solid #ffffff; /* 按钮边框,2px宽,白色 */
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: lightgray;
|
||||
}
|
||||
/*去掉item虚线边框*/
|
||||
QListWidget, QListView, QTreeWidget, QTreeView {
|
||||
outline: 0px;
|
||||
border:none;
|
||||
}
|
||||
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
|
||||
QListWidget {
|
||||
min-width: 400px;
|
||||
max-width: 400px;
|
||||
min-height: 80px;
|
||||
max-height: 80px;
|
||||
color: black;
|
||||
border:none;
|
||||
}
|
||||
QListWidget::item{
|
||||
min-width: 80px;
|
||||
max-width: 400px;
|
||||
min-height: 80px;
|
||||
max-height: 80px;
|
||||
}
|
||||
/*被选中时的背景颜色和左边框颜色*/
|
||||
QListWidget::item:selected {
|
||||
border-left:none;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class ToolWindow(QWidget, Ui_Dialog):
|
||||
get_info_signal = pyqtSignal(str)
|
||||
decrypt_success_signal = pyqtSignal(bool)
|
||||
load_finish_signal = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
self.setStyleSheet(Stylesheet)
|
||||
self.init_ui()
|
||||
self.load_finish_signal.emit(True)
|
||||
|
||||
def init_ui(self):
|
||||
self.listWidget.clear()
|
||||
self.listWidget.currentRowChanged.connect(self.setCurrentIndex)
|
||||
chat_item = QListWidgetItem(Icon.Decrypt_Icon, '解密', self.listWidget)
|
||||
contact_item = QListWidgetItem(Icon.Contact_Icon, '设置', self.listWidget)
|
||||
myinfo_item = QListWidgetItem(Icon.Home_Icon, '解密2', self.listWidget)
|
||||
tool_item = QListWidgetItem(Icon.Home_Icon, '别点', self.listWidget)
|
||||
|
||||
self.decrypt_window = DecryptControl()
|
||||
self.decrypt_window.get_wxidSignal.connect(self.get_info_signal)
|
||||
self.decrypt_window.DecryptSignal.connect(self.decrypt_success_signal)
|
||||
self.decrypt_window.versionErrorSignal.connect(self.show_decrypt2)
|
||||
self.stackedWidget.addWidget(self.decrypt_window)
|
||||
|
||||
setting_window = SettingControl()
|
||||
self.stackedWidget.addWidget(setting_window)
|
||||
|
||||
self.get_bias_addr_window = GetBiasAddrControl()
|
||||
self.get_bias_addr_window.biasAddrSignal.connect(self.decrypt)
|
||||
self.stackedWidget.addWidget(self.get_bias_addr_window)
|
||||
|
||||
label = QLabel('都说了不让你点', self)
|
||||
label.setFont(QFont("微软雅黑", 50))
|
||||
label.setAlignment(Qt.AlignCenter)
|
||||
# 设置label的背景颜色(这里随机)
|
||||
# 这里加了一个margin边距(方便区分QStackedWidget和QLabel的颜色)
|
||||
# label.setStyleSheet('background: rgb(%d, %d, %d);margin: 50px;' % (
|
||||
# randint(0, 255), randint(0, 255), randint(0, 255)))
|
||||
|
||||
self.stackedWidget.addWidget(label)
|
||||
self.listWidget.setCurrentRow(0)
|
||||
self.stackedWidget.setCurrentIndex(0)
|
||||
|
||||
def decrypt(self, version_list):
|
||||
self.listWidget.setCurrentRow(0)
|
||||
self.stackedWidget.setCurrentIndex(0)
|
||||
self.decrypt_window.version_list = version_list
|
||||
self.decrypt_window.get_info()
|
||||
|
||||
def show_decrypt2(self, version):
|
||||
self.listWidget.setCurrentRow(2)
|
||||
self.stackedWidget.setCurrentIndex(2)
|
||||
|
||||
def setCurrentIndex(self, row):
|
||||
self.stackedWidget.setCurrentIndex(row)
|
||||
11
app/ui/update/update.py
Normal file
11
app/ui/update/update.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from app.ui.update.updateUi import Ui_Dialog
|
||||
import shutil
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtWidgets import QWidget, QMessageBox, QAction, QLineEdit
|
||||
|
||||
|
||||
class UpdateControl(QWidget, Ui_Dialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
52
app/ui/update/updateUi.py
Normal file
52
app/ui/update/updateUi.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'updateUi.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(590, 547)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("微软雅黑")
|
||||
Dialog.setFont(font)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.btn_report = QtWidgets.QPushButton(Dialog)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("微软雅黑")
|
||||
font.setPointSize(30)
|
||||
self.btn_report.setFont(font)
|
||||
self.btn_report.setObjectName("btn_report")
|
||||
self.verticalLayout.addWidget(self.btn_report)
|
||||
self.progressBar = QtWidgets.QProgressBar(Dialog)
|
||||
self.progressBar.setProperty("value", 0)
|
||||
self.progressBar.setObjectName("progressBar")
|
||||
self.verticalLayout.addWidget(self.progressBar)
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.btn_start_update = QtWidgets.QPushButton(Dialog)
|
||||
self.btn_start_update.setObjectName("btn_start_update")
|
||||
self.horizontalLayout.addWidget(self.btn_start_update)
|
||||
self.btn_cancle = QtWidgets.QPushButton(Dialog)
|
||||
self.btn_cancle.setObjectName("btn_cancle")
|
||||
self.horizontalLayout.addWidget(self.btn_cancle)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||
self.btn_report.setText(_translate("Dialog", "更新程序"))
|
||||
self.btn_start_update.setText(_translate("Dialog", "开始更新"))
|
||||
self.btn_cancle.setText(_translate("Dialog", "取消更新"))
|
||||
Reference in New Issue
Block a user