mirror of
https://github.com/LC044/WeChatMsg
synced 2025-02-21 01:52:35 +08:00
全面删除对模拟器数据库的支持
This commit is contained in:
parent
858fc306b4
commit
4c6ec0ed3b
@ -1,7 +0,0 @@
|
|||||||
|
|
||||||
PRAGMA key = '10f35f1';
|
|
||||||
PRAGMA cipher_migrate;
|
|
||||||
ATTACH DATABASE './app/DataBase/Msg.db' AS Msg KEY '';
|
|
||||||
SELECT sqlcipher_export('Msg');
|
|
||||||
DETACH DATABASE Msg;
|
|
||||||
|
|
@ -1,584 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
@File : data.py
|
|
||||||
@Author : Shuaikang Zhou
|
|
||||||
@Time : 2023/1/5 0:11
|
|
||||||
@IDE : Pycharm
|
|
||||||
@Version : Python3.10
|
|
||||||
@comment : ···
|
|
||||||
"""
|
|
||||||
import hashlib
|
|
||||||
import os
|
|
||||||
import sqlite3
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
|
|
||||||
import requests
|
|
||||||
|
|
||||||
DB = None
|
|
||||||
cursor = None
|
|
||||||
lock = threading.Lock()
|
|
||||||
Type = {
|
|
||||||
1: '文本内容',
|
|
||||||
2: '位置信息',
|
|
||||||
3: '图片及视频',
|
|
||||||
34: '语音消息',
|
|
||||||
42: '名片(公众号名片)',
|
|
||||||
43: '图片及视频',
|
|
||||||
47: '表情包',
|
|
||||||
48: '定位信息',
|
|
||||||
49: '小程序链接',
|
|
||||||
10000: '撤回消息提醒',
|
|
||||||
1048625: '照片',
|
|
||||||
16777265: '链接',
|
|
||||||
285212721: '文件',
|
|
||||||
419430449: '微信转账',
|
|
||||||
436207665: '微信红包',
|
|
||||||
469762097: '微信红包',
|
|
||||||
11879048186: '位置共享',
|
|
||||||
}
|
|
||||||
|
|
||||||
Type0 = {
|
|
||||||
'1': '文字',
|
|
||||||
'3': '图片',
|
|
||||||
'43': '视频',
|
|
||||||
'-1879048185': '微信运动排行榜',
|
|
||||||
'5': '',
|
|
||||||
'47': '表情包',
|
|
||||||
'268445456': '撤回的消息',
|
|
||||||
'34': '语音',
|
|
||||||
'419430449': '转账',
|
|
||||||
'50': '语音电话',
|
|
||||||
'100001': '领取红包',
|
|
||||||
'10000': '消息已发出,但被对方拒收了。',
|
|
||||||
'822083633': '回复消息',
|
|
||||||
'922746929': '拍一拍',
|
|
||||||
'1090519089': '发送文件',
|
|
||||||
'318767153': '付款成功',
|
|
||||||
'436207665': '发红包',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def mkdir(path):
|
|
||||||
path = path.strip()
|
|
||||||
path = path.rstrip("\\")
|
|
||||||
if os.path.exists(path):
|
|
||||||
return False
|
|
||||||
os.makedirs(path)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
root_path = os.path.abspath('.')
|
|
||||||
mkdir(os.path.abspath('.') + '/app/DataBase')
|
|
||||||
mkdir(os.path.abspath('.') + '/app/data/emoji')
|
|
||||||
if os.path.exists('./app/DataBase/Msg.db'):
|
|
||||||
DB = sqlite3.connect("./app/DataBase/Msg.db", check_same_thread=False)
|
|
||||||
# '''创建游标'''
|
|
||||||
cursor = DB.cursor()
|
|
||||||
if os.path.exists('./Msg.db'):
|
|
||||||
DB = sqlite3.connect("./Msg.db", check_same_thread=False)
|
|
||||||
# '''创建游标'''
|
|
||||||
cursor = DB.cursor()
|
|
||||||
|
|
||||||
|
|
||||||
def is_db_exist() -> bool:
|
|
||||||
"""
|
|
||||||
判断数据库是否正常使用
|
|
||||||
"""
|
|
||||||
global DB
|
|
||||||
global cursor
|
|
||||||
if DB and cursor:
|
|
||||||
try:
|
|
||||||
sql = 'select * from userinfo where id=2'
|
|
||||||
cursor.execute(sql)
|
|
||||||
result = cursor.fetchone()
|
|
||||||
if result[2]:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
except Exception as e:
|
|
||||||
return False
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def init_database():
|
|
||||||
global DB
|
|
||||||
global cursor
|
|
||||||
if os.path.exists('./app/DataBase/Msg.db'):
|
|
||||||
DB = sqlite3.connect("./app/DataBase/Msg.db", check_same_thread=False)
|
|
||||||
# '''创建游标'''
|
|
||||||
cursor = DB.cursor()
|
|
||||||
if os.path.exists('./Msg.db'):
|
|
||||||
DB = sqlite3.connect("./Msg.db", check_same_thread=False)
|
|
||||||
# '''创建游标'''
|
|
||||||
cursor = DB.cursor()
|
|
||||||
|
|
||||||
|
|
||||||
def decrypt(db, key):
|
|
||||||
if not key:
|
|
||||||
print('缺少数据库密钥')
|
|
||||||
return False
|
|
||||||
if not db:
|
|
||||||
print('没有数据库文件')
|
|
||||||
return False
|
|
||||||
if is_db_exist():
|
|
||||||
print('/app/DataBase/Msg.db 已经存在')
|
|
||||||
return True
|
|
||||||
cmd = './sqlcipher-3.0.1/bin/sqlcipher-shell32.exe'
|
|
||||||
param = f"""
|
|
||||||
PRAGMA key = '{key}';
|
|
||||||
PRAGMA cipher_migrate;
|
|
||||||
ATTACH DATABASE './app/DataBase/Msg.db' AS Msg KEY '';
|
|
||||||
SELECT sqlcipher_export('Msg');
|
|
||||||
DETACH DATABASE Msg;
|
|
||||||
"""
|
|
||||||
with open('./app/data/config.txt', 'w') as f:
|
|
||||||
f.write(param)
|
|
||||||
p = os.system(f"{os.path.abspath('.')}{cmd} {db} < ./app/data/config.txt")
|
|
||||||
global DB
|
|
||||||
global cursor
|
|
||||||
DB = sqlite3.connect("./app/DataBase/Msg.db", check_same_thread=False)
|
|
||||||
# '''创建游标'''
|
|
||||||
cursor = DB.cursor()
|
|
||||||
|
|
||||||
|
|
||||||
def get_myinfo():
|
|
||||||
sql = 'select * from userinfo where id=2'
|
|
||||||
cursor.execute(sql)
|
|
||||||
result = cursor.fetchone()
|
|
||||||
return result[2]
|
|
||||||
|
|
||||||
|
|
||||||
def get_contacts():
|
|
||||||
sql = 'select * from rcontact'
|
|
||||||
cursor.execute(sql)
|
|
||||||
result = cursor.fetchall()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def get_rconversation():
|
|
||||||
sql = '''
|
|
||||||
select msgCount,username,unReadCount,chatmode,status,isSend,conversationTime,msgType,digest,digestUser,hasTrunc,attrflag
|
|
||||||
from rconversation
|
|
||||||
where chatmode=1 or chatmode=0 and (msgType='1' or msgType='3' or msgType='47')
|
|
||||||
order by msgCount desc
|
|
||||||
'''
|
|
||||||
'''order by conversationTime desc'''
|
|
||||||
cursor.execute(sql)
|
|
||||||
result = cursor.fetchall()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def timestamp2str(timestamp):
|
|
||||||
# t2 = 1586102400
|
|
||||||
s_l = time.localtime(timestamp / 1000)
|
|
||||||
ts = time.strftime("%Y/%m/%d", s_l)
|
|
||||||
# print(ts)
|
|
||||||
return ts
|
|
||||||
|
|
||||||
|
|
||||||
def get_conRemark(username):
|
|
||||||
try:
|
|
||||||
lock.acquire(True)
|
|
||||||
sql = 'select conRemark,nickname from rcontact where username=?'
|
|
||||||
cursor.execute(sql, [username])
|
|
||||||
result = cursor.fetchone()
|
|
||||||
if result:
|
|
||||||
if result[0]:
|
|
||||||
return result[0]
|
|
||||||
else:
|
|
||||||
return result[1]
|
|
||||||
except:
|
|
||||||
time.sleep(0.1)
|
|
||||||
sql = 'select conRemark,nickname from rcontact where username=?'
|
|
||||||
cursor.execute(sql, [username])
|
|
||||||
result = cursor.fetchone()
|
|
||||||
if result:
|
|
||||||
if result[0]:
|
|
||||||
return result[0]
|
|
||||||
else:
|
|
||||||
return result[1]
|
|
||||||
finally:
|
|
||||||
lock.release()
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def get_nickname(username):
|
|
||||||
sql = 'select nickname,alias from rcontact where username=?'
|
|
||||||
cursor.execute(sql, [username])
|
|
||||||
result = cursor.fetchone()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def avatar_md5(wxid):
|
|
||||||
m = hashlib.md5()
|
|
||||||
# 参数必须是byte类型,否则报Unicode-objects must be encoded before hashing错误
|
|
||||||
m.update(bytes(wxid.encode('utf-8')))
|
|
||||||
return m.hexdigest()
|
|
||||||
|
|
||||||
|
|
||||||
def get_avator(wxid):
|
|
||||||
if wxid == None:
|
|
||||||
return os.path.join(root_path, '/app/data/icons/default_avatar.svg')
|
|
||||||
wxid = str(wxid)
|
|
||||||
avatar = avatar_md5(wxid)
|
|
||||||
path = os.path.join(root_path, 'app', 'data', 'avatar', avatar[:2], avatar[2:4])
|
|
||||||
# avatar_path + avatar[:2] + '/' + avatar[2:4]
|
|
||||||
for root, dirs, files in os.walk(path):
|
|
||||||
for file in files:
|
|
||||||
if avatar in file:
|
|
||||||
avatar = file
|
|
||||||
break
|
|
||||||
return os.path.join(path, avatar)
|
|
||||||
# return f'''{path}/{avatar}'''
|
|
||||||
# return f'''{path}/user_{avatar}.png'''
|
|
||||||
|
|
||||||
|
|
||||||
def get_message(wxid, num):
|
|
||||||
sql = '''
|
|
||||||
select * from message
|
|
||||||
where talker = ?
|
|
||||||
order by createTime desc
|
|
||||||
limit ?,100
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [wxid, num * 100])
|
|
||||||
return cursor.fetchall()
|
|
||||||
|
|
||||||
|
|
||||||
def get_text_by_num(wxid, num):
|
|
||||||
sql = '''
|
|
||||||
SELECT content,strftime('%Y-%m-%d',createTime/1000,'unixepoch','localtime') as days
|
|
||||||
from message
|
|
||||||
where talker = ? and type=1
|
|
||||||
order by days
|
|
||||||
'''
|
|
||||||
'''group by days'''
|
|
||||||
cursor.execute(sql, [wxid])
|
|
||||||
return cursor.fetchall()
|
|
||||||
|
|
||||||
|
|
||||||
def search_send_message(start_time, end_time):
|
|
||||||
start_time = '2022-1-1 00:00:00'
|
|
||||||
end_time = '2023-1-1 00:00:00'
|
|
||||||
start = time.mktime(time.strptime(start_time, '%Y-%m-%d %H:%M:%S'))
|
|
||||||
end = time.mktime(time.strptime(end_time, '%Y-%m-%d %H:%M:%S'))
|
|
||||||
sql = '''
|
|
||||||
select count(*) from message
|
|
||||||
where createTime >? and createTime < ? and isSend=0 and talker like '%wxid%';
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [start * 1000, end * 1000])
|
|
||||||
return cursor.fetchone()
|
|
||||||
|
|
||||||
|
|
||||||
def clearImagePath(imgpath):
|
|
||||||
path = imgpath.split('/')
|
|
||||||
newPath = '/'.join(path[:-1]) + '/' + path[-1][3:] + '.jpg'
|
|
||||||
if os.path.exists(newPath):
|
|
||||||
return newPath
|
|
||||||
newPath = '/'.join(path[:-1]) + '/' + path[-1][3:] + '.png'
|
|
||||||
if os.path.exists(newPath):
|
|
||||||
return newPath
|
|
||||||
newPath = '/'.join(path[:-1]) + '/' + path[-1] + 'hd'
|
|
||||||
if os.path.exists(newPath):
|
|
||||||
return newPath
|
|
||||||
return imgpath
|
|
||||||
|
|
||||||
|
|
||||||
def get_all_message(wxid):
|
|
||||||
sql = '''
|
|
||||||
select * from message
|
|
||||||
where talker = ?
|
|
||||||
order by createTime
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [wxid])
|
|
||||||
return cursor.fetchall()
|
|
||||||
|
|
||||||
|
|
||||||
def get_emoji(imgPath):
|
|
||||||
newPath = f"{os.path.abspath('.')}/app/data/emoji/{imgPath}"
|
|
||||||
if os.path.exists(newPath):
|
|
||||||
return newPath
|
|
||||||
else:
|
|
||||||
sql = '''
|
|
||||||
select cdnUrl
|
|
||||||
from EmojiInfo
|
|
||||||
where md5=?
|
|
||||||
'''
|
|
||||||
try:
|
|
||||||
cursor.execute(sql, [imgPath])
|
|
||||||
result = cursor.fetchone()
|
|
||||||
download_emoji(newPath, result[0])
|
|
||||||
except sqlite3.ProgrammingError as e:
|
|
||||||
print(e, imgPath)
|
|
||||||
return False
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def download_emoji(imgPath, url):
|
|
||||||
if not url:
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
resp = requests.get(url)
|
|
||||||
with open(imgPath, 'wb') as f:
|
|
||||||
f.write(resp.content)
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
return imgPath
|
|
||||||
|
|
||||||
|
|
||||||
def get_chatroom_displayname(chatroom, username):
|
|
||||||
sql = 'select memberlist,displayname from chatroom where chatroomname =?'
|
|
||||||
cursor.execute(sql, [chatroom])
|
|
||||||
result = cursor.fetchone()
|
|
||||||
wxids = result[0].split(';')
|
|
||||||
names = result[1].split('、')
|
|
||||||
id = wxids.index(username)
|
|
||||||
print(result[0])
|
|
||||||
print(wxids)
|
|
||||||
for i in wxids:
|
|
||||||
print(get_conRemark(i))
|
|
||||||
return names[id]
|
|
||||||
|
|
||||||
|
|
||||||
def get_contacts():
|
|
||||||
sql = '''
|
|
||||||
select * from rcontact
|
|
||||||
where type=3 or type = 333
|
|
||||||
'''
|
|
||||||
cursor.execute(sql)
|
|
||||||
result = cursor.fetchall()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def send_nums(username):
|
|
||||||
sql = '''
|
|
||||||
select count(*) from message
|
|
||||||
where talker = ? and isSend=1
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [username])
|
|
||||||
return cursor.fetchone()[0]
|
|
||||||
|
|
||||||
|
|
||||||
def recv_nums(username):
|
|
||||||
sql = '''
|
|
||||||
select count(*) from message
|
|
||||||
where talker = ? and isSend=0
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [username])
|
|
||||||
return cursor.fetchone()[0]
|
|
||||||
|
|
||||||
|
|
||||||
def get_imgPath(imgPath):
|
|
||||||
sql = '''
|
|
||||||
select bigImgPath from ImgInfo2
|
|
||||||
where thumbImgPath = ?;
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [imgPath])
|
|
||||||
return cursor.fetchone()[0]
|
|
||||||
|
|
||||||
|
|
||||||
def get_text(username):
|
|
||||||
sql = '''
|
|
||||||
select content from message
|
|
||||||
where talker=? and type=1
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [username])
|
|
||||||
result = cursor.fetchall()
|
|
||||||
return ''.join(map(lambda x: x[0], result))
|
|
||||||
|
|
||||||
|
|
||||||
def msg_type_num(username):
|
|
||||||
sql = '''
|
|
||||||
select type,count(*) from message
|
|
||||||
where talker = ?
|
|
||||||
group by type
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [username])
|
|
||||||
return cursor.fetchall()
|
|
||||||
|
|
||||||
|
|
||||||
def get_msg_start_time(username):
|
|
||||||
sql = '''
|
|
||||||
select strftime('%Y-%m-%d %H:%M:%S',createTime/1000,'unixepoch','localtime') from message
|
|
||||||
where talker = ?
|
|
||||||
order by msgId
|
|
||||||
limit 1
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [username])
|
|
||||||
return cursor.fetchone()[0]
|
|
||||||
|
|
||||||
|
|
||||||
def get_msg_end_time(username):
|
|
||||||
sql = '''
|
|
||||||
select strftime('%Y-%m-%d %H:%M:%S',createTime/1000,'unixepoch','localtime') from message
|
|
||||||
where talker = ?
|
|
||||||
order by msgId desc
|
|
||||||
limit 1
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [username])
|
|
||||||
try:
|
|
||||||
return cursor.fetchone()[0]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_msg_by_days(username, year='2022'):
|
|
||||||
sql = '''
|
|
||||||
SELECT strftime('%Y-%m-%d',createTime/1000,'unixepoch','localtime') as days,count(msgId)
|
|
||||||
from message
|
|
||||||
where talker = ? and strftime('%Y',createTime/1000,'unixepoch','localtime') = ?
|
|
||||||
group by days
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [username, year])
|
|
||||||
result = cursor.fetchall()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def get_msg_by_day(username):
|
|
||||||
sql = '''
|
|
||||||
SELECT strftime('%Y-%m-%d',createTime/1000,'unixepoch','localtime') as days,count(msgId)
|
|
||||||
from message
|
|
||||||
where talker = ?
|
|
||||||
group by days
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [username])
|
|
||||||
result = cursor.fetchall()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def get_msg_by_month(username, year='2022'):
|
|
||||||
sql = '''
|
|
||||||
SELECT strftime('%Y-%m',createTime/1000,'unixepoch','localtime') as days,count(msgId)
|
|
||||||
from message
|
|
||||||
where talker = ? and strftime('%Y',createTime/1000,'unixepoch','localtime') = ?
|
|
||||||
group by days
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [username, year])
|
|
||||||
result = cursor.fetchall()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def get_msg_by_hour(username):
|
|
||||||
sql = '''
|
|
||||||
SELECT strftime('%H:00',createTime/1000,'unixepoch','localtime') as days,count(msgId)
|
|
||||||
from message
|
|
||||||
where talker = ?
|
|
||||||
group by days
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [username])
|
|
||||||
result = cursor.fetchall()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def get_sport():
|
|
||||||
sql = '''
|
|
||||||
SELECT createTime,content,strftime('%Y-%m-%d',createTime/1000,'unixepoch','localtime') as months
|
|
||||||
from message
|
|
||||||
where talker = 'gh_43f2581f6fd6'
|
|
||||||
'''
|
|
||||||
cursor.execute(sql)
|
|
||||||
result = cursor.fetchall()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def get_myInfo():
|
|
||||||
sql = '''
|
|
||||||
select value from userinfo
|
|
||||||
where id = 4
|
|
||||||
'''
|
|
||||||
cursor.execute(sql)
|
|
||||||
name = cursor.fetchone()[0]
|
|
||||||
sql = '''
|
|
||||||
select value from userinfo
|
|
||||||
where id = 5
|
|
||||||
'''
|
|
||||||
cursor.execute(sql)
|
|
||||||
email = cursor.fetchone()[0]
|
|
||||||
sql = '''
|
|
||||||
select value from userinfo
|
|
||||||
where id = 6
|
|
||||||
'''
|
|
||||||
cursor.execute(sql)
|
|
||||||
tel = cursor.fetchone()[0]
|
|
||||||
sql = '''
|
|
||||||
select value from userinfo
|
|
||||||
where id = 9
|
|
||||||
'''
|
|
||||||
cursor.execute(sql)
|
|
||||||
QQ = cursor.fetchone()[0]
|
|
||||||
sql = '''
|
|
||||||
select value from userinfo
|
|
||||||
where id = 42
|
|
||||||
'''
|
|
||||||
cursor.execute(sql)
|
|
||||||
wxid = cursor.fetchone()[0]
|
|
||||||
sql = '''
|
|
||||||
select value from userinfo
|
|
||||||
where id = 12291
|
|
||||||
'''
|
|
||||||
cursor.execute(sql)
|
|
||||||
signature = cursor.fetchone()[0]
|
|
||||||
sql = '''
|
|
||||||
select value from userinfo
|
|
||||||
where id = 12292
|
|
||||||
'''
|
|
||||||
cursor.execute(sql)
|
|
||||||
city = cursor.fetchone()[0]
|
|
||||||
sql = '''
|
|
||||||
select value from userinfo
|
|
||||||
where id = 12293
|
|
||||||
'''
|
|
||||||
cursor.execute(sql)
|
|
||||||
province = cursor.fetchone()[0]
|
|
||||||
return {
|
|
||||||
'name': name,
|
|
||||||
'username': wxid,
|
|
||||||
'city': city,
|
|
||||||
'province': province,
|
|
||||||
'email': email,
|
|
||||||
'QQ': QQ,
|
|
||||||
'signature': signature,
|
|
||||||
'tel': tel,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def search_Latest_chat_time(wxid):
|
|
||||||
# 查找聊天最晚的消息
|
|
||||||
sql = '''
|
|
||||||
SELECT strftime('%H:%M:%S',createTime/1000,'unixepoch','localtime') as t,content,strftime('%Y-%m-%d %H:%M:%S',createTime/1000,'unixepoch','localtime')
|
|
||||||
from message
|
|
||||||
where talker = ? and t>'00:00:00' and t<'05:00:00' and type=1
|
|
||||||
order by t desc
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [wxid])
|
|
||||||
result = cursor.fetchall()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def search_emoji(wxid):
|
|
||||||
# 查找聊天最晚的消息
|
|
||||||
sql = '''
|
|
||||||
SELECT imgPath,strftime('%Y-%m-%d %H:%M:%S',createTime/1000,'unixepoch','localtime') as t,count(imgPath)
|
|
||||||
from message
|
|
||||||
where talker = ? and t>'2022-01-01 00:00:00' and t<'2022-12-31 00::00:00' and type=47 and isSend=0
|
|
||||||
group by content
|
|
||||||
order by count(imgPath) desc
|
|
||||||
'''
|
|
||||||
cursor.execute(sql, [wxid])
|
|
||||||
result = cursor.fetchall()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
wxid = 'wxid_8piw6sb4hvfm22'
|
|
||||||
# wxid = 'wxid_wt2vsktnu4z022'
|
|
||||||
# emotion_analysis(wxid)
|
|
||||||
t = search_Latest_chat_time(wxid)
|
|
||||||
print(t[0])
|
|
||||||
d = get_msg_by_days(wxid)
|
|
||||||
print(len(d))
|
|
||||||
e = search_emoji(wxid)
|
|
||||||
print(e)
|
|
||||||
p = get_emoji(e[1][0])
|
|
||||||
print(p)
|
|
@ -1,6 +0,0 @@
|
|||||||
import sys
|
|
||||||
from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QFileDialog
|
|
||||||
from PyQt5.Qt import QPixmap, QPoint, Qt, QPainter, QIcon
|
|
||||||
from PyQt5.QtCore import QSize
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
|
||||||
from PyQt5.QtGui import QImageReader
|
|
Binary file not shown.
Before Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.0 KiB |
Binary file not shown.
Before Width: | Height: | Size: 543 KiB |
Binary file not shown.
Before Width: | Height: | Size: 678 KiB |
Binary file not shown.
Before Width: | Height: | Size: 405 KiB |
@ -1,9 +0,0 @@
|
|||||||
from ui import MainDemo
|
|
||||||
from config import *
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
box = MainDemo()
|
|
||||||
box.show()
|
|
||||||
app.exec_()
|
|
@ -1,157 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from .config import *
|
|
||||||
|
|
||||||
|
|
||||||
class ImageBox(QWidget):
|
|
||||||
def __init__(self):
|
|
||||||
super(ImageBox, self).__init__()
|
|
||||||
self.img = None
|
|
||||||
self.scaled_img = None
|
|
||||||
self.point = QPoint(100, 100)
|
|
||||||
self.start_pos = None
|
|
||||||
self.end_pos = None
|
|
||||||
self.left_click = False
|
|
||||||
self.scale = 1
|
|
||||||
|
|
||||||
def init_ui(self):
|
|
||||||
self.setWindowTitle("ImageBox")
|
|
||||||
|
|
||||||
def set_image(self, img_path):
|
|
||||||
"""
|
|
||||||
open image file
|
|
||||||
:param img_path: image file path
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# img = QImageReader(img_path)
|
|
||||||
# img.setScaledSize(QSize(self.size().width(), self.size().height()))
|
|
||||||
# img = img.read()
|
|
||||||
self.img = QPixmap(img_path)
|
|
||||||
# print(self.img.size(),self.img.size().width(),self.img.size().height())
|
|
||||||
self.scaled_img = self.img
|
|
||||||
# print(img_size)
|
|
||||||
img_size = self.scaled_img.size()
|
|
||||||
x = min(500, max((1000 - img_size.width()) // 2, 0))
|
|
||||||
y = min(300, max((600 - img_size.height()) // 2 - 60, 0))
|
|
||||||
# print(x,y)
|
|
||||||
self.point = QPoint(x, y)
|
|
||||||
|
|
||||||
def paintEvent(self, e):
|
|
||||||
"""
|
|
||||||
receive paint events
|
|
||||||
:param e: QPaintEvent
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self.scaled_img:
|
|
||||||
painter = QPainter()
|
|
||||||
painter.begin(self)
|
|
||||||
painter.scale(self.scale, self.scale)
|
|
||||||
painter.drawPixmap(self.point, self.scaled_img)
|
|
||||||
painter.end()
|
|
||||||
|
|
||||||
def wheelEvent(self, event):
|
|
||||||
angle = event.angleDelta() / 8 # 返回QPoint对象,为滚轮转过的数值,单位为1/8度
|
|
||||||
angleY = angle.y()
|
|
||||||
# 获取当前鼠标相对于view的位置
|
|
||||||
if angleY > 0:
|
|
||||||
self.scale *= 1.1
|
|
||||||
else: # 滚轮下滚
|
|
||||||
self.scale *= 0.9
|
|
||||||
self.adjustSize()
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def mouseMoveEvent(self, e):
|
|
||||||
"""
|
|
||||||
mouse move events for the widget
|
|
||||||
:param e: QMouseEvent
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self.left_click:
|
|
||||||
self.end_pos = e.pos() - self.start_pos
|
|
||||||
self.point = self.point + self.end_pos
|
|
||||||
self.start_pos = e.pos()
|
|
||||||
self.repaint()
|
|
||||||
|
|
||||||
def mousePressEvent(self, e):
|
|
||||||
"""
|
|
||||||
mouse press events for the widget
|
|
||||||
:param e: QMouseEvent
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if e.button() == Qt.LeftButton:
|
|
||||||
self.left_click = True
|
|
||||||
self.start_pos = e.pos()
|
|
||||||
|
|
||||||
def mouseReleaseEvent(self, e):
|
|
||||||
"""
|
|
||||||
mouse release events for the widget
|
|
||||||
:param e: QMouseEvent
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if e.button() == Qt.LeftButton:
|
|
||||||
self.left_click = False
|
|
||||||
|
|
||||||
|
|
||||||
class MainDemo(QWidget):
|
|
||||||
def __init__(self):
|
|
||||||
super(MainDemo, self).__init__()
|
|
||||||
|
|
||||||
self.setWindowTitle("Image Viewer")
|
|
||||||
self.setFixedSize(1000, 600)
|
|
||||||
self.setWindowIcon(QIcon('./app/data/icons/logo.svg'))
|
|
||||||
self.zoom_in = QPushButton("")
|
|
||||||
self.zoom_in.clicked.connect(self.large_click)
|
|
||||||
self.zoom_in.setFixedSize(30, 30)
|
|
||||||
in_icon = QIcon("./app/ImageBox/icons/zoom_in.jpg")
|
|
||||||
self.zoom_in.setIcon(in_icon)
|
|
||||||
self.zoom_in.setIconSize(QSize(30, 30))
|
|
||||||
|
|
||||||
self.zoom_out = QPushButton("")
|
|
||||||
self.zoom_out.clicked.connect(self.small_click)
|
|
||||||
self.zoom_out.setFixedSize(30, 30)
|
|
||||||
out_icon = QIcon("./app/ImageBox/icons/zoom_out.jpg")
|
|
||||||
self.zoom_out.setIcon(out_icon)
|
|
||||||
self.zoom_out.setIconSize(QSize(30, 30))
|
|
||||||
|
|
||||||
w = QWidget(self)
|
|
||||||
layout = QHBoxLayout()
|
|
||||||
layout.addWidget(self.zoom_in)
|
|
||||||
layout.addWidget(self.zoom_out)
|
|
||||||
layout.setAlignment(Qt.AlignLeft)
|
|
||||||
w.setLayout(layout)
|
|
||||||
w.setFixedSize(550, 50)
|
|
||||||
|
|
||||||
self.box = ImageBox()
|
|
||||||
self.box.resize(500, 300)
|
|
||||||
|
|
||||||
layout = QVBoxLayout()
|
|
||||||
layout.addWidget(w)
|
|
||||||
layout.addWidget(self.box)
|
|
||||||
self.setLayout(layout)
|
|
||||||
|
|
||||||
def open_image(self):
|
|
||||||
"""
|
|
||||||
select image file and open it
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
img_name, _ = QFileDialog.getOpenFileName(self, "Open Image File", "*.jpg;;*.png;;*.jpeg")
|
|
||||||
self.box.set_image(img_name)
|
|
||||||
|
|
||||||
def large_click(self):
|
|
||||||
"""
|
|
||||||
used to enlarge image
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self.box.scale < 2:
|
|
||||||
self.box.scale += 0.1
|
|
||||||
self.box.adjustSize()
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def small_click(self):
|
|
||||||
"""
|
|
||||||
used to reduce image
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self.box.scale > 0.1:
|
|
||||||
self.box.scale -= 0.2
|
|
||||||
self.box.adjustSize()
|
|
||||||
self.update()
|
|
@ -1,18 +0,0 @@
|
|||||||
from PyQt5.QtGui import QIcon
|
|
||||||
|
|
||||||
|
|
||||||
class Icon:
|
|
||||||
Default_avatar_path = './app/data/icons/default_avatar.svg'
|
|
||||||
MainWindow_Icon = QIcon('./app/data/icons/logo.svg')
|
|
||||||
Default_avatar = QIcon(Default_avatar_path)
|
|
||||||
Output = QIcon('./app/data/icons/output.svg')
|
|
||||||
Back = QIcon('./app/data/icons/back.svg')
|
|
||||||
ToDocx = QIcon('app/data/icons/word.svg')
|
|
||||||
ToCSV = QIcon('app/data/icons/csv.svg')
|
|
||||||
ToHTML = QIcon('app/data/icons/html.svg')
|
|
||||||
Chat_Icon = QIcon('./app/data/icons/chat.svg')
|
|
||||||
Contact_Icon = QIcon('./app/data/icons/contact.svg')
|
|
||||||
MyInfo_Icon = QIcon('./app/data/icons/myinfo.svg')
|
|
||||||
Annual_Report_Icon = QIcon('./app/data/icons/annual_report.svg')
|
|
||||||
Analysis_Icon = QIcon('./app/data/icons/analysis.svg')
|
|
||||||
Emotion_Icon = QIcon('./app/data/icons/emotion.svg')
|
|
@ -1,17 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
@File : __init__.py.py
|
|
||||||
@Author : Shuaikang Zhou
|
|
||||||
@Time : 2022/12/13 14:19
|
|
||||||
@IDE : Pycharm
|
|
||||||
@Version : Python3.10
|
|
||||||
@comment : ···
|
|
||||||
"""
|
|
||||||
# from .ICON import Icon
|
|
||||||
# from .chat import chat
|
|
||||||
from app.Ui import mainview
|
|
||||||
# 文件__init__.py
|
|
||||||
# from login import login
|
|
||||||
from app.Ui.decrypt import decrypt
|
|
||||||
|
|
||||||
__all__ = ["decrypt", 'mainview', 'chat']
|
|
@ -1,9 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
@File : __init__.py.py
|
|
||||||
@Author : Shuaikang Zhou
|
|
||||||
@Time : 2022/12/13 20:33
|
|
||||||
@IDE : Pycharm
|
|
||||||
@Version : Python3.10
|
|
||||||
@comment : ···
|
|
||||||
"""
|
|
@ -1,499 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
@File : chat.py
|
|
||||||
@Author : Shuaikang Zhou
|
|
||||||
@Time : 2022/12/13 17:07
|
|
||||||
@IDE : Pycharm
|
|
||||||
@Version : Python3.10
|
|
||||||
@comment : 聊天窗口
|
|
||||||
"""
|
|
||||||
import time
|
|
||||||
import traceback
|
|
||||||
from typing import Dict
|
|
||||||
|
|
||||||
import xmltodict
|
|
||||||
from PIL import Image
|
|
||||||
from PyQt5.QtCore import *
|
|
||||||
from PyQt5.QtGui import *
|
|
||||||
from PyQt5.QtWidgets import *
|
|
||||||
|
|
||||||
from app.components.Button_Contact import ContactUi
|
|
||||||
from app.log import logger, log
|
|
||||||
from .chatUi import *
|
|
||||||
from ...DataBase import data
|
|
||||||
from ...ImageBox.ui import MainDemo
|
|
||||||
|
|
||||||
|
|
||||||
class ChatController(QWidget, Ui_Form):
|
|
||||||
exitSignal = pyqtSignal()
|
|
||||||
urlSignal = pyqtSignal(QUrl)
|
|
||||||
|
|
||||||
# username = ''
|
|
||||||
|
|
||||||
def __init__(self, me, parent=None):
|
|
||||||
super(ChatController, self).__init__(parent)
|
|
||||||
self.chatroomFlag = None
|
|
||||||
self.ta_avatar = None
|
|
||||||
self.setupUi(self)
|
|
||||||
self.message = self.message_2
|
|
||||||
self.frame = self.frame_2
|
|
||||||
self.scrollAreaWidgetContents = self.scrollAreaWidgetContents_2
|
|
||||||
self.label_remark = self.label_remark_2
|
|
||||||
self.textEdit = self.textEdit_2
|
|
||||||
self.setWindowTitle('WeChat')
|
|
||||||
self.setWindowIcon(QIcon('./app/data/icon.png'))
|
|
||||||
self.initui()
|
|
||||||
self.Me = me
|
|
||||||
|
|
||||||
self.Thread = ChatMsg(self.Me.wxid, None)
|
|
||||||
self.Thread.isSend_signal.connect(self.showMsg)
|
|
||||||
self.Thread.okSignal.connect(self.setScrollBarPos)
|
|
||||||
|
|
||||||
self.contacts: Dict[str, ContactUi] = {}
|
|
||||||
self.last_btn = None
|
|
||||||
self.chat_flag = True
|
|
||||||
# self.showChat()
|
|
||||||
|
|
||||||
self.message.verticalScrollBar().valueChanged.connect(self.textbrower_verticalScrollBar)
|
|
||||||
self.show_flag = False
|
|
||||||
self.ta_username = None
|
|
||||||
self.last_pos = 0
|
|
||||||
self.last_msg_time = 0 # 上次信息的时间
|
|
||||||
self.last_talkerId = None
|
|
||||||
self.now_talkerId = None
|
|
||||||
self.showChat()
|
|
||||||
|
|
||||||
def initui(self):
|
|
||||||
self.qurl = QUrl('baidu.com')
|
|
||||||
# self.urlSignal.connect(self.hyperlink)
|
|
||||||
self.message.setOpenLinks(False)
|
|
||||||
self.message.setOpenExternalLinks(False)
|
|
||||||
# self.message.anchorClicked(self.hyperlink())
|
|
||||||
self.message.anchorClicked.connect(self.hyperlink)
|
|
||||||
self.btn_sendMsg_2.setToolTip('按Enter键发送,按Ctrl+Enter键换行')
|
|
||||||
|
|
||||||
def showChat(self):
|
|
||||||
"""
|
|
||||||
显示联系人界面
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self.show_flag:
|
|
||||||
return
|
|
||||||
self.show_flag = True
|
|
||||||
rconversations = data.get_rconversation()
|
|
||||||
# max_hight = max(len(rconversations) * 80, 680)
|
|
||||||
max_hight = max(len(rconversations) * 80, self.size().height())
|
|
||||||
|
|
||||||
self.scrollAreaWidgetContents.setGeometry(
|
|
||||||
QtCore.QRect(0, 0, 300, max_hight))
|
|
||||||
for i in range(len(rconversations)):
|
|
||||||
rconversation = rconversations[i]
|
|
||||||
username = rconversation[1]
|
|
||||||
# print('联系人:', i, rconversation)
|
|
||||||
pushButton_2 = ContactUi(self.scrollAreaWidgetContents, i, rconversation)
|
|
||||||
pushButton_2.setGeometry(QtCore.QRect(0, 80 * i, 300, 80))
|
|
||||||
pushButton_2.setLayoutDirection(QtCore.Qt.LeftToRight)
|
|
||||||
pushButton_2.clicked.connect(pushButton_2.show_msg)
|
|
||||||
pushButton_2.usernameSingal.connect(self.Chat)
|
|
||||||
self.contacts[username] = pushButton_2
|
|
||||||
|
|
||||||
def Chat(self, talkerId):
|
|
||||||
"""
|
|
||||||
聊天界面 点击联系人头像时候显示聊天数据
|
|
||||||
:param talkerId:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.now_talkerId = talkerId
|
|
||||||
# 把当前按钮设置为灰色
|
|
||||||
if self.last_talkerId and self.last_talkerId != talkerId:
|
|
||||||
print('对方账号:', self.last_talkerId)
|
|
||||||
self.contacts[self.last_talkerId].setStyleSheet(
|
|
||||||
"QPushButton {background-color: rgb(220,220,220);}"
|
|
||||||
"QPushButton:hover{background-color: rgb(208,208,208);}\n"
|
|
||||||
)
|
|
||||||
self.last_talkerId = talkerId
|
|
||||||
self.contacts[talkerId].setStyleSheet(
|
|
||||||
"QPushButton {background-color: rgb(198,198,198);}"
|
|
||||||
"QPushButton:hover{background-color: rgb(209,209,209);}\n"
|
|
||||||
)
|
|
||||||
conRemark = self.contacts[talkerId].contact.conRemark
|
|
||||||
self.label_remark.setText(conRemark)
|
|
||||||
self.message.clear()
|
|
||||||
self.message.append(talkerId)
|
|
||||||
self.ta_username = talkerId
|
|
||||||
if '@chatroom' in talkerId:
|
|
||||||
self.chatroomFlag = True
|
|
||||||
else:
|
|
||||||
self.chatroomFlag = False
|
|
||||||
self.ta_avatar = self.contacts[talkerId].contact.avatar_path
|
|
||||||
self.textEdit.setFocus()
|
|
||||||
self.Thread.ta_u = talkerId
|
|
||||||
self.Thread.msg_id = 0
|
|
||||||
self.Thread.start()
|
|
||||||
# 创建新的线程用于显示聊天记录
|
|
||||||
|
|
||||||
def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
|
|
||||||
print("closed")
|
|
||||||
self.exitSignal.emit()
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def textbrower_verticalScrollBar(self, pos):
|
|
||||||
"""
|
|
||||||
滚动条到0之后自动更新聊天记录
|
|
||||||
:param pos:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# print(pos)
|
|
||||||
if pos > 0:
|
|
||||||
return
|
|
||||||
self.last_pos = self.message.verticalScrollBar().maximum()
|
|
||||||
self.Thread.start()
|
|
||||||
|
|
||||||
def setScrollBarPos(self, pos):
|
|
||||||
"""
|
|
||||||
将滚动条位置设置为上次看到的地方
|
|
||||||
:param pos:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
pos = self.message.verticalScrollBar().maximum() - self.last_pos
|
|
||||||
|
|
||||||
print(pos)
|
|
||||||
self.message.verticalScrollBar().setValue(pos)
|
|
||||||
|
|
||||||
def check_time(self, msg_time):
|
|
||||||
"""
|
|
||||||
判断两次聊天时间是否大于五分钟
|
|
||||||
超过五分钟就显示时间
|
|
||||||
:param msg_time:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
dt = msg_time - self.last_msg_time
|
|
||||||
# print(msg_time)
|
|
||||||
if abs(dt // 1000) >= 300:
|
|
||||||
s_l = time.localtime(msg_time / 1000)
|
|
||||||
ts = time.strftime("%Y-%m-%d %H:%M", s_l)
|
|
||||||
html = '''
|
|
||||||
<table align="center" style="vertical-align: middle;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>%s</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>''' % (ts)
|
|
||||||
# print(html)
|
|
||||||
self.last_msg_time = msg_time
|
|
||||||
self.message.insertHtml(html)
|
|
||||||
|
|
||||||
@log
|
|
||||||
def showMsg(self, message):
|
|
||||||
"""
|
|
||||||
显示聊天消息
|
|
||||||
:param message:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
msgId = message[0]
|
|
||||||
# print(msgId, type(msgId))
|
|
||||||
self.message.moveCursor(self.message.textCursor().Start)
|
|
||||||
ta_username = message[7]
|
|
||||||
msgType = str(message[2])
|
|
||||||
isSend = message[4]
|
|
||||||
content = message[8]
|
|
||||||
imgPath = message[9]
|
|
||||||
msg_time = message[6]
|
|
||||||
self.check_time(msg_time)
|
|
||||||
|
|
||||||
if msgType == '1':
|
|
||||||
# return
|
|
||||||
self.show_text(isSend, content)
|
|
||||||
elif msgType == '3':
|
|
||||||
# return
|
|
||||||
self.show_img(isSend, imgPath, content)
|
|
||||||
elif msgType == '47':
|
|
||||||
# return
|
|
||||||
self.show_emoji(isSend, imgPath, content)
|
|
||||||
elif msgType == '268445456':
|
|
||||||
self.show_recall_information(content)
|
|
||||||
elif msgType == '922746929':
|
|
||||||
self.pat_a_pat(content)
|
|
||||||
# self.message.moveCursor(self.message.textCursor().End)
|
|
||||||
|
|
||||||
@log
|
|
||||||
def pat_a_pat(self, content):
|
|
||||||
try:
|
|
||||||
pat_data = xmltodict.parse(content)
|
|
||||||
pat_data = pat_data['msg']['appmsg']['patMsg']['records']['record']
|
|
||||||
fromUser = pat_data['fromUser']
|
|
||||||
pattedUser = pat_data['pattedUser']
|
|
||||||
template = pat_data['template']
|
|
||||||
template = ''.join(template.split('${pattedusername@textstatusicon}'))
|
|
||||||
template = ''.join(template.split('${fromusername@textstatusicon}'))
|
|
||||||
template = template.replace(f'${{{fromUser}}}', data.get_conRemark(fromUser))
|
|
||||||
template = template.replace(f'${{{pattedUser}}}', data.get_conRemark(pattedUser))
|
|
||||||
print(template)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
template = '糟糕!出错了。'
|
|
||||||
|
|
||||||
html = '''
|
|
||||||
<table align="center" style="vertical-align: middle;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>%s</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>''' % template
|
|
||||||
self.message.insertHtml(html)
|
|
||||||
|
|
||||||
@log
|
|
||||||
def show_recall_information(self, content):
|
|
||||||
html = '''
|
|
||||||
<table align="center" style="vertical-align: middle;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>%s</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>''' % content
|
|
||||||
self.message.insertHtml(html)
|
|
||||||
|
|
||||||
@log
|
|
||||||
def show_emoji(self, isSend, imagePath, content):
|
|
||||||
imgPath = data.get_emoji(imagePath)
|
|
||||||
if not imgPath:
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
image = Image.open(imgPath)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"\nshow_emoji is error,here are details:\n{traceback.format_exc()}")
|
|
||||||
print(e)
|
|
||||||
return
|
|
||||||
imagePixmap = image.size # 宽高像素
|
|
||||||
# 设置最大宽度
|
|
||||||
if imagePixmap[0] < 150:
|
|
||||||
size = ""
|
|
||||||
else:
|
|
||||||
size = '''height="150" width="150"'''
|
|
||||||
html = '''
|
|
||||||
<td style="border: 1px #000000 solid;" height="150">
|
|
||||||
<img src="{0}" {1} >
|
|
||||||
</td>
|
|
||||||
'''.format(imgPath, size)
|
|
||||||
style = 'vertical-align: top'
|
|
||||||
if isSend:
|
|
||||||
self.right(html, style=style)
|
|
||||||
else:
|
|
||||||
if self.chatroomFlag:
|
|
||||||
username = content.split(':')[0]
|
|
||||||
self.chatroom_left(html, username=username, style=style)
|
|
||||||
self.left(html, style=style)
|
|
||||||
|
|
||||||
@log
|
|
||||||
def show_img(self, isSend, imgPath, content):
|
|
||||||
'THUMBNAIL_DIRPATH://th_29cd0f0ca87652943be9ede365aabeaa'
|
|
||||||
# imgPath = imgPath.split('th_')[1]
|
|
||||||
imgPath = data.get_imgPath(imgPath)
|
|
||||||
imgPath = f'./app/data/image2/{imgPath[0:2]}/{imgPath[2:4]}/{imgPath}'
|
|
||||||
html = '''
|
|
||||||
<td style="border: 1px #000000 solid;" height="150">
|
|
||||||
<a href="%s" target="_blank" height="150">
|
|
||||||
<img herf= "baidu.com" align="right" src="%s" style="max-height:100%%" height="200">
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
''' % (imgPath, imgPath)
|
|
||||||
style = 'vertical-align: top'
|
|
||||||
if isSend:
|
|
||||||
self.right(html, style=style)
|
|
||||||
else:
|
|
||||||
if self.chatroomFlag:
|
|
||||||
username = content.split(':')[0]
|
|
||||||
self.chatroom_left(html, username=username, style=style)
|
|
||||||
else:
|
|
||||||
self.left(html, style=style)
|
|
||||||
|
|
||||||
@log
|
|
||||||
def show_text(self, isSend, content):
|
|
||||||
if isSend:
|
|
||||||
html = '''
|
|
||||||
<td style="background-color: #9EEA6A;border-radius: 40px;"> %s </td>
|
|
||||||
''' % content
|
|
||||||
self.right(html)
|
|
||||||
else:
|
|
||||||
if self.chatroomFlag:
|
|
||||||
# print(content)
|
|
||||||
'wxid_mv4jjhc0w0w521:'
|
|
||||||
username = content.split(':')[0]
|
|
||||||
msg = ''.join(content.split(':')[1:])
|
|
||||||
# avatar = data.get_avator(username)
|
|
||||||
html = '''
|
|
||||||
<td max-width = 300 style="background-color: #fff;border-radius: 4px;">
|
|
||||||
%s
|
|
||||||
</td>
|
|
||||||
''' % (msg)
|
|
||||||
# self.left(html, avatar=avatar)
|
|
||||||
self.chatroom_left(html, username=username)
|
|
||||||
else:
|
|
||||||
html = '''
|
|
||||||
<td max-width = 300 style="background-color: #fff;border-radius: 4px;"> %s </td>
|
|
||||||
''' % (content)
|
|
||||||
self.left(html)
|
|
||||||
|
|
||||||
def hyperlink(self, url: QUrl):
|
|
||||||
"""
|
|
||||||
超链接,点击之后放大显示图片
|
|
||||||
:param url:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
path = data.clearImagePath(url.path())
|
|
||||||
print(url.path(), path)
|
|
||||||
self.imagebox = MainDemo()
|
|
||||||
self.imagebox.show()
|
|
||||||
self.imagebox.box.set_image(path)
|
|
||||||
|
|
||||||
def right(self, content, style='vertical-align: middle'):
|
|
||||||
html = '''
|
|
||||||
<div>
|
|
||||||
<table align="right" style="%s;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
%s
|
|
||||||
<td>:</td>
|
|
||||||
<td style="border: 1px #000000 solid"><img align="right" src="%s" width="45" height="45"/></td>
|
|
||||||
<td width="15"></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
''' % (style, content, self.Me.avatar_path)
|
|
||||||
# print('总的HTML')
|
|
||||||
# print(html)
|
|
||||||
self.message.insertHtml(html)
|
|
||||||
|
|
||||||
def left(self, content, avatar=None, style='vertical-align: middle'):
|
|
||||||
if not avatar:
|
|
||||||
avatar = self.ta_avatar
|
|
||||||
if self.chatroomFlag == 5:
|
|
||||||
try:
|
|
||||||
username, msg = content.split('\n')
|
|
||||||
avatar = data.get_avator(username)
|
|
||||||
html = '''
|
|
||||||
<div>
|
|
||||||
<table align="left" style="%s;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td width="15"></td>
|
|
||||||
<td rowspan="2" style="border: 1px #000000 solid"><img align="right" src="%s" width="45" height="45"/></td>
|
|
||||||
<td>:</td>
|
|
||||||
<td>:</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td width="15"></td>
|
|
||||||
<td>:</td>
|
|
||||||
%s
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
''' % (style, avatar, msg)
|
|
||||||
except:
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
html = '''
|
|
||||||
<div>
|
|
||||||
<table align="left" style="%s;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td width="15"></td>
|
|
||||||
<td style="border: 1px #000000 solid"><img align="right" src="%s" width="45" height="45"/></td>
|
|
||||||
<td>:</td>
|
|
||||||
%s
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
''' % (style, avatar, content)
|
|
||||||
self.message.insertHtml(html)
|
|
||||||
|
|
||||||
def chatroom_left(self, content, username, style='vertical-align: middle'):
|
|
||||||
# if username:
|
|
||||||
avatar = data.get_avator(username)
|
|
||||||
# conRemark = data.get_conRemark(username)
|
|
||||||
conRemark = data.get_conRemark(username)
|
|
||||||
html = '''
|
|
||||||
<div>
|
|
||||||
<table align="left" style="%s;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td width="15"></td>
|
|
||||||
<td rowspan="2" style="border: 1px #000000 solid"><img align="right" src="%s" width="45" height="45"/></td>
|
|
||||||
<td></td>
|
|
||||||
<td>%s</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td width="15"></td>
|
|
||||||
<td>:</td>
|
|
||||||
%s
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
''' % (style, avatar, conRemark, content)
|
|
||||||
self.message.insertHtml(html)
|
|
||||||
|
|
||||||
def destroy_me(self):
|
|
||||||
"""注销账户"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ChatMsg(QThread):
|
|
||||||
"""
|
|
||||||
多线程显示信息
|
|
||||||
"""
|
|
||||||
isSend_signal = pyqtSignal(tuple)
|
|
||||||
okSignal = pyqtSignal(int)
|
|
||||||
|
|
||||||
def __init__(self, my_u, ta_u, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.sec = 2 # 默认1000秒
|
|
||||||
self.my_u = my_u
|
|
||||||
self.ta_u = ta_u
|
|
||||||
self.my_avatar = data.get_avator(my_u)
|
|
||||||
self.msg_id = 0
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self.ta_avatar = data.get_avator(self.ta_u)
|
|
||||||
messages = data.get_message(self.ta_u, self.msg_id)
|
|
||||||
# messages.reverse()
|
|
||||||
for message in messages:
|
|
||||||
self.isSend_signal.emit(message)
|
|
||||||
self.msg_id += 1
|
|
||||||
self.okSignal.emit(1)
|
|
||||||
|
|
||||||
|
|
||||||
class myTextEdit(QtWidgets.QTextEdit): # 继承 原本组件
|
|
||||||
sendSignal = pyqtSignal(str)
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
QtWidgets.QTextEdit.__init__(self, parent)
|
|
||||||
self.parent = parent
|
|
||||||
_translate = QtCore.QCoreApplication.translate
|
|
||||||
self.setHtml(_translate("Dialog",
|
|
||||||
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" "
|
|
||||||
"\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
|
|
||||||
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
|
|
||||||
"p, li { white-space: pre-wrap; }\n"
|
|
||||||
"</style></head><body style=\" font-family:\'SimSun\'; font-size:15pt; "
|
|
||||||
"font-weight:400; font-style:normal;\">\n"
|
|
||||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; "
|
|
||||||
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br "
|
|
||||||
"/></p></body></html>"))
|
|
||||||
|
|
||||||
def keyPressEvent(self, event):
|
|
||||||
QtWidgets.QTextEdit.keyPressEvent(self, event)
|
|
||||||
if event.key() == Qt.Key_Return: # 如果是Enter 按钮
|
|
||||||
modifiers = event.modifiers()
|
|
||||||
if modifiers == Qt.ControlModifier:
|
|
||||||
print('success press ctrl+enter key', self.toPlainText())
|
|
||||||
self.append('\0')
|
|
||||||
return
|
|
||||||
self.sendSignal.emit(self.toPlainText())
|
|
||||||
print('success press enter key', self.toPlainText())
|
|
@ -1,157 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'chatUi.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_Form(object):
|
|
||||||
def setupUi(self, Form):
|
|
||||||
Form.setObjectName("Form")
|
|
||||||
Form.resize(878, 720)
|
|
||||||
self.horizontalLayout = QtWidgets.QHBoxLayout(Form)
|
|
||||||
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.horizontalLayout.setSpacing(0)
|
|
||||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
|
||||||
self.scrollArea_2 = QtWidgets.QScrollArea(Form)
|
|
||||||
self.scrollArea_2.setEnabled(True)
|
|
||||||
self.scrollArea_2.setMaximumSize(QtCore.QSize(325, 150000))
|
|
||||||
self.scrollArea_2.setAutoFillBackground(False)
|
|
||||||
self.scrollArea_2.setFrameShape(QtWidgets.QFrame.NoFrame)
|
|
||||||
self.scrollArea_2.setFrameShadow(QtWidgets.QFrame.Raised)
|
|
||||||
self.scrollArea_2.setMidLineWidth(0)
|
|
||||||
self.scrollArea_2.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
|
|
||||||
self.scrollArea_2.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
|
||||||
self.scrollArea_2.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContentsOnFirstShow)
|
|
||||||
self.scrollArea_2.setWidgetResizable(False)
|
|
||||||
self.scrollArea_2.setObjectName("scrollArea_2")
|
|
||||||
self.scrollAreaWidgetContents_2 = QtWidgets.QWidget()
|
|
||||||
self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 300, 12000))
|
|
||||||
self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2")
|
|
||||||
self.pushButton_3 = QtWidgets.QPushButton(self.scrollAreaWidgetContents_2)
|
|
||||||
self.pushButton_3.setGeometry(QtCore.QRect(0, 0, 300, 80))
|
|
||||||
self.pushButton_3.setLayoutDirection(QtCore.Qt.LeftToRight)
|
|
||||||
self.pushButton_3.setAutoFillBackground(False)
|
|
||||||
self.pushButton_3.setText("")
|
|
||||||
self.pushButton_3.setIconSize(QtCore.QSize(80, 80))
|
|
||||||
self.pushButton_3.setObjectName("pushButton_3")
|
|
||||||
self.label_2 = QtWidgets.QLabel(self.scrollAreaWidgetContents_2)
|
|
||||||
self.label_2.setGeometry(QtCore.QRect(220, 10, 72, 15))
|
|
||||||
self.label_2.setObjectName("label_2")
|
|
||||||
self.scrollArea_2.setWidget(self.scrollAreaWidgetContents_2)
|
|
||||||
self.horizontalLayout.addWidget(self.scrollArea_2)
|
|
||||||
self.frame_2 = QtWidgets.QFrame(Form)
|
|
||||||
self.frame_2.setMinimumSize(QtCore.QSize(500, 500))
|
|
||||||
self.frame_2.setStyleSheet("background-color: #F5F5F5;")
|
|
||||||
self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
|
||||||
self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
|
|
||||||
self.frame_2.setObjectName("frame_2")
|
|
||||||
self.verticalLayout = QtWidgets.QVBoxLayout(self.frame_2)
|
|
||||||
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.verticalLayout.setSpacing(0)
|
|
||||||
self.verticalLayout.setObjectName("verticalLayout")
|
|
||||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
|
|
||||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
|
||||||
self.label_remark_2 = QtWidgets.QLabel(self.frame_2)
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setPointSize(12)
|
|
||||||
self.label_remark_2.setFont(font)
|
|
||||||
self.label_remark_2.setText("")
|
|
||||||
self.label_remark_2.setObjectName("label_remark_2")
|
|
||||||
self.horizontalLayout_3.addWidget(self.label_remark_2)
|
|
||||||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
|
||||||
self.horizontalLayout_3.addItem(spacerItem)
|
|
||||||
self.toolButton_2 = QtWidgets.QToolButton(self.frame_2)
|
|
||||||
self.toolButton_2.setObjectName("toolButton_2")
|
|
||||||
self.horizontalLayout_3.addWidget(self.toolButton_2)
|
|
||||||
self.verticalLayout.addLayout(self.horizontalLayout_3)
|
|
||||||
self.line_5 = QtWidgets.QFrame(self.frame_2)
|
|
||||||
self.line_5.setFrameShape(QtWidgets.QFrame.HLine)
|
|
||||||
self.line_5.setFrameShadow(QtWidgets.QFrame.Sunken)
|
|
||||||
self.line_5.setObjectName("line_5")
|
|
||||||
self.verticalLayout.addWidget(self.line_5)
|
|
||||||
self.message_2 = QtWidgets.QTextBrowser(self.frame_2)
|
|
||||||
self.message_2.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
|
|
||||||
self.message_2.setStyleSheet("background-color: #F5F5F5;")
|
|
||||||
self.message_2.setObjectName("message_2")
|
|
||||||
self.verticalLayout.addWidget(self.message_2)
|
|
||||||
self.line_6 = QtWidgets.QFrame(self.frame_2)
|
|
||||||
self.line_6.setFrameShape(QtWidgets.QFrame.HLine)
|
|
||||||
self.line_6.setFrameShadow(QtWidgets.QFrame.Sunken)
|
|
||||||
self.line_6.setObjectName("line_6")
|
|
||||||
self.verticalLayout.addWidget(self.line_6)
|
|
||||||
self.textEdit_2 = QtWidgets.QTextEdit(self.frame_2)
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setPointSize(15)
|
|
||||||
self.textEdit_2.setFont(font)
|
|
||||||
self.textEdit_2.setAutoFillBackground(False)
|
|
||||||
self.textEdit_2.setStyleSheet("background-color: #F5F5F5;")
|
|
||||||
self.textEdit_2.setFrameShape(QtWidgets.QFrame.NoFrame)
|
|
||||||
self.textEdit_2.setOverwriteMode(False)
|
|
||||||
self.textEdit_2.setTabStopWidth(80)
|
|
||||||
self.textEdit_2.setAcceptRichText(True)
|
|
||||||
self.textEdit_2.setCursorWidth(1)
|
|
||||||
self.textEdit_2.setTextInteractionFlags(QtCore.Qt.TextEditorInteraction)
|
|
||||||
self.textEdit_2.setObjectName("textEdit_2")
|
|
||||||
self.verticalLayout.addWidget(self.textEdit_2)
|
|
||||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
|
|
||||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
|
||||||
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
|
||||||
self.horizontalLayout_2.addItem(spacerItem1)
|
|
||||||
self.btn_sendMsg_2 = QtWidgets.QPushButton(self.frame_2)
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setFamily("黑体")
|
|
||||||
font.setPointSize(15)
|
|
||||||
font.setBold(False)
|
|
||||||
font.setWeight(50)
|
|
||||||
self.btn_sendMsg_2.setFont(font)
|
|
||||||
self.btn_sendMsg_2.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
|
|
||||||
self.btn_sendMsg_2.setMouseTracking(False)
|
|
||||||
self.btn_sendMsg_2.setAutoFillBackground(False)
|
|
||||||
self.btn_sendMsg_2.setStyleSheet("QPushButton {\n"
|
|
||||||
" background-color:rgb(233,233,233);\n"
|
|
||||||
" padding: 10px;\n"
|
|
||||||
" color:rgb(5,180,104);}\n"
|
|
||||||
" QPushButton:hover{\n"
|
|
||||||
" background-color:rgb(198,198,198)}\n"
|
|
||||||
" ")
|
|
||||||
self.btn_sendMsg_2.setIconSize(QtCore.QSize(40, 40))
|
|
||||||
self.btn_sendMsg_2.setCheckable(False)
|
|
||||||
self.btn_sendMsg_2.setAutoDefault(True)
|
|
||||||
self.btn_sendMsg_2.setObjectName("btn_sendMsg_2")
|
|
||||||
self.horizontalLayout_2.addWidget(self.btn_sendMsg_2)
|
|
||||||
self.horizontalLayout_2.setStretch(0, 7)
|
|
||||||
self.horizontalLayout_2.setStretch(1, 2)
|
|
||||||
self.verticalLayout.addLayout(self.horizontalLayout_2)
|
|
||||||
self.verticalLayout.setStretch(0, 2)
|
|
||||||
self.verticalLayout.setStretch(1, 2)
|
|
||||||
self.verticalLayout.setStretch(2, 60)
|
|
||||||
self.verticalLayout.setStretch(3, 2)
|
|
||||||
self.verticalLayout.setStretch(4, 2)
|
|
||||||
self.verticalLayout.setStretch(5, 1)
|
|
||||||
self.horizontalLayout.addWidget(self.frame_2)
|
|
||||||
|
|
||||||
self.retranslateUi(Form)
|
|
||||||
QtCore.QMetaObject.connectSlotsByName(Form)
|
|
||||||
|
|
||||||
def retranslateUi(self, Form):
|
|
||||||
_translate = QtCore.QCoreApplication.translate
|
|
||||||
Form.setWindowTitle(_translate("Form", "Form"))
|
|
||||||
self.label_2.setText(_translate("Form", "TextLabel"))
|
|
||||||
self.toolButton_2.setText(_translate("Form", "..."))
|
|
||||||
self.textEdit_2.setHtml(_translate("Form",
|
|
||||||
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
|
|
||||||
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
|
|
||||||
"p, li { white-space: pre-wrap; }\n"
|
|
||||||
"</style></head><body style=\" font-family:\'SimSun\'; font-size:15pt; font-weight:400; font-style:normal;\">\n"
|
|
||||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"> </p>\n"
|
|
||||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"> </p>\n"
|
|
||||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"> </p>\n"
|
|
||||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"> </p></body></html>"))
|
|
||||||
self.btn_sendMsg_2.setText(_translate("Form", "发送"))
|
|
@ -1,140 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'form.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_Form(object):
|
|
||||||
def setupUi(self, Form):
|
|
||||||
Form.setObjectName("Form")
|
|
||||||
Form.resize(878, 720)
|
|
||||||
self.horizontalLayout = QtWidgets.QHBoxLayout(Form)
|
|
||||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
|
||||||
self.scrollArea_2 = QtWidgets.QScrollArea(Form)
|
|
||||||
self.scrollArea_2.setEnabled(True)
|
|
||||||
self.scrollArea_2.setMaximumSize(QtCore.QSize(325, 150000))
|
|
||||||
self.scrollArea_2.setAutoFillBackground(False)
|
|
||||||
self.scrollArea_2.setFrameShape(QtWidgets.QFrame.WinPanel)
|
|
||||||
self.scrollArea_2.setFrameShadow(QtWidgets.QFrame.Raised)
|
|
||||||
self.scrollArea_2.setMidLineWidth(0)
|
|
||||||
self.scrollArea_2.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
|
|
||||||
self.scrollArea_2.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
|
||||||
self.scrollArea_2.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContentsOnFirstShow)
|
|
||||||
self.scrollArea_2.setWidgetResizable(False)
|
|
||||||
self.scrollArea_2.setObjectName("scrollArea_2")
|
|
||||||
self.scrollAreaWidgetContents_2 = QtWidgets.QWidget()
|
|
||||||
self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 300, 12000))
|
|
||||||
self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2")
|
|
||||||
self.pushButton_3 = QtWidgets.QPushButton(self.scrollAreaWidgetContents_2)
|
|
||||||
self.pushButton_3.setGeometry(QtCore.QRect(0, 0, 300, 80))
|
|
||||||
self.pushButton_3.setLayoutDirection(QtCore.Qt.LeftToRight)
|
|
||||||
self.pushButton_3.setAutoFillBackground(False)
|
|
||||||
self.pushButton_3.setText("")
|
|
||||||
self.pushButton_3.setIconSize(QtCore.QSize(80, 80))
|
|
||||||
self.pushButton_3.setObjectName("pushButton_3")
|
|
||||||
self.label_2 = QtWidgets.QLabel(self.scrollAreaWidgetContents_2)
|
|
||||||
self.label_2.setGeometry(QtCore.QRect(220, 10, 72, 15))
|
|
||||||
self.label_2.setObjectName("label_2")
|
|
||||||
self.scrollArea_2.setWidget(self.scrollAreaWidgetContents_2)
|
|
||||||
self.horizontalLayout.addWidget(self.scrollArea_2)
|
|
||||||
self.frame_2 = QtWidgets.QFrame(Form)
|
|
||||||
self.frame_2.setMinimumSize(QtCore.QSize(500, 500))
|
|
||||||
self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
|
||||||
self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
|
|
||||||
self.frame_2.setObjectName("frame_2")
|
|
||||||
self.verticalLayout = QtWidgets.QVBoxLayout(self.frame_2)
|
|
||||||
self.verticalLayout.setObjectName("verticalLayout")
|
|
||||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
|
|
||||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
|
||||||
self.label_remark_2 = QtWidgets.QLabel(self.frame_2)
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setPointSize(12)
|
|
||||||
self.label_remark_2.setFont(font)
|
|
||||||
self.label_remark_2.setText("")
|
|
||||||
self.label_remark_2.setObjectName("label_remark_2")
|
|
||||||
self.horizontalLayout_3.addWidget(self.label_remark_2)
|
|
||||||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
|
||||||
self.horizontalLayout_3.addItem(spacerItem)
|
|
||||||
self.toolButton_2 = QtWidgets.QToolButton(self.frame_2)
|
|
||||||
self.toolButton_2.setObjectName("toolButton_2")
|
|
||||||
self.horizontalLayout_3.addWidget(self.toolButton_2)
|
|
||||||
self.verticalLayout.addLayout(self.horizontalLayout_3)
|
|
||||||
self.line_4 = QtWidgets.QFrame(self.frame_2)
|
|
||||||
self.line_4.setLineWidth(6)
|
|
||||||
self.line_4.setFrameShape(QtWidgets.QFrame.VLine)
|
|
||||||
self.line_4.setFrameShadow(QtWidgets.QFrame.Sunken)
|
|
||||||
self.line_4.setObjectName("line_4")
|
|
||||||
self.verticalLayout.addWidget(self.line_4)
|
|
||||||
self.line_5 = QtWidgets.QFrame(self.frame_2)
|
|
||||||
self.line_5.setFrameShape(QtWidgets.QFrame.HLine)
|
|
||||||
self.line_5.setFrameShadow(QtWidgets.QFrame.Sunken)
|
|
||||||
self.line_5.setObjectName("line_5")
|
|
||||||
self.verticalLayout.addWidget(self.line_5)
|
|
||||||
self.message_2 = QtWidgets.QTextBrowser(self.frame_2)
|
|
||||||
self.message_2.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
|
|
||||||
self.message_2.setStyleSheet("background-color: #F5F5F5;")
|
|
||||||
self.message_2.setObjectName("message_2")
|
|
||||||
self.verticalLayout.addWidget(self.message_2)
|
|
||||||
self.textEdit_2 = QtWidgets.QTextEdit(self.frame_2)
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setPointSize(15)
|
|
||||||
self.textEdit_2.setFont(font)
|
|
||||||
self.textEdit_2.setTabStopWidth(80)
|
|
||||||
self.textEdit_2.setCursorWidth(1)
|
|
||||||
self.textEdit_2.setObjectName("textEdit_2")
|
|
||||||
self.verticalLayout.addWidget(self.textEdit_2)
|
|
||||||
self.line_6 = QtWidgets.QFrame(self.frame_2)
|
|
||||||
self.line_6.setFrameShape(QtWidgets.QFrame.HLine)
|
|
||||||
self.line_6.setFrameShadow(QtWidgets.QFrame.Sunken)
|
|
||||||
self.line_6.setObjectName("line_6")
|
|
||||||
self.verticalLayout.addWidget(self.line_6)
|
|
||||||
self.btn_sendMsg_2 = QtWidgets.QPushButton(self.frame_2)
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setFamily("黑体")
|
|
||||||
font.setPointSize(15)
|
|
||||||
font.setBold(False)
|
|
||||||
font.setWeight(50)
|
|
||||||
self.btn_sendMsg_2.setFont(font)
|
|
||||||
self.btn_sendMsg_2.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
|
|
||||||
self.btn_sendMsg_2.setMouseTracking(False)
|
|
||||||
self.btn_sendMsg_2.setAutoFillBackground(False)
|
|
||||||
self.btn_sendMsg_2.setStyleSheet("QPushButton {\n"
|
|
||||||
" background-color: #f0f0f0;\n"
|
|
||||||
" \n"
|
|
||||||
" padding: 10px;\n"
|
|
||||||
" color:rgb(5,180,104);\n"
|
|
||||||
"}")
|
|
||||||
self.btn_sendMsg_2.setIconSize(QtCore.QSize(40, 40))
|
|
||||||
self.btn_sendMsg_2.setCheckable(False)
|
|
||||||
self.btn_sendMsg_2.setAutoDefault(True)
|
|
||||||
self.btn_sendMsg_2.setObjectName("btn_sendMsg_2")
|
|
||||||
self.verticalLayout.addWidget(self.btn_sendMsg_2)
|
|
||||||
self.verticalLayout.setStretch(0, 1)
|
|
||||||
self.verticalLayout.setStretch(2, 3)
|
|
||||||
self.verticalLayout.setStretch(3, 20)
|
|
||||||
self.verticalLayout.setStretch(4, 1)
|
|
||||||
self.verticalLayout.setStretch(6, 1)
|
|
||||||
self.horizontalLayout.addWidget(self.frame_2)
|
|
||||||
|
|
||||||
self.retranslateUi(Form)
|
|
||||||
QtCore.QMetaObject.connectSlotsByName(Form)
|
|
||||||
|
|
||||||
def retranslateUi(self, Form):
|
|
||||||
_translate = QtCore.QCoreApplication.translate
|
|
||||||
Form.setWindowTitle(_translate("Form", "Form"))
|
|
||||||
self.label_2.setText(_translate("Form", "TextLabel"))
|
|
||||||
self.toolButton_2.setText(_translate("Form", "..."))
|
|
||||||
self.textEdit_2.setHtml(_translate("Form",
|
|
||||||
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
|
|
||||||
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
|
|
||||||
"p, li { white-space: pre-wrap; }\n"
|
|
||||||
"</style></head><body style=\" font-family:\'SimSun\'; font-size:15pt; font-weight:400; font-style:normal;\">\n"
|
|
||||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p></body></html>"))
|
|
||||||
self.btn_sendMsg_2.setText(_translate("Form", "发送"))
|
|
Binary file not shown.
@ -1,9 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
@File : __init__.py.py
|
|
||||||
@Author : Shuaikang Zhou
|
|
||||||
@Time : 2022/12/13 20:33
|
|
||||||
@IDE : Pycharm
|
|
||||||
@Version : Python3.10
|
|
||||||
@comment : ···
|
|
||||||
"""
|
|
@ -1,153 +0,0 @@
|
|||||||
import sys
|
|
||||||
|
|
||||||
from PyQt5.QtCore import *
|
|
||||||
from PyQt5.QtGui import *
|
|
||||||
from PyQt5.QtWebEngineWidgets import QWebEngineView
|
|
||||||
from PyQt5.QtWidgets import *
|
|
||||||
|
|
||||||
QCoreApplication.setAttribute(Qt.AA_UseSoftwareOpenGL)
|
|
||||||
from . import charts
|
|
||||||
|
|
||||||
|
|
||||||
class AnalysisController(QWidget):
|
|
||||||
def __init__(self, username, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.ta_username = username
|
|
||||||
# self.setWindowTitle('数据分析')
|
|
||||||
# self.setWindowIcon(QIcon('./app/data/icon.png'))
|
|
||||||
|
|
||||||
# self.setWindowFlag(Qt.FramelessWindowHint)
|
|
||||||
self.setStyleSheet('''QWidget{background-color:rgb(255, 255, 255);}''')
|
|
||||||
self.center()
|
|
||||||
self.setAttribute(Qt.WA_AttributeCount)
|
|
||||||
self.label_01()
|
|
||||||
self.isStart = False
|
|
||||||
|
|
||||||
def center(self): # 定义一个函数使得窗口居中显示
|
|
||||||
# 获取屏幕坐标系
|
|
||||||
screen = QDesktopWidget().screenGeometry()
|
|
||||||
# 获取窗口坐标系
|
|
||||||
size = self.geometry()
|
|
||||||
newLeft = (screen.width() - size.width()) / 2
|
|
||||||
newTop = (screen.height() - size.height()) / 2
|
|
||||||
self.move(int(newLeft), int(newTop))
|
|
||||||
|
|
||||||
def label_01(self):
|
|
||||||
self.label = QLabel(self)
|
|
||||||
size = self.geometry()
|
|
||||||
self.label.setGeometry(size.width() // 2, self.height() // 2, 100, 100)
|
|
||||||
self.label.setToolTip("这是一个标签")
|
|
||||||
self.m_movie()
|
|
||||||
|
|
||||||
def m_movie(self):
|
|
||||||
movie = QMovie("./app/data/bg.gif")
|
|
||||||
self.label.setMovie(movie)
|
|
||||||
movie.start()
|
|
||||||
|
|
||||||
def initUI(self):
|
|
||||||
self.label.setVisible(False)
|
|
||||||
# self.setStyleSheet('''QWidget{background-color:rgb(240, 240, 240);}''')
|
|
||||||
|
|
||||||
main_box = QVBoxLayout(self)
|
|
||||||
main_box.setContentsMargins(0, 0, 0, 0)
|
|
||||||
main_box.setSpacing(0)
|
|
||||||
|
|
||||||
self.browser1 = QWebEngineView()
|
|
||||||
self.browser1.load(QUrl('file:///data/聊天统计/title.html'))
|
|
||||||
self.browser1.setMinimumSize(810, 60)
|
|
||||||
self.browser1.setStyleSheet('''QWidget{background-color:rgb(240, 240, 240);}''')
|
|
||||||
self.browser2 = QWebEngineView()
|
|
||||||
self.browser2.load(QUrl('file:///data/聊天统计/wordcloud.html'))
|
|
||||||
self.browser2.setStyleSheet('''QWidget{background-color:rgb(240, 240, 240);}''')
|
|
||||||
# self.browser2.setMinimumWidth(810)
|
|
||||||
self.browser2.setMinimumSize(810, 810)
|
|
||||||
self.browser3 = QWebEngineView()
|
|
||||||
self.browser3.load(QUrl('file:///data/聊天统计/time.html'))
|
|
||||||
self.browser3.setMaximumSize(810, 100)
|
|
||||||
self.browser3.adjustSize()
|
|
||||||
self.browser4 = QWebEngineView()
|
|
||||||
self.browser4.load(QUrl('http://www.baidu.com'))
|
|
||||||
self.browser4.resize(800, 600)
|
|
||||||
self.browser5 = QWebEngineView()
|
|
||||||
self.browser5.load(QUrl('file:///data/聊天统计/chat_session.html'))
|
|
||||||
self.browser6 = QWebEngineView()
|
|
||||||
self.browser6.load(QUrl('file:///data/聊天统计/sports.html'))
|
|
||||||
self.browser7 = QWebEngineView()
|
|
||||||
self.browser7.load(QUrl('file:///data/聊天统计/month_num.html'))
|
|
||||||
self.browser8 = QWebEngineView()
|
|
||||||
self.browser8.load(QUrl('file:///data/聊天统计/calendar.html'))
|
|
||||||
self.browser9 = QWebEngineView()
|
|
||||||
self.browser9.load(QUrl('file:///data/聊天统计/msg_type_rate.html'))
|
|
||||||
self.browser10 = QWebEngineView()
|
|
||||||
self.browser10.load(QUrl('file:///data/聊天统计/send_recv_rate.html'))
|
|
||||||
self.browser10.adjustSize()
|
|
||||||
# self.browser10.
|
|
||||||
main_box.addWidget(self.browser1)
|
|
||||||
|
|
||||||
self.scrollArea = QScrollArea()
|
|
||||||
self.scrollArea.setEnabled(True)
|
|
||||||
self.scrollArea.adjustSize()
|
|
||||||
|
|
||||||
scrollAreaContent = QWidget(self.scrollArea)
|
|
||||||
scrollAreaContent.setStyleSheet('''QWidget{background-color:rgb(240, 240, 240);}''')
|
|
||||||
Vlayout2 = QVBoxLayout()
|
|
||||||
Vlayout2.setContentsMargins(0, 0, 0, 0)
|
|
||||||
Vlayout2.setSpacing(0)
|
|
||||||
Vlayout2.addWidget(self.browser3)
|
|
||||||
Vlayout2.addWidget(self.browser2)
|
|
||||||
Vlayout2.addWidget(self.browser8)
|
|
||||||
Vlayout2.addWidget(self.browser6)
|
|
||||||
Vlayout2.addWidget(self.browser5)
|
|
||||||
Vlayout2.addWidget(self.browser7)
|
|
||||||
Vlayout2.addWidget(self.browser9)
|
|
||||||
Vlayout2.addWidget(self.browser10)
|
|
||||||
scrollAreaContent.setLayout(Vlayout2)
|
|
||||||
self.scrollArea.setWidget(scrollAreaContent)
|
|
||||||
main_box.addWidget(self.scrollArea)
|
|
||||||
main_box.setStretch(0, 1)
|
|
||||||
main_box.setStretch(1, 10)
|
|
||||||
self.setLayout(main_box)
|
|
||||||
|
|
||||||
def setBackground(self):
|
|
||||||
palette = QPalette()
|
|
||||||
pix = QPixmap("./app/data/bg.png")
|
|
||||||
pix = pix.scaled(self.width(), self.height(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation) # 自适应图片大小
|
|
||||||
palette.setBrush(self.backgroundRole(), QBrush(pix)) # 设置背景图片
|
|
||||||
# palette.setColor(self.backgroundRole(), QColor(192, 253, 123)) # 设置背景颜色
|
|
||||||
self.setPalette(palette)
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
if not self.isStart:
|
|
||||||
self.Thread = LoadData(self.ta_username)
|
|
||||||
self.Thread.okSignal.connect(self.initUI)
|
|
||||||
self.Thread.start()
|
|
||||||
self.isStart = True
|
|
||||||
|
|
||||||
|
|
||||||
class LoadData(QThread):
|
|
||||||
"""
|
|
||||||
发送信息线程
|
|
||||||
"""
|
|
||||||
okSignal = pyqtSignal(int)
|
|
||||||
|
|
||||||
def __init__(self, ta_u, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.ta_username = ta_u
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
charts.chat_start_endTime(self.ta_username)
|
|
||||||
charts.title(self.ta_username)
|
|
||||||
charts.send_recv_rate(self.ta_username)
|
|
||||||
charts.message_word_cloud(self.ta_username)
|
|
||||||
charts.msg_type_rate(self.ta_username)
|
|
||||||
charts.calendar_chart(self.ta_username)
|
|
||||||
charts.month_num(self.ta_username)
|
|
||||||
charts.sport(self.ta_username)
|
|
||||||
charts.chat_session(self.ta_username)
|
|
||||||
self.okSignal.emit(10)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
ex = MainWindow()
|
|
||||||
sys.exit(app.exec_())
|
|
Binary file not shown.
@ -1,539 +0,0 @@
|
|||||||
import os
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
import jieba
|
|
||||||
import pandas as pd
|
|
||||||
import xmltodict
|
|
||||||
from pyecharts import options as opts
|
|
||||||
from pyecharts.charts import Pie, WordCloud, Calendar, Bar, Line, Timeline, Grid
|
|
||||||
|
|
||||||
from app.log import logger, log
|
|
||||||
from ....DataBase import data
|
|
||||||
|
|
||||||
# from app.DataBase import data
|
|
||||||
|
|
||||||
data.mkdir(os.path.abspath('.') + '/data/聊天统计')
|
|
||||||
|
|
||||||
Type = {
|
|
||||||
'1': '文字',
|
|
||||||
'3': '图片',
|
|
||||||
'43': '视频',
|
|
||||||
'-1879048185': '微信运动排行榜',
|
|
||||||
'5': '',
|
|
||||||
'47': '表情包',
|
|
||||||
'268445456': '撤回消息',
|
|
||||||
'34': '语音',
|
|
||||||
'419430449': '转账',
|
|
||||||
'50': '语音电话',
|
|
||||||
'100001': '领取红包',
|
|
||||||
'10000': '消息已发出,但被对方拒收了。',
|
|
||||||
'822083633': '回复消息',
|
|
||||||
'922746929': '拍一拍',
|
|
||||||
'1090519089': '文件',
|
|
||||||
'318767153': '付款成功',
|
|
||||||
'436207665': '发红包',
|
|
||||||
'49': '分享链接'
|
|
||||||
}
|
|
||||||
charts_width = 800
|
|
||||||
charts_height = 450
|
|
||||||
wordcloud_width = 780
|
|
||||||
wordcloud_height = 720
|
|
||||||
|
|
||||||
|
|
||||||
@log
|
|
||||||
def send_recv_rate(username):
|
|
||||||
send_num = data.send_nums(username)
|
|
||||||
recv_num = data.recv_nums(username)
|
|
||||||
total_num = send_num + recv_num
|
|
||||||
print(send_num, recv_num)
|
|
||||||
c = (
|
|
||||||
Pie(init_opts=opts.InitOpts(
|
|
||||||
# bg_color='rgb(240,240,240)',
|
|
||||||
width=f"{charts_width}px",
|
|
||||||
height=f"{charts_height}px")
|
|
||||||
)
|
|
||||||
.add(
|
|
||||||
"",
|
|
||||||
[
|
|
||||||
('发送', send_num), ('接收', recv_num)
|
|
||||||
],
|
|
||||||
center=["40%", "50%"],
|
|
||||||
)
|
|
||||||
.set_global_opts(
|
|
||||||
title_opts=opts.TitleOpts(title=f"信息发送接收", subtitle=f"总计:{total_num}条消息", pos_bottom="0%"),
|
|
||||||
legend_opts=opts.LegendOpts(type_="scroll", pos_left="80%", orient="vertical"),
|
|
||||||
)
|
|
||||||
.set_series_opts(
|
|
||||||
label_opts=opts.LabelOpts(formatter="{b}:{d}%"),
|
|
||||||
)
|
|
||||||
.render("./data/聊天统计/send_recv_rate.html")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@log
|
|
||||||
def msg_type_rate(username):
|
|
||||||
type_data = data.msg_type_num(username)
|
|
||||||
type_data = sorted(type_data, key=lambda x: x[1], reverse=True)
|
|
||||||
data1 = type_data[:4]
|
|
||||||
data2 = sum(map(lambda x: x[1], type_data[4:]))
|
|
||||||
print(type_data)
|
|
||||||
new_data = []
|
|
||||||
for t in data1:
|
|
||||||
try:
|
|
||||||
new_data.append((Type[str(t[0])], t[1]))
|
|
||||||
except:
|
|
||||||
new_data.append(('未知类型', t[1]))
|
|
||||||
new_data.append(('其他', data2))
|
|
||||||
|
|
||||||
c = (
|
|
||||||
Pie(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px"))
|
|
||||||
.add(
|
|
||||||
"",
|
|
||||||
new_data
|
|
||||||
,
|
|
||||||
center=["40%", "50%"],
|
|
||||||
)
|
|
||||||
.set_global_opts(
|
|
||||||
title_opts=opts.TitleOpts(title=f"消息类型占比", pos_bottom="0%"),
|
|
||||||
legend_opts=opts.LegendOpts(type_="scroll", pos_left="80%", orient="vertical"),
|
|
||||||
)
|
|
||||||
.set_series_opts(
|
|
||||||
label_opts=opts.LabelOpts(formatter="{b}:{d}%"),
|
|
||||||
)
|
|
||||||
.render("./data/聊天统计/msg_type_rate.html")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@log
|
|
||||||
def message_word_cloud(username):
|
|
||||||
text = data.get_text(username)
|
|
||||||
total_msg_len = len(text)
|
|
||||||
word_list = jieba.cut(text)
|
|
||||||
# word = " ".join(word_list)
|
|
||||||
# print(word)
|
|
||||||
stopwords = set()
|
|
||||||
content = [line.strip() for line in open('./app/data/stopwords.txt', 'r', encoding='utf-8').readlines()]
|
|
||||||
stopwords.update(content)
|
|
||||||
wordcount = {}
|
|
||||||
for word in jieba.cut(text):
|
|
||||||
if len(word) > 1 and word not in stopwords:
|
|
||||||
wordcount[word] = wordcount.get(word, 0) + 1
|
|
||||||
text_data = sorted(wordcount.items(), key=lambda x: x[1], reverse=True)
|
|
||||||
if len(text_data) > 100:
|
|
||||||
text_data = text_data[:100]
|
|
||||||
# print(text_data)
|
|
||||||
(
|
|
||||||
WordCloud(init_opts=opts.InitOpts(width=f"{wordcloud_width}px", height=f"{wordcloud_height}px"))
|
|
||||||
.add(series_name="聊天文字", data_pair=text_data, word_size_range=[20, 100])
|
|
||||||
.set_global_opts(
|
|
||||||
title_opts=opts.TitleOpts(
|
|
||||||
title=f"词云图", subtitle=f"总计{total_msg_len}字",
|
|
||||||
title_textstyle_opts=opts.TextStyleOpts(font_size=23)
|
|
||||||
),
|
|
||||||
tooltip_opts=opts.TooltipOpts(is_show=True),
|
|
||||||
legend_opts=opts.LegendOpts(is_show=False)
|
|
||||||
)
|
|
||||||
.render("./data/聊天统计/wordcloud.html")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@log
|
|
||||||
def calendar_chart(username):
|
|
||||||
msg_data = data.get_msg_by_days(username, year='2022')
|
|
||||||
if not msg_data:
|
|
||||||
return False
|
|
||||||
min_ = min(map(lambda x: x[1], msg_data))
|
|
||||||
max_ = max(map(lambda x: x[1], msg_data))
|
|
||||||
c = (
|
|
||||||
Calendar(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px"))
|
|
||||||
.add(
|
|
||||||
"",
|
|
||||||
msg_data,
|
|
||||||
calendar_opts=opts.CalendarOpts(range_="2022")
|
|
||||||
)
|
|
||||||
.set_global_opts(
|
|
||||||
title_opts=opts.TitleOpts(title="2022年聊天情况"),
|
|
||||||
visualmap_opts=opts.VisualMapOpts(
|
|
||||||
max_=max_,
|
|
||||||
min_=min_,
|
|
||||||
orient="horizontal",
|
|
||||||
# is_piecewise=True,
|
|
||||||
# pos_top="200px",
|
|
||||||
pos_bottom="0px",
|
|
||||||
pos_left="0px",
|
|
||||||
),
|
|
||||||
legend_opts=opts.LegendOpts(is_show=False)
|
|
||||||
)
|
|
||||||
.render("./data/聊天统计/calendar.html")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@log
|
|
||||||
def month_num(username):
|
|
||||||
"""
|
|
||||||
每月聊天条数
|
|
||||||
"""
|
|
||||||
msg_data = data.get_msg_by_month(username, year='2022')
|
|
||||||
y_data = list(map(lambda x: x[1], msg_data))
|
|
||||||
x_axis = list(map(lambda x: x[0], msg_data))
|
|
||||||
c = (
|
|
||||||
Bar(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px"))
|
|
||||||
.add_xaxis(x_axis)
|
|
||||||
.add_yaxis("消息数量", y_data)
|
|
||||||
.set_global_opts(
|
|
||||||
title_opts=opts.TitleOpts(title="逐月统计", subtitle=None),
|
|
||||||
datazoom_opts=opts.DataZoomOpts(),
|
|
||||||
toolbox_opts=opts.ToolboxOpts(),
|
|
||||||
)
|
|
||||||
.render("./data/聊天统计/month_num.html")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@log
|
|
||||||
def chat_session(username):
|
|
||||||
msg_data = data.get_msg_by_hour(username)
|
|
||||||
x_axis = list(map(lambda x: x[0], msg_data))
|
|
||||||
y_data = list(map(lambda x: x[1], msg_data))
|
|
||||||
# print(x_axis)
|
|
||||||
# print(y_data)
|
|
||||||
# max_ = max(y_data)
|
|
||||||
c = (
|
|
||||||
Line(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px"))
|
|
||||||
.add_xaxis(xaxis_data=x_axis)
|
|
||||||
.add_yaxis(
|
|
||||||
series_name="聊天频率",
|
|
||||||
y_axis=y_data,
|
|
||||||
markpoint_opts=opts.MarkPointOpts(
|
|
||||||
data=[
|
|
||||||
opts.MarkPointItem(type_="max", name="最大值"),
|
|
||||||
opts.MarkPointItem(type_="min", name="最小值", value=int(10)),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
markline_opts=opts.MarkLineOpts(
|
|
||||||
data=[opts.MarkLineItem(type_="average", name="平均值")]
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.set_global_opts(
|
|
||||||
title_opts=opts.TitleOpts(title="聊天时段", subtitle=None),
|
|
||||||
# datazoom_opts=opts.DataZoomOpts(),
|
|
||||||
# toolbox_opts=opts.ToolboxOpts(),
|
|
||||||
)
|
|
||||||
.set_series_opts(
|
|
||||||
label_opts=opts.LabelOpts(
|
|
||||||
is_show=False
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.render("./data/聊天统计/chat_session.html")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@log
|
|
||||||
def sport(username):
|
|
||||||
sports = data.get_sport()
|
|
||||||
ranks = []
|
|
||||||
steps = []
|
|
||||||
date = []
|
|
||||||
for sport in sports:
|
|
||||||
try:
|
|
||||||
timestamp, content, t = sport
|
|
||||||
rank_data = xmltodict.parse(content)
|
|
||||||
sub_data = rank_data['msg']['appmsg']['hardwareinfo']['messagenodeinfo']
|
|
||||||
# print(sub_data)
|
|
||||||
# my_rank = sub_data['rankinfo']['rank']['rankdisplay']
|
|
||||||
# my_steps = int(sub_data['rankinfo']['score']['scoredisplay'])
|
|
||||||
# print(f'rank: {my_rank},steps: {my_steps}')
|
|
||||||
rank_view = rank_data['msg']['appmsg']['hardwareinfo']['rankview']['rankinfolist']['rankinfo']
|
|
||||||
for userinfo in rank_view:
|
|
||||||
username0 = userinfo['username']
|
|
||||||
if username0 == username:
|
|
||||||
rank_ta = int(userinfo['rank']['rankdisplay'])
|
|
||||||
steps_ta = int(userinfo['score']['scoredisplay'])
|
|
||||||
ranks.append(rank_ta)
|
|
||||||
steps.append(steps_ta)
|
|
||||||
date.append(t)
|
|
||||||
except:
|
|
||||||
logger.error(f"\nsport is error,here are details:\n{traceback.format_exc()}\n")
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
# todo 可能没有运动信息
|
|
||||||
df = pd.DataFrame({'ranks': ranks, 'score': steps, 'date': date}, index=date)
|
|
||||||
months = pd.date_range(date[0], date[-1], freq='M')
|
|
||||||
except:
|
|
||||||
months = []
|
|
||||||
tl = Timeline(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px"))
|
|
||||||
tl.add_schema(is_auto_play=True)
|
|
||||||
for i in range(len(months) - 1):
|
|
||||||
da = df[(months[i + 1].strftime("%Y-%m-%d") >= df['date']) & (df['date'] > months[i].strftime("%Y-%m-%d"))]
|
|
||||||
bar = (
|
|
||||||
Bar(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px"))
|
|
||||||
.add_xaxis(list(da['date']))
|
|
||||||
.add_yaxis(
|
|
||||||
"步数",
|
|
||||||
list(da['score']),
|
|
||||||
yaxis_index=1,
|
|
||||||
color="#d14a61",
|
|
||||||
)
|
|
||||||
.extend_axis(
|
|
||||||
yaxis=opts.AxisOpts(
|
|
||||||
name="步数",
|
|
||||||
type_="value",
|
|
||||||
# grid_index=0,
|
|
||||||
# min_=0,
|
|
||||||
# max_=250,
|
|
||||||
position="right",
|
|
||||||
axisline_opts=opts.AxisLineOpts(
|
|
||||||
linestyle_opts=opts.LineStyleOpts(color="#d14a61")
|
|
||||||
),
|
|
||||||
# axislabel_opts=opts.LabelOpts(formatter="{value} ml"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.extend_axis(
|
|
||||||
yaxis=opts.AxisOpts(
|
|
||||||
type_="value",
|
|
||||||
name="排名",
|
|
||||||
# min_=0,
|
|
||||||
# max_=25,
|
|
||||||
position="left",
|
|
||||||
is_inverse=True,
|
|
||||||
is_show=False,
|
|
||||||
# interval=True,
|
|
||||||
# grid_index=1,
|
|
||||||
axisline_opts=opts.AxisLineOpts(
|
|
||||||
linestyle_opts=opts.LineStyleOpts(color="#675bba")
|
|
||||||
),
|
|
||||||
# axislabel_opts=opts.LabelOpts(formatter="{value} °C"),
|
|
||||||
splitline_opts=opts.SplitLineOpts(
|
|
||||||
is_show=True, linestyle_opts=opts.LineStyleOpts(opacity=1)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.set_global_opts(
|
|
||||||
title_opts=opts.TitleOpts(
|
|
||||||
title="{}".format(months[i + 1].strftime("%Y-%m")),
|
|
||||||
|
|
||||||
),
|
|
||||||
# legend_opts=opts.LegendOpts(is_show=False),
|
|
||||||
yaxis_opts=opts.AxisOpts(is_inverse=True),
|
|
||||||
# xaxis_opts=opts.AxisOpts(type_='time')
|
|
||||||
)
|
|
||||||
.set_series_opts(
|
|
||||||
label_opts=opts.LabelOpts(
|
|
||||||
is_show=False
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
# init_opts = opts.InitOpts(width="400px", height="235px")
|
|
||||||
line = (
|
|
||||||
Line(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px"))
|
|
||||||
.add_xaxis(list(da['date']))
|
|
||||||
.add_yaxis(
|
|
||||||
"排名",
|
|
||||||
list(da['ranks']),
|
|
||||||
yaxis_index=0,
|
|
||||||
color="#675bba",
|
|
||||||
# label_opts=opts.LabelOpts(is_show=False),
|
|
||||||
|
|
||||||
)
|
|
||||||
.set_global_opts(
|
|
||||||
yaxis_opts=opts.AxisOpts(is_inverse=True),
|
|
||||||
# xaxis_opts=opts.AxisOpts(type_='time')
|
|
||||||
)
|
|
||||||
.set_series_opts(
|
|
||||||
label_opts=opts.LabelOpts(
|
|
||||||
is_show=False
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
bar.overlap(line)
|
|
||||||
grid = Grid()
|
|
||||||
grid.add(bar, opts.GridOpts(pos_left="5%", pos_right="11%"), is_control_axis_index=True)
|
|
||||||
# grid.render("grid_multi_yaxis.html")
|
|
||||||
tl.add(grid, "{}".format(months[i].strftime("%Y-%m")))
|
|
||||||
tl.render("./data/聊天统计/sports.html")
|
|
||||||
return {
|
|
||||||
username: {
|
|
||||||
'ranks': ranks,
|
|
||||||
'score': steps,
|
|
||||||
'date': date,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@log
|
|
||||||
def chat_start_endTime(username):
|
|
||||||
start_time = data.get_msg_start_time(username)
|
|
||||||
end_time = data.get_msg_end_time(username)
|
|
||||||
year = start_time[:4]
|
|
||||||
month = start_time[5:7]
|
|
||||||
day = start_time[8:10]
|
|
||||||
hour = start_time[11:13]
|
|
||||||
minute = start_time[14:16]
|
|
||||||
second = start_time[17:]
|
|
||||||
html = '''
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>聊天时间</title>
|
|
||||||
<style>
|
|
||||||
/* 倒计时开始 */
|
|
||||||
.gn_box {
|
|
||||||
padding: 0px 0px;
|
|
||||||
margin-bottom:0px;
|
|
||||||
text-align: center;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
#t_d{
|
|
||||||
color: #982585;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
#t_h{
|
|
||||||
color: #8f79c1;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
#t_m{
|
|
||||||
color: #65b4b5;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
#t_s{
|
|
||||||
color: #83caa3;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
#text{
|
|
||||||
color: #E80017;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<!--倒计时开始-->
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="gn_box">
|
|
||||||
<h1>
|
|
||||||
<font color="#E80017">第</font><font color="#D1002E">一次</font><font color="#BA0045">聊天</font><font
|
|
||||||
color="#A3005C">发生</font><font color="#8C0073">在</font>
|
|
||||||
<font color="#75008A">%s</font><font color="#5E00A1">-</font><font color="#4700B8">%s</font><font
|
|
||||||
color="#3000CF"> %s</font><font color="#1900E6">:%s</font><font color="#0200FD">:%s</font>
|
|
||||||
</h1>
|
|
||||||
<center>
|
|
||||||
<div id="CountMsg" class="HotDate">
|
|
||||||
<span id="text">距今已有</span>
|
|
||||||
<span id="t_d">626 天</span>
|
|
||||||
<span id="t_h">6 时</span>
|
|
||||||
<span id="t_m">26 分</span>
|
|
||||||
<span id="t_s">26 秒</span>
|
|
||||||
</div>
|
|
||||||
</center>
|
|
||||||
</div>
|
|
||||||
<!--倒计时结束-->
|
|
||||||
<script type="text/javascript"> function getRTime() {
|
|
||||||
var EndTime = new Date('%s');
|
|
||||||
var NowTime = new Date();
|
|
||||||
var t = NowTime.getTime()-EndTime.getTime();
|
|
||||||
var d = Math.floor(t / 1000 / 60 / 60 / 24);
|
|
||||||
var h = Math.floor(t / 1000 / 60 / 60 %% 24);
|
|
||||||
var m = Math.floor(t / 1000 / 60 %% 60);
|
|
||||||
var s = Math.floor(t / 1000 %% 60);
|
|
||||||
document.getElementById("t_d").innerHTML = d + " 天";
|
|
||||||
document.getElementById("t_h").innerHTML = h + " 时";
|
|
||||||
document.getElementById("t_m").innerHTML = m + " 分";
|
|
||||||
document.getElementById("t_s").innerHTML = s + " 秒";
|
|
||||||
}
|
|
||||||
setInterval(getRTime, 1000);
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
''' % (year, month + '-' + day, hour, minute, second, start_time)
|
|
||||||
with open('./data/聊天统计/time.html', 'w', encoding='utf-8') as f:
|
|
||||||
f.write(html)
|
|
||||||
|
|
||||||
|
|
||||||
@log
|
|
||||||
def title(username):
|
|
||||||
conRemark = data.get_conRemark(username)
|
|
||||||
avatar = data.get_avator(username)
|
|
||||||
html = '''
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>聊天时间</title>
|
|
||||||
<style>
|
|
||||||
/* 倒计时开始 */
|
|
||||||
.gn_box {
|
|
||||||
padding: 0px 0px;
|
|
||||||
margin-bottom: 0px;
|
|
||||||
text-align: center;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
#t_d{
|
|
||||||
color: #982585;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
#t_h{
|
|
||||||
color: #8f79c1;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
#t_m{
|
|
||||||
color: #65b4b5;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
#t_s{
|
|
||||||
color: #83caa3;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
#text{
|
|
||||||
color: #E80017;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
#conRemark{
|
|
||||||
color: #A3005C;
|
|
||||||
font-size: 28px;
|
|
||||||
}
|
|
||||||
#table {
|
|
||||||
width: 600px; height: 100px;//可随意
|
|
||||||
position: absolute; left: 0; top: 0; right: 0; bottom: 0;
|
|
||||||
margin: auto; /* 有了这个就自动居中了 */
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<!--倒计时开始-->
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="gn_box">
|
|
||||||
<table align="center" style="margin:0px auto;">
|
|
||||||
<tr valign="middle">
|
|
||||||
<td valign="middle">
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<img src="../../../%s" height="40" width="40"
|
|
||||||
alt="Avatar"/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
<td align="center" valign="middle">
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<font id="conRemark">%s</font>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div>
|
|
||||||
<span>
|
|
||||||
|
|
||||||
</span>
|
|
||||||
<span></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
''' % (avatar, conRemark)
|
|
||||||
with open('./data/聊天统计/title.html', 'w', encoding='utf-8') as f:
|
|
||||||
f.write(html)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# send_recv_rate('wxid_wt2vsktnu4z022')
|
|
||||||
sport('wxid_wt2vsktnu4z022')
|
|
@ -1,174 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Awesome-pyecharts</title>
|
|
||||||
<script type="text/javascript" src="https://assets.pyecharts.org/assets/v5/echarts.min.js"></script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body >
|
|
||||||
<div id="ec5cb8f7096941f5ba51d65454d9c631" class="chart-container" style="width:470px; height:270px; "></div>
|
|
||||||
<script>
|
|
||||||
var chart_ec5cb8f7096941f5ba51d65454d9c631 = echarts.init(
|
|
||||||
document.getElementById('ec5cb8f7096941f5ba51d65454d9c631'), 'white', {renderer: 'canvas'});
|
|
||||||
var option_ec5cb8f7096941f5ba51d65454d9c631 = {
|
|
||||||
"animation": true,
|
|
||||||
"animationThreshold": 2000,
|
|
||||||
"animationDuration": 1000,
|
|
||||||
"animationEasing": "cubicOut",
|
|
||||||
"animationDelay": 0,
|
|
||||||
"animationDurationUpdate": 300,
|
|
||||||
"animationEasingUpdate": "cubicOut",
|
|
||||||
"animationDelayUpdate": 0,
|
|
||||||
"aria": {
|
|
||||||
"enabled": false
|
|
||||||
},
|
|
||||||
"color": [
|
|
||||||
"#5470c6",
|
|
||||||
"#91cc75",
|
|
||||||
"#fac858",
|
|
||||||
"#ee6666",
|
|
||||||
"#73c0de",
|
|
||||||
"#3ba272",
|
|
||||||
"#fc8452",
|
|
||||||
"#9a60b4",
|
|
||||||
"#ea7ccc"
|
|
||||||
],
|
|
||||||
"series": [
|
|
||||||
{
|
|
||||||
"type": "pie",
|
|
||||||
"colorBy": "data",
|
|
||||||
"legendHoverLink": true,
|
|
||||||
"selectedMode": false,
|
|
||||||
"selectedOffset": 10,
|
|
||||||
"clockwise": true,
|
|
||||||
"startAngle": 90,
|
|
||||||
"minAngle": 0,
|
|
||||||
"minShowLabelAngle": 0,
|
|
||||||
"avoidLabelOverlap": true,
|
|
||||||
"stillShowZeroSum": true,
|
|
||||||
"percentPrecision": 2,
|
|
||||||
"showEmptyCircle": true,
|
|
||||||
"emptyCircleStyle": {
|
|
||||||
"color": "lightgray",
|
|
||||||
"borderColor": "#000",
|
|
||||||
"borderWidth": 0,
|
|
||||||
"borderType": "solid",
|
|
||||||
"borderDashOffset": 0,
|
|
||||||
"borderCap": "butt",
|
|
||||||
"borderJoin": "bevel",
|
|
||||||
"borderMiterLimit": 10,
|
|
||||||
"opacity": 1
|
|
||||||
},
|
|
||||||
"data": [
|
|
||||||
{
|
|
||||||
"name": "\u53d1\u9001",
|
|
||||||
"value": 0.6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "\u63a5\u6536",
|
|
||||||
"value": 0.4
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"radius": [
|
|
||||||
"0%",
|
|
||||||
"75%"
|
|
||||||
],
|
|
||||||
"center": [
|
|
||||||
"40%",
|
|
||||||
"50%"
|
|
||||||
],
|
|
||||||
"label": {
|
|
||||||
"show": true,
|
|
||||||
"margin": 8,
|
|
||||||
"formatter": "{b}: {c}"
|
|
||||||
},
|
|
||||||
"labelLine": {
|
|
||||||
"show": true,
|
|
||||||
"showAbove": false,
|
|
||||||
"length": 15,
|
|
||||||
"length2": 15,
|
|
||||||
"smooth": false,
|
|
||||||
"minTurnAngle": 90,
|
|
||||||
"maxSurfaceAngle": 90
|
|
||||||
},
|
|
||||||
"rippleEffect": {
|
|
||||||
"show": true,
|
|
||||||
"brushType": "stroke",
|
|
||||||
"scale": 2.5,
|
|
||||||
"period": 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"legend": [
|
|
||||||
{
|
|
||||||
"data": [
|
|
||||||
"\u53d1\u9001",
|
|
||||||
"\u63a5\u6536"
|
|
||||||
],
|
|
||||||
"selected": {},
|
|
||||||
"type": "scroll",
|
|
||||||
"show": true,
|
|
||||||
"left": "60%",
|
|
||||||
"orient": "vertical",
|
|
||||||
"padding": 5,
|
|
||||||
"itemGap": 10,
|
|
||||||
"itemWidth": 25,
|
|
||||||
"itemHeight": 14,
|
|
||||||
"backgroundColor": "transparent",
|
|
||||||
"borderColor": "#ccc",
|
|
||||||
"borderWidth": 1,
|
|
||||||
"borderRadius": 0,
|
|
||||||
"pageButtonItemGap": 5,
|
|
||||||
"pageButtonPosition": "end",
|
|
||||||
"pageFormatter": "{current}/{total}",
|
|
||||||
"pageIconColor": "#2f4554",
|
|
||||||
"pageIconInactiveColor": "#aaa",
|
|
||||||
"pageIconSize": 15,
|
|
||||||
"animationDurationUpdate": 800,
|
|
||||||
"selector": false,
|
|
||||||
"selectorPosition": "auto",
|
|
||||||
"selectorItemGap": 7,
|
|
||||||
"selectorButtonGap": 10
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"tooltip": {
|
|
||||||
"show": true,
|
|
||||||
"trigger": "item",
|
|
||||||
"triggerOn": "mousemove|click",
|
|
||||||
"axisPointer": {
|
|
||||||
"type": "line"
|
|
||||||
},
|
|
||||||
"showContent": true,
|
|
||||||
"alwaysShowContent": false,
|
|
||||||
"showDelay": 0,
|
|
||||||
"hideDelay": 100,
|
|
||||||
"enterable": false,
|
|
||||||
"confine": false,
|
|
||||||
"appendToBody": false,
|
|
||||||
"transitionDuration": 0.4,
|
|
||||||
"textStyle": {
|
|
||||||
"fontSize": 14
|
|
||||||
},
|
|
||||||
"borderWidth": 0,
|
|
||||||
"padding": 5,
|
|
||||||
"order": "seriesAsc"
|
|
||||||
},
|
|
||||||
"title": [
|
|
||||||
{
|
|
||||||
"show": true,
|
|
||||||
"text": "\u53d1\u9001\u63a5\u6536\u5360\u6bd4",
|
|
||||||
"target": "blank",
|
|
||||||
"subtarget": "blank",
|
|
||||||
"padding": 5,
|
|
||||||
"itemGap": 10,
|
|
||||||
"textAlign": "auto",
|
|
||||||
"textVerticalAlign": "auto",
|
|
||||||
"triggerEvent": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
chart_ec5cb8f7096941f5ba51d65454d9c631.setOption(option_ec5cb8f7096941f5ba51d65454d9c631);
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,116 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
@File : contact.py
|
|
||||||
@Author : Shuaikang Zhou
|
|
||||||
@Time : 2022/12/13 15:07
|
|
||||||
@IDE : Pycharm
|
|
||||||
@Version : Python3.10
|
|
||||||
@comment : ···
|
|
||||||
"""
|
|
||||||
from typing import Dict
|
|
||||||
|
|
||||||
from PyQt5 import QtCore
|
|
||||||
from PyQt5.QtCore import *
|
|
||||||
from PyQt5.QtWidgets import *
|
|
||||||
|
|
||||||
import app.components.Button_Contact as MyLabel
|
|
||||||
from app import person
|
|
||||||
from app.DataBase import data
|
|
||||||
from app.Ui.contact.contactInfo import ContactInfo
|
|
||||||
from app.Ui.contact.contactUi import Ui_Dialog
|
|
||||||
|
|
||||||
EMOTION = 1
|
|
||||||
ANALYSIS = 2
|
|
||||||
|
|
||||||
|
|
||||||
class StackedWidget():
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ContactController(QWidget, Ui_Dialog):
|
|
||||||
exitSignal = pyqtSignal()
|
|
||||||
urlSignal = pyqtSignal(QUrl)
|
|
||||||
|
|
||||||
# username = ''
|
|
||||||
|
|
||||||
def __init__(self, Me: person.Me, parent=None):
|
|
||||||
super(ContactController, self).__init__(parent)
|
|
||||||
self.chatroomFlag = None
|
|
||||||
self.ta_avatar = None
|
|
||||||
self.setupUi(self)
|
|
||||||
self.Me = Me
|
|
||||||
self.contacts: Dict[str, MyLabel.ContactUi] = {}
|
|
||||||
self.contactInfo: Dict[str, ContactInfo] = {}
|
|
||||||
self.show_flag = False
|
|
||||||
self.last_talkerId = None
|
|
||||||
self.now_talkerId = None
|
|
||||||
# self.showContact()
|
|
||||||
self.show_thread = ShowContactThread()
|
|
||||||
self.show_thread.showSingal.connect(self.showContact)
|
|
||||||
self.show_thread.heightSingal.connect(self.setScreenAreaHeight)
|
|
||||||
self.show_thread.start()
|
|
||||||
|
|
||||||
def showContact(self, data_):
|
|
||||||
"""
|
|
||||||
data:Tuple[rconversation,index:int]
|
|
||||||
显示联系人
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
rconversation, i = data_
|
|
||||||
username = rconversation[1]
|
|
||||||
# print(username)
|
|
||||||
pushButton_2 = MyLabel.ContactUi(self.scrollAreaWidgetContents, i, rconversation)
|
|
||||||
pushButton_2.setGeometry(QtCore.QRect(0, 80 * i, 300, 80))
|
|
||||||
pushButton_2.setLayoutDirection(QtCore.Qt.LeftToRight)
|
|
||||||
pushButton_2.clicked.connect(pushButton_2.show_msg)
|
|
||||||
pushButton_2.usernameSingal.connect(self.Contact)
|
|
||||||
self.contacts[username] = pushButton_2
|
|
||||||
self.contactInfo[username] = ContactInfo(username, self.Me)
|
|
||||||
self.stackedWidget.addWidget(self.contactInfo[username])
|
|
||||||
|
|
||||||
def setScreenAreaHeight(self, height: int):
|
|
||||||
self.scrollAreaWidgetContents.setGeometry(
|
|
||||||
QtCore.QRect(0, 0, 300, height))
|
|
||||||
|
|
||||||
def Contact(self, talkerId):
|
|
||||||
"""
|
|
||||||
聊天界面 点击联系人头像时候显示聊天数据
|
|
||||||
:param talkerId:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.now_talkerId = talkerId
|
|
||||||
# 把当前按钮设置为灰色
|
|
||||||
if self.last_talkerId and self.last_talkerId != talkerId:
|
|
||||||
print('对方账号:', self.last_talkerId)
|
|
||||||
self.contacts[self.last_talkerId].setStyleSheet(
|
|
||||||
"QPushButton {background-color: rgb(220,220,220);}"
|
|
||||||
"QPushButton:hover{background-color: rgb(208,208,208);}\n"
|
|
||||||
)
|
|
||||||
self.last_talkerId = talkerId
|
|
||||||
self.contacts[talkerId].setStyleSheet(
|
|
||||||
"QPushButton {background-color: rgb(198,198,198);}"
|
|
||||||
"QPushButton:hover{background-color: rgb(209,209,209);}\n"
|
|
||||||
)
|
|
||||||
self.stackedWidget.setCurrentWidget(self.contactInfo[talkerId])
|
|
||||||
|
|
||||||
if '@chatroom' in talkerId:
|
|
||||||
self.chatroomFlag = True
|
|
||||||
else:
|
|
||||||
self.chatroomFlag = False
|
|
||||||
|
|
||||||
|
|
||||||
class ShowContactThread(QThread):
|
|
||||||
showSingal = pyqtSignal(tuple)
|
|
||||||
heightSingal = pyqtSignal(int)
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
def run(self) -> None:
|
|
||||||
rconversations = data.get_rconversation()
|
|
||||||
max_height = max(len(rconversations) * 80, 680)
|
|
||||||
# 设置滚动区域的高度
|
|
||||||
self.heightSingal.emit(max_height)
|
|
||||||
for i in range(len(rconversations)):
|
|
||||||
self.showSingal.emit((rconversations[i], i))
|
|
@ -1,137 +0,0 @@
|
|||||||
from PyQt5.QtCore import *
|
|
||||||
from PyQt5.QtWidgets import *
|
|
||||||
|
|
||||||
from app import person
|
|
||||||
from app.DataBase import output
|
|
||||||
from app.Ui.Icon import Icon
|
|
||||||
from .analysis import analysis
|
|
||||||
from .contactInfoUi import Ui_Form
|
|
||||||
from .emotion import emotion
|
|
||||||
from .userinfo import userinfo
|
|
||||||
|
|
||||||
|
|
||||||
class ContactInfo(QWidget, Ui_Form):
|
|
||||||
exitSignal = pyqtSignal()
|
|
||||||
urlSignal = pyqtSignal(QUrl)
|
|
||||||
|
|
||||||
# username = ''
|
|
||||||
def __init__(self, wxid, me: person.Me, parent=None):
|
|
||||||
super(ContactInfo, self).__init__(parent)
|
|
||||||
self.setupUi(self)
|
|
||||||
self.contact = person.Contact(wxid)
|
|
||||||
self.view_userinfo = userinfo.UserinfoController(self.contact)
|
|
||||||
self.view_analysis = analysis.AnalysisController(wxid)
|
|
||||||
self.view_emotion = emotion.EmotionController(wxid)
|
|
||||||
self.btn_analysis.clicked.connect(self.analysis)
|
|
||||||
self.btn_emotion.clicked.connect(self.emotionale_Analysis)
|
|
||||||
self.btn_report.clicked.connect(self.annual_report)
|
|
||||||
self.btn_back.clicked.connect(self.back)
|
|
||||||
self.Me = me
|
|
||||||
# self.
|
|
||||||
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.label_remark.setText(self.contact.conRemark)
|
|
||||||
self.stackedWidget.addWidget(self.view_userinfo)
|
|
||||||
self.stackedWidget.addWidget(self.view_analysis)
|
|
||||||
self.stackedWidget.addWidget(self.view_emotion)
|
|
||||||
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.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)
|
|
||||||
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)
|
|
||||||
|
|
||||||
def toolButton_show(self):
|
|
||||||
self.toolButton_output.showMenu()
|
|
||||||
|
|
||||||
def analysis(self):
|
|
||||||
self.stackedWidget.setCurrentWidget(self.view_analysis)
|
|
||||||
if 'room' in self.contact.wxid:
|
|
||||||
QMessageBox.warning(
|
|
||||||
self, '警告',
|
|
||||||
'暂不支持群组'
|
|
||||||
)
|
|
||||||
return
|
|
||||||
self.view_analysis.start()
|
|
||||||
|
|
||||||
def annual_report(self):
|
|
||||||
QMessageBox.warning(
|
|
||||||
self,
|
|
||||||
"提示",
|
|
||||||
"敬请期待"
|
|
||||||
)
|
|
||||||
return
|
|
||||||
# self.report = report.ReportController(self.contact)
|
|
||||||
# self.report.show()
|
|
||||||
|
|
||||||
def emotionale_Analysis(self):
|
|
||||||
self.stackedWidget.setCurrentWidget(self.view_emotion)
|
|
||||||
if 'room' in self.contact.wxid:
|
|
||||||
QMessageBox.warning(
|
|
||||||
self, '警告',
|
|
||||||
'暂不支持群组'
|
|
||||||
)
|
|
||||||
return
|
|
||||||
self.view_emotion.start()
|
|
||||||
|
|
||||||
def back(self):
|
|
||||||
"""
|
|
||||||
将userinfo界面设置为可见,其他界面设置为不可见
|
|
||||||
"""
|
|
||||||
self.stackedWidget.setCurrentWidget(self.view_userinfo)
|
|
||||||
|
|
||||||
def output(self):
|
|
||||||
"""
|
|
||||||
导出聊天记录
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.stackedWidget.setCurrentWidget(self.view_userinfo)
|
|
||||||
if self.sender() == self.toDocxAct:
|
|
||||||
self.outputThread = output.Output(self.Me, self.contact.wxid)
|
|
||||||
elif self.sender() == self.toCSVAct:
|
|
||||||
print('开始导出csv')
|
|
||||||
self.outputThread = output.Output(self.Me, self.contact.wxid, type_=output.Output.CSV)
|
|
||||||
print('导出csv')
|
|
||||||
elif self.sender() == self.toHtmlAct:
|
|
||||||
print('功能暂未实现')
|
|
||||||
QMessageBox.warning(self,
|
|
||||||
"别急别急",
|
|
||||||
"马上就实现该功能"
|
|
||||||
)
|
|
||||||
return
|
|
||||||
self.outputThread.progressSignal.connect(self.output_progress)
|
|
||||||
self.outputThread.rangeSignal.connect(self.set_progressBar_range)
|
|
||||||
self.outputThread.okSignal.connect(self.hide_progress_bar)
|
|
||||||
self.outputThread.start()
|
|
||||||
|
|
||||||
def hide_progress_bar(self, int):
|
|
||||||
reply = QMessageBox(self)
|
|
||||||
reply.setIcon(QMessageBox.Information)
|
|
||||||
reply.setWindowTitle('OK')
|
|
||||||
reply.setText(f"导出聊天记录成功\n在.\\data\\目录下")
|
|
||||||
reply.addButton("确认", QMessageBox.AcceptRole)
|
|
||||||
reply.addButton("取消", QMessageBox.RejectRole)
|
|
||||||
api = reply.exec_()
|
|
||||||
self.view_userinfo.progressBar.setVisible(False)
|
|
||||||
|
|
||||||
def output_progress(self, value):
|
|
||||||
self.view_userinfo.progressBar.setProperty('value', value)
|
|
||||||
|
|
||||||
def set_progressBar_range(self, value):
|
|
||||||
self.view_userinfo.progressBar.setVisible(True)
|
|
||||||
self.view_userinfo.progressBar.setRange(0, value)
|
|
@ -1,92 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'contactInfoUi.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_Form(object):
|
|
||||||
def setupUi(self, Form):
|
|
||||||
Form.setObjectName("Form")
|
|
||||||
Form.resize(817, 748)
|
|
||||||
self.horizontalLayout = QtWidgets.QHBoxLayout(Form)
|
|
||||||
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.horizontalLayout.setSpacing(0)
|
|
||||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
|
||||||
self.frame = QtWidgets.QFrame(Form)
|
|
||||||
self.frame.setFrameShape(QtWidgets.QFrame.NoFrame)
|
|
||||||
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
|
|
||||||
self.frame.setObjectName("frame")
|
|
||||||
self.verticalLayout = QtWidgets.QVBoxLayout(self.frame)
|
|
||||||
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.verticalLayout.setSpacing(0)
|
|
||||||
self.verticalLayout.setObjectName("verticalLayout")
|
|
||||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
|
|
||||||
self.horizontalLayout_3.setSpacing(0)
|
|
||||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
|
||||||
self.label_remark = QtWidgets.QLabel(self.frame)
|
|
||||||
self.label_remark.setMaximumSize(QtCore.QSize(16777215, 100))
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setPointSize(12)
|
|
||||||
self.label_remark.setFont(font)
|
|
||||||
self.label_remark.setText("")
|
|
||||||
self.label_remark.setObjectName("label_remark")
|
|
||||||
self.horizontalLayout_3.addWidget(self.label_remark)
|
|
||||||
self.btn_analysis = QtWidgets.QPushButton(self.frame)
|
|
||||||
self.btn_analysis.setStyleSheet("")
|
|
||||||
self.btn_analysis.setFlat(True)
|
|
||||||
self.btn_analysis.setObjectName("btn_analysis")
|
|
||||||
self.horizontalLayout_3.addWidget(self.btn_analysis)
|
|
||||||
self.btn_emotion = QtWidgets.QPushButton(self.frame)
|
|
||||||
self.btn_emotion.setFlat(True)
|
|
||||||
self.btn_emotion.setObjectName("btn_emotion")
|
|
||||||
self.horizontalLayout_3.addWidget(self.btn_emotion)
|
|
||||||
self.btn_report = QtWidgets.QPushButton(self.frame)
|
|
||||||
self.btn_report.setFlat(True)
|
|
||||||
self.btn_report.setObjectName("btn_report")
|
|
||||||
self.horizontalLayout_3.addWidget(self.btn_report)
|
|
||||||
self.btn_back = QtWidgets.QPushButton(self.frame)
|
|
||||||
self.btn_back.setFlat(True)
|
|
||||||
self.btn_back.setObjectName("btn_back")
|
|
||||||
self.horizontalLayout_3.addWidget(self.btn_back)
|
|
||||||
self.toolButton_output = QtWidgets.QToolButton(self.frame)
|
|
||||||
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(self.frame)
|
|
||||||
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.horizontalLayout.addWidget(self.frame)
|
|
||||||
|
|
||||||
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.btn_back.setText(_translate("Form", "退出"))
|
|
||||||
self.toolButton_output.setText(_translate("Form", "导出聊天记录"))
|
|
@ -1,77 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'contactUi.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(1141, 740)
|
|
||||||
Dialog.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
|
|
||||||
Dialog.setAutoFillBackground(False)
|
|
||||||
self.horizontalLayout = QtWidgets.QHBoxLayout(Dialog)
|
|
||||||
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.horizontalLayout.setSpacing(0)
|
|
||||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
|
||||||
self.frame_2 = QtWidgets.QFrame(Dialog)
|
|
||||||
self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
|
||||||
self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
|
|
||||||
self.frame_2.setObjectName("frame_2")
|
|
||||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame_2)
|
|
||||||
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.horizontalLayout_2.setSpacing(0)
|
|
||||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
|
||||||
self.scrollArea = QtWidgets.QScrollArea(self.frame_2)
|
|
||||||
self.scrollArea.setEnabled(True)
|
|
||||||
self.scrollArea.setMinimumSize(QtCore.QSize(325, 0))
|
|
||||||
self.scrollArea.setMaximumSize(QtCore.QSize(325, 150000))
|
|
||||||
self.scrollArea.setAutoFillBackground(False)
|
|
||||||
self.scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame)
|
|
||||||
self.scrollArea.setFrameShadow(QtWidgets.QFrame.Raised)
|
|
||||||
self.scrollArea.setMidLineWidth(0)
|
|
||||||
self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
|
|
||||||
self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
|
||||||
self.scrollArea.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContentsOnFirstShow)
|
|
||||||
self.scrollArea.setWidgetResizable(False)
|
|
||||||
self.scrollArea.setObjectName("scrollArea")
|
|
||||||
self.scrollAreaWidgetContents = QtWidgets.QWidget()
|
|
||||||
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 300, 12000))
|
|
||||||
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
|
|
||||||
self.pushButton_2 = QtWidgets.QPushButton(self.scrollAreaWidgetContents)
|
|
||||||
self.pushButton_2.setGeometry(QtCore.QRect(0, 0, 300, 80))
|
|
||||||
self.pushButton_2.setLayoutDirection(QtCore.Qt.LeftToRight)
|
|
||||||
self.pushButton_2.setAutoFillBackground(False)
|
|
||||||
self.pushButton_2.setText("")
|
|
||||||
self.pushButton_2.setIconSize(QtCore.QSize(80, 80))
|
|
||||||
self.pushButton_2.setObjectName("pushButton_2")
|
|
||||||
self.label = QtWidgets.QLabel(self.scrollAreaWidgetContents)
|
|
||||||
self.label.setGeometry(QtCore.QRect(220, 10, 72, 15))
|
|
||||||
self.label.setObjectName("label")
|
|
||||||
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
|
|
||||||
self.horizontalLayout_2.addWidget(self.scrollArea)
|
|
||||||
self.stackedWidget = QtWidgets.QStackedWidget(self.frame_2)
|
|
||||||
self.stackedWidget.setObjectName("stackedWidget")
|
|
||||||
self.page = QtWidgets.QWidget()
|
|
||||||
self.page.setObjectName("page")
|
|
||||||
self.stackedWidget.addWidget(self.page)
|
|
||||||
self.page_2 = QtWidgets.QWidget()
|
|
||||||
self.page_2.setObjectName("page_2")
|
|
||||||
self.stackedWidget.addWidget(self.page_2)
|
|
||||||
self.horizontalLayout_2.addWidget(self.stackedWidget)
|
|
||||||
self.horizontalLayout.addWidget(self.frame_2)
|
|
||||||
|
|
||||||
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", "TextLabel"))
|
|
@ -1,170 +0,0 @@
|
|||||||
import numpy as np
|
|
||||||
import pandas as pd
|
|
||||||
from pyecharts import options as opts
|
|
||||||
from pyecharts.charts import Line
|
|
||||||
|
|
||||||
from app.log import log
|
|
||||||
from ....DataBase import data
|
|
||||||
|
|
||||||
|
|
||||||
def load_data(wxid):
|
|
||||||
message_data = data.get_text_by_num(wxid, 1)
|
|
||||||
df = pd.DataFrame(message_data, columns=['message', 'date'])
|
|
||||||
# print(df)
|
|
||||||
d = df.groupby('date')
|
|
||||||
for key, value in d:
|
|
||||||
yield key, value['message'].values
|
|
||||||
|
|
||||||
|
|
||||||
import snownlp
|
|
||||||
|
|
||||||
|
|
||||||
@log
|
|
||||||
def emotion_analysis(wxid):
|
|
||||||
dates = []
|
|
||||||
emotions = []
|
|
||||||
for date, messages in load_data(wxid):
|
|
||||||
dates.append(date)
|
|
||||||
s = 0
|
|
||||||
for msg in messages:
|
|
||||||
val = snownlp.SnowNLP(msg).sentiments
|
|
||||||
s += val
|
|
||||||
emotions.append(s / len(messages))
|
|
||||||
emotions = np.array(emotions)
|
|
||||||
emotions = np.around(emotions, 3) * 100
|
|
||||||
emotions = np.around(emotions, 1)
|
|
||||||
return dates, emotions
|
|
||||||
|
|
||||||
|
|
||||||
@log
|
|
||||||
def plot_emotion(wxid):
|
|
||||||
"""
|
|
||||||
画图
|
|
||||||
"""
|
|
||||||
datas, emotions = emotion_analysis(wxid) # 获取数据
|
|
||||||
max_ = max(emotions)
|
|
||||||
min_ = min(emotions)
|
|
||||||
c = (
|
|
||||||
Line()
|
|
||||||
.add_xaxis(
|
|
||||||
xaxis_data=datas,
|
|
||||||
)
|
|
||||||
.add_yaxis(
|
|
||||||
series_name="情感趋势",
|
|
||||||
is_smooth=True,
|
|
||||||
y_axis=emotions,
|
|
||||||
markpoint_opts=opts.MarkPointOpts(
|
|
||||||
data=[
|
|
||||||
opts.MarkPointItem(type_="max", name="最大值", value=int(max_ * 100) / 100),
|
|
||||||
opts.MarkPointItem(type_="min", name="最小值", value=int(min_ * 100) / 100),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
markline_opts=opts.MarkLineOpts(
|
|
||||||
data=[opts.MarkLineItem(type_="average", name="平均值")]
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.set_global_opts(
|
|
||||||
yaxis_opts=opts.AxisOpts(
|
|
||||||
max_=max_,
|
|
||||||
min_=min_,
|
|
||||||
),
|
|
||||||
xaxis_opts=opts.AxisOpts(
|
|
||||||
type_='time'
|
|
||||||
),
|
|
||||||
axispointer_opts=opts.AxisPointerOpts(
|
|
||||||
is_show=True, link=[{"xAxisIndex": "all"}]
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
|
|
||||||
.render("./data/聊天统计/emotion_chart.html")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
from PyQt5.QtCore import *
|
|
||||||
from PyQt5.QtGui import *
|
|
||||||
from PyQt5.QtWebEngineWidgets import QWebEngineView
|
|
||||||
from PyQt5.QtWidgets import *
|
|
||||||
|
|
||||||
from . import emotionUi
|
|
||||||
|
|
||||||
|
|
||||||
class EmotionController(QWidget, emotionUi.Ui_Dialog):
|
|
||||||
def __init__(self, username, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.ta_username = username
|
|
||||||
|
|
||||||
# self.setStyleSheet('''QWidget{background-color:rgb(240, 240, 240);}''')
|
|
||||||
# 加载动画
|
|
||||||
self.center()
|
|
||||||
self.label_01()
|
|
||||||
|
|
||||||
def center(self): # 定义一个函数使得窗口居中显示
|
|
||||||
# 获取屏幕坐标系
|
|
||||||
screen = QDesktopWidget().screenGeometry()
|
|
||||||
# 获取窗口坐标系
|
|
||||||
size = self.geometry()
|
|
||||||
newLeft = (screen.width() - size.width()) / 2
|
|
||||||
newTop = (screen.height() - size.height()) / 2
|
|
||||||
self.move(int(newLeft), int(newTop))
|
|
||||||
|
|
||||||
def label_01(self):
|
|
||||||
w = self.size().width()
|
|
||||||
h = self.size().height()
|
|
||||||
self.label = QLabel(self)
|
|
||||||
self.label.setGeometry(w // 2, h // 2, 100, 100)
|
|
||||||
self.label.setToolTip("这是一个标签")
|
|
||||||
self.m_movie()
|
|
||||||
|
|
||||||
def m_movie(self):
|
|
||||||
movie = QMovie("./app/data/bg.gif")
|
|
||||||
self.label.setMovie(movie)
|
|
||||||
movie.start()
|
|
||||||
|
|
||||||
def initUI(self):
|
|
||||||
self.label.setVisible(False)
|
|
||||||
# self.setStyleSheet('''QWidget{background-color:rgb(244, 244, 244);}''')
|
|
||||||
main_box = QHBoxLayout(self)
|
|
||||||
self.browser1 = QWebEngineView()
|
|
||||||
self.browser1.load(QUrl('file:///data/聊天统计/emotion_chart.html'))
|
|
||||||
# self.browser1.setStyleSheet('''QWidget{background-color:rgb(240, 240, 240);}''')
|
|
||||||
|
|
||||||
splitter1 = QSplitter(Qt.Vertical)
|
|
||||||
|
|
||||||
splitter1.addWidget(self.browser1)
|
|
||||||
main_box.addWidget(splitter1)
|
|
||||||
self.setLayout(main_box)
|
|
||||||
|
|
||||||
def setBackground(self):
|
|
||||||
palette = QPalette()
|
|
||||||
pix = QPixmap("./app/data/bg.png")
|
|
||||||
pix = pix.scaled(self.width(), self.height(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation) # 自适应图片大小
|
|
||||||
palette.setBrush(self.backgroundRole(), QBrush(pix)) # 设置背景图片
|
|
||||||
# palette.setColor(self.backgroundRole(), QColor(192, 253, 123)) # 设置背景颜色
|
|
||||||
self.setPalette(palette)
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
# 防止卡死,新建线程处理数据
|
|
||||||
self.Thread = LoadData(self.ta_username)
|
|
||||||
self.Thread.okSignal.connect(self.initUI)
|
|
||||||
self.Thread.start()
|
|
||||||
|
|
||||||
|
|
||||||
class LoadData(QThread):
|
|
||||||
"""
|
|
||||||
发送信息线程
|
|
||||||
"""
|
|
||||||
okSignal = pyqtSignal(int)
|
|
||||||
|
|
||||||
def __init__(self, ta_u, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.ta_username = ta_u
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
plot_emotion(self.ta_username)
|
|
||||||
self.okSignal.emit(10)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# wxid = 'wxid_8piw6sb4hvfm22'
|
|
||||||
wxid = 'wxid_wt2vsktnu4z022'
|
|
||||||
load_data(wxid)
|
|
@ -1,24 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'emotionUi.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
|
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
|
||||||
def setupUi(self, Dialog):
|
|
||||||
Dialog.setObjectName("Dialog")
|
|
||||||
Dialog.resize(400, 300)
|
|
||||||
|
|
||||||
self.retranslateUi(Dialog)
|
|
||||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
|
||||||
|
|
||||||
def retranslateUi(self, Dialog):
|
|
||||||
_translate = QtCore.QCoreApplication.translate
|
|
||||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
|
@ -1,28 +0,0 @@
|
|||||||
from bs4 import BeautifulSoup
|
|
||||||
|
|
||||||
|
|
||||||
def create_title_page(nickname, time, avatar_path):
|
|
||||||
with open('D:\\Project\\Python\\WeChatMsg\\app\\data\\html\\0.html', 'r+', encoding='utf-8') as f:
|
|
||||||
html_document = f.read()
|
|
||||||
# 创建Beautiful Soup对象
|
|
||||||
soup = BeautifulSoup(html_document, 'html.parser')
|
|
||||||
# 找到需要替换的图片元素
|
|
||||||
target_image = soup.find(id='avatar')
|
|
||||||
# 替换图片元素的src属性
|
|
||||||
if target_image:
|
|
||||||
target_image['src'] = avatar_path
|
|
||||||
# 找到需要替换的元素
|
|
||||||
target_element = soup.find(id='nickname')
|
|
||||||
# 替换元素的文本内容
|
|
||||||
if target_element:
|
|
||||||
target_element.string = nickname
|
|
||||||
target_element = soup.find(id='first_time')
|
|
||||||
# 替换元素的文本内容
|
|
||||||
if target_element:
|
|
||||||
target_element.string = time
|
|
||||||
with open('./data/AnnualReport/0.html', 'w', encoding='utf-8') as f1:
|
|
||||||
f1.write(soup.prettify())
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
create_title_page('小学生', '2023-09-18 20:39:08', 'D:\Project\Python\WeChatMsg\\app\data\icons\default_avatar.svg')
|
|
@ -1,74 +0,0 @@
|
|||||||
import sys
|
|
||||||
|
|
||||||
from PyQt5.QtCore import *
|
|
||||||
from PyQt5.QtGui import *
|
|
||||||
from PyQt5.QtWebEngineWidgets import QWebEngineView
|
|
||||||
from PyQt5.QtWidgets import *
|
|
||||||
|
|
||||||
from app import person
|
|
||||||
from app.DataBase import data
|
|
||||||
from . import annual_report
|
|
||||||
|
|
||||||
|
|
||||||
class ReportController(QWidget):
|
|
||||||
def __init__(self, contact: person.Contact, me: person.Me = None, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.ta_username = contact.wxid
|
|
||||||
self.contact = contact
|
|
||||||
self.Me = me
|
|
||||||
# self.setStyleSheet('''QWidget{background-color:rgb(240, 240, 240);}''')
|
|
||||||
# 加载动画
|
|
||||||
self.center()
|
|
||||||
self.label_01()
|
|
||||||
|
|
||||||
def center(self): # 定义一个函数使得窗口居中显示
|
|
||||||
# 获取屏幕坐标系
|
|
||||||
screen = QDesktopWidget().screenGeometry()
|
|
||||||
# 获取窗口坐标系
|
|
||||||
size = self.geometry()
|
|
||||||
newLeft = (screen.width() - size.width()) / 2
|
|
||||||
newTop = (screen.height() - size.height()) / 2
|
|
||||||
self.move(int(newLeft), int(newTop))
|
|
||||||
|
|
||||||
def label_01(self):
|
|
||||||
w = self.size().width()
|
|
||||||
h = self.size().height()
|
|
||||||
self.label = QLabel(self)
|
|
||||||
self.label.setGeometry(w // 2, h // 2, 100, 100)
|
|
||||||
self.label.setToolTip("这是一个标签")
|
|
||||||
# self.m_movie()
|
|
||||||
self.initUI()
|
|
||||||
|
|
||||||
def m_movie(self):
|
|
||||||
movie = QMovie("./app/data/bg.gif")
|
|
||||||
self.label.setMovie(movie)
|
|
||||||
movie.start()
|
|
||||||
|
|
||||||
def initUI(self):
|
|
||||||
start_time = data.get_msg_start_time(self.contact.wxid)
|
|
||||||
annual_report.create_title_page(self.contact.nickname, start_time, self.contact.avatar_path)
|
|
||||||
self.label.setVisible(False)
|
|
||||||
# self.setStyleSheet('''QWidget{background-color:rgb(244, 244, 244);}''')
|
|
||||||
main_box = QHBoxLayout(self)
|
|
||||||
self.browser1 = QWebEngineView()
|
|
||||||
self.browser1.load(QUrl('file:///data/AnnualReport/index.html'))
|
|
||||||
|
|
||||||
splitter1 = QSplitter(Qt.Vertical)
|
|
||||||
splitter1.addWidget(self.browser1)
|
|
||||||
main_box.addWidget(splitter1)
|
|
||||||
self.setLayout(main_box)
|
|
||||||
|
|
||||||
def setBackground(self):
|
|
||||||
palette = QPalette()
|
|
||||||
pix = QPixmap("./app/data/bg.png")
|
|
||||||
pix = pix.scaled(self.width(), self.height(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation) # 自适应图片大小
|
|
||||||
palette.setBrush(self.backgroundRole(), QBrush(pix)) # 设置背景图片
|
|
||||||
# palette.setColor(self.backgroundRole(), QColor(192, 253, 123)) # 设置背景颜色
|
|
||||||
self.setPalette(palette)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
ex = ReportController(1)
|
|
||||||
ex.show()
|
|
||||||
sys.exit(app.exec_())
|
|
@ -1,9 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
@File : __init__.py.py
|
|
||||||
@Author : Shuaikang Zhou
|
|
||||||
@Time : 2022/12/24 10:34
|
|
||||||
@IDE : Pycharm
|
|
||||||
@Version : Python3.10
|
|
||||||
@comment : ···
|
|
||||||
"""
|
|
@ -1,15 +0,0 @@
|
|||||||
from PyQt5.QtWidgets import *
|
|
||||||
|
|
||||||
from .userinfoUi import Ui_Frame
|
|
||||||
|
|
||||||
|
|
||||||
class UserinfoController(QWidget, Ui_Frame):
|
|
||||||
def __init__(self, contact, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.setupUi(self)
|
|
||||||
self.l_remark.setText(contact.conRemark)
|
|
||||||
self.l_avatar.setPixmap(contact.avatar)
|
|
||||||
self.l_nickname.setText(f'昵称:{contact.nickname}')
|
|
||||||
self.l_username.setText(f'微信号:{contact.alias}')
|
|
||||||
self.lineEdit.setText(contact.conRemark)
|
|
||||||
self.progressBar.setVisible(False)
|
|
@ -1,121 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'userinfoUi.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_Frame(object):
|
|
||||||
def setupUi(self, Frame):
|
|
||||||
Frame.setObjectName("Frame")
|
|
||||||
Frame.resize(800, 720)
|
|
||||||
Frame.setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor))
|
|
||||||
Frame.setMouseTracking(True)
|
|
||||||
Frame.setTabletTracking(True)
|
|
||||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout(Frame)
|
|
||||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
|
||||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
|
|
||||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
|
||||||
spacerItem = QtWidgets.QSpacerItem(40, 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 = QtWidgets.QGridLayout()
|
|
||||||
self.gridLayout.setHorizontalSpacing(6)
|
|
||||||
self.gridLayout.setObjectName("gridLayout")
|
|
||||||
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.setObjectName("l_avatar")
|
|
||||||
self.gridLayout.addWidget(self.l_avatar, 0, 0, 3, 1)
|
|
||||||
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.setObjectName("l_remark")
|
|
||||||
self.gridLayout.addWidget(self.l_remark, 0, 1, 1, 1)
|
|
||||||
self.l_nickname = QtWidgets.QLabel(Frame)
|
|
||||||
self.l_nickname.setMinimumSize(QtCore.QSize(0, 30))
|
|
||||||
self.l_nickname.setMaximumSize(QtCore.QSize(16777215, 30))
|
|
||||||
self.l_nickname.setObjectName("l_nickname")
|
|
||||||
self.gridLayout.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, 20))
|
|
||||||
self.l_username.setObjectName("l_username")
|
|
||||||
self.gridLayout.addWidget(self.l_username, 2, 1, 1, 1)
|
|
||||||
self.gridLayout.setRowStretch(0, 1)
|
|
||||||
self.gridLayout.setRowStretch(1, 1)
|
|
||||||
self.gridLayout.setRowStretch(2, 1)
|
|
||||||
self.verticalLayout.addLayout(self.gridLayout)
|
|
||||||
spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
|
||||||
self.verticalLayout.addItem(spacerItem2)
|
|
||||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
|
||||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
|
||||||
self.label = QtWidgets.QLabel(Frame)
|
|
||||||
self.label.setMinimumSize(QtCore.QSize(80, 0))
|
|
||||||
self.label.setMaximumSize(QtCore.QSize(80, 16777215))
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setPointSize(15)
|
|
||||||
self.label.setFont(font)
|
|
||||||
self.label.setObjectName("label")
|
|
||||||
self.horizontalLayout.addWidget(self.label)
|
|
||||||
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("background:transparent;border-width:0;border-style:outset")
|
|
||||||
self.lineEdit.setObjectName("lineEdit")
|
|
||||||
self.horizontalLayout.addWidget(self.lineEdit)
|
|
||||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
|
||||||
spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
|
||||||
self.verticalLayout.addItem(spacerItem3)
|
|
||||||
self.progressBar = QtWidgets.QProgressBar(Frame)
|
|
||||||
self.progressBar.setProperty("value", 24)
|
|
||||||
self.progressBar.setObjectName("progressBar")
|
|
||||||
self.verticalLayout.addWidget(self.progressBar)
|
|
||||||
spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
|
||||||
self.verticalLayout.addItem(spacerItem4)
|
|
||||||
self.verticalLayout.setStretch(0, 2)
|
|
||||||
self.verticalLayout.setStretch(1, 3)
|
|
||||||
self.verticalLayout.setStretch(2, 4)
|
|
||||||
self.verticalLayout.setStretch(3, 1)
|
|
||||||
self.verticalLayout.setStretch(4, 4)
|
|
||||||
self.verticalLayout.setStretch(5, 1)
|
|
||||||
self.verticalLayout.setStretch(6, 2)
|
|
||||||
self.horizontalLayout_2.addLayout(self.verticalLayout)
|
|
||||||
spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
|
||||||
self.horizontalLayout_2.addItem(spacerItem5)
|
|
||||||
self.horizontalLayout_2.setStretch(0, 1)
|
|
||||||
self.horizontalLayout_2.setStretch(1, 2)
|
|
||||||
self.horizontalLayout_2.setStretch(2, 1)
|
|
||||||
self.horizontalLayout_3.addLayout(self.horizontalLayout_2)
|
|
||||||
|
|
||||||
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", "曹雨萱"))
|
|
@ -1,161 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
@File : decrypt.py
|
|
||||||
@Author : Shuaikang Zhou
|
|
||||||
@Time : 2023/1/5 18:13
|
|
||||||
@IDE : Pycharm
|
|
||||||
@Version : Python3.10
|
|
||||||
@comment : ··· 解密数据库,导出原始数据库文件
|
|
||||||
"""
|
|
||||||
import hashlib
|
|
||||||
import time
|
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
|
|
||||||
from PyQt5.QtCore import *
|
|
||||||
from PyQt5.QtGui import *
|
|
||||||
from PyQt5.QtWidgets import *
|
|
||||||
|
|
||||||
from . import decryptUi
|
|
||||||
from ...DataBase import data
|
|
||||||
|
|
||||||
|
|
||||||
class DecryptControl(QWidget, decryptUi.Ui_Dialog):
|
|
||||||
DecryptSignal = pyqtSignal(str)
|
|
||||||
registerSignal = pyqtSignal(str)
|
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super(DecryptControl, self).__init__(parent)
|
|
||||||
self.setupUi(self)
|
|
||||||
self.setWindowTitle('解密')
|
|
||||||
self.setWindowIcon(QIcon('./app/data/icons/logo.svg'))
|
|
||||||
self.btn_db.clicked.connect(self.get_db)
|
|
||||||
self.btn_xml.clicked.connect(self.get_xml)
|
|
||||||
self.pushButton_3.clicked.connect(self.decrypt)
|
|
||||||
self.xml_path: str = None
|
|
||||||
self.db_path: str = None
|
|
||||||
|
|
||||||
def db_exist(self):
|
|
||||||
if data.is_db_exist():
|
|
||||||
self.btnEnterClicked()
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def get_xml(self):
|
|
||||||
self.xml_path, _ = QFileDialog.getOpenFileName(self, 'Open file', r'..', "Xml files (*.xml)")
|
|
||||||
if self.xml_path:
|
|
||||||
self.label_xml.setText('xml已就绪')
|
|
||||||
key = self.parser_xml()
|
|
||||||
self.label_key.setText(f'数据库密钥:{key}')
|
|
||||||
return self.xml_path
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_db(self):
|
|
||||||
self.db_path, _ = QFileDialog.getOpenFileName(self, 'Open file', r'..', "Database files (*.db)")
|
|
||||||
if self.db_path:
|
|
||||||
if ' ' in self.db_path:
|
|
||||||
self.label_db.setText('数据库未就绪')
|
|
||||||
QMessageBox.critical(self, "错误", "db文件路径请不要带有空格\n可以放在D:\\\\data 目录下")
|
|
||||||
self.db_path = ''
|
|
||||||
elif self.db_path.isascii():
|
|
||||||
self.label_db.setText('数据库已就绪')
|
|
||||||
return self.db_path
|
|
||||||
else:
|
|
||||||
self.label_db.setText('数据库未就绪')
|
|
||||||
QMessageBox.critical(self, "错误", "db文件请不要带有中文路径\n可以放在D:\\\\data 目录下")
|
|
||||||
self.db_path = ''
|
|
||||||
return False
|
|
||||||
|
|
||||||
def decrypt(self):
|
|
||||||
if not (self.xml_path and self.db_path):
|
|
||||||
QMessageBox.critical(self, "错误", "请把两个文件加载进来")
|
|
||||||
return
|
|
||||||
key = self.parser_xml()
|
|
||||||
self.label_key.setText(f'数据库密钥:{key}')
|
|
||||||
self.thread1 = MyThread()
|
|
||||||
self.thread1.signal.connect(self.progressBar_view)
|
|
||||||
self.thread1.start()
|
|
||||||
self.thread2 = DecryptThread(self.db_path, key)
|
|
||||||
self.thread2.signal.connect(self.progressBar_view)
|
|
||||||
self.thread2.start()
|
|
||||||
|
|
||||||
def parser_xml(self):
|
|
||||||
if not self.xml_path:
|
|
||||||
return False
|
|
||||||
pid = self.pid(self.xml_path)
|
|
||||||
if not pid:
|
|
||||||
return False
|
|
||||||
key = self.key(pid)
|
|
||||||
return key
|
|
||||||
|
|
||||||
def pid(self, xml_path):
|
|
||||||
tree = ET.parse(xml_path)
|
|
||||||
# 根节点
|
|
||||||
root = tree.getroot()
|
|
||||||
# 标签名
|
|
||||||
for stu in root:
|
|
||||||
if stu.attrib["name"] == '_auth_uin':
|
|
||||||
return stu.attrib['value']
|
|
||||||
return False
|
|
||||||
|
|
||||||
def key(self, uin, IMEI='1234567890ABCDEF'):
|
|
||||||
m = hashlib.md5()
|
|
||||||
m.update(bytes((IMEI + uin).encode('utf-8')))
|
|
||||||
psw = m.hexdigest()
|
|
||||||
return psw[:7]
|
|
||||||
|
|
||||||
def btnEnterClicked(self):
|
|
||||||
# print("enter clicked")
|
|
||||||
# 中间可以添加处理逻辑
|
|
||||||
self.DecryptSignal.emit('ok')
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def progressBar_view(self, value):
|
|
||||||
"""
|
|
||||||
进度条显示
|
|
||||||
:param value: 进度0-100
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
self.progressBar.setProperty('value', value)
|
|
||||||
if value == '99':
|
|
||||||
QMessageBox.information(self, "温馨提示", "我知道你很急\n但你先别急")
|
|
||||||
if value == '100':
|
|
||||||
QMessageBox.information(self, "解密成功", "请退出该界面",
|
|
||||||
QMessageBox.Yes)
|
|
||||||
self.btnExitClicked()
|
|
||||||
data.init_database()
|
|
||||||
|
|
||||||
def btnExitClicked(self):
|
|
||||||
# print("Exit clicked")
|
|
||||||
self.DecryptSignal.emit('ok')
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
|
|
||||||
class DecryptThread(QThread):
|
|
||||||
signal = pyqtSignal(str)
|
|
||||||
|
|
||||||
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):
|
|
||||||
data.decrypt(self.db_path, self.key)
|
|
||||||
self.signal.emit('100')
|
|
||||||
|
|
||||||
|
|
||||||
class MyThread(QThread):
|
|
||||||
signal = pyqtSignal(str)
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super(MyThread, self).__init__()
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
for i in range(100):
|
|
||||||
self.signal.emit(str(i))
|
|
||||||
time.sleep(0.1)
|
|
@ -1,72 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'decryptUi.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(400, 300)
|
|
||||||
self.label_3 = QtWidgets.QLabel(Dialog)
|
|
||||||
self.label_3.setGeometry(QtCore.QRect(110, 20, 221, 51))
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setFamily("一纸情书")
|
|
||||||
font.setPointSize(20)
|
|
||||||
self.label_3.setFont(font)
|
|
||||||
self.label_3.setObjectName("label_3")
|
|
||||||
self.progressBar = QtWidgets.QProgressBar(Dialog)
|
|
||||||
self.progressBar.setGeometry(QtCore.QRect(90, 260, 271, 23))
|
|
||||||
self.progressBar.setProperty("value", 50)
|
|
||||||
self.progressBar.setObjectName("progressBar")
|
|
||||||
self.label_key = QtWidgets.QLabel(Dialog)
|
|
||||||
self.label_key.setGeometry(QtCore.QRect(80, 230, 241, 20))
|
|
||||||
self.label_key.setText("")
|
|
||||||
self.label_key.setObjectName("label_key")
|
|
||||||
self.widget = QtWidgets.QWidget(Dialog)
|
|
||||||
self.widget.setGeometry(QtCore.QRect(80, 80, 245, 134))
|
|
||||||
self.widget.setObjectName("widget")
|
|
||||||
self.verticalLayout = QtWidgets.QVBoxLayout(self.widget)
|
|
||||||
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.verticalLayout.setObjectName("verticalLayout")
|
|
||||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
|
||||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
|
||||||
self.btn_xml = QtWidgets.QPushButton(self.widget)
|
|
||||||
self.btn_xml.setObjectName("btn_xml")
|
|
||||||
self.horizontalLayout.addWidget(self.btn_xml)
|
|
||||||
self.label_xml = QtWidgets.QLabel(self.widget)
|
|
||||||
self.label_xml.setObjectName("label_xml")
|
|
||||||
self.horizontalLayout.addWidget(self.label_xml)
|
|
||||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
|
||||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
|
|
||||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
|
||||||
self.btn_db = QtWidgets.QPushButton(self.widget)
|
|
||||||
self.btn_db.setObjectName("btn_db")
|
|
||||||
self.horizontalLayout_2.addWidget(self.btn_db)
|
|
||||||
self.label_db = QtWidgets.QLabel(self.widget)
|
|
||||||
self.label_db.setObjectName("label_db")
|
|
||||||
self.horizontalLayout_2.addWidget(self.label_db)
|
|
||||||
self.verticalLayout.addLayout(self.horizontalLayout_2)
|
|
||||||
self.pushButton_3 = QtWidgets.QPushButton(self.widget)
|
|
||||||
self.pushButton_3.setObjectName("pushButton_3")
|
|
||||||
self.verticalLayout.addWidget(self.pushButton_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_xml.setText(_translate("Dialog", "点击加载xml文件"))
|
|
||||||
self.label_xml.setText(_translate("Dialog", "xml未就绪"))
|
|
||||||
self.btn_db.setText(_translate("Dialog", "点击加载数据库文件"))
|
|
||||||
self.label_db.setText(_translate("Dialog", "数据库未就绪"))
|
|
||||||
self.pushButton_3.setText(_translate("Dialog", "开始解密数据库"))
|
|
@ -1,146 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
@File : mainview.py
|
|
||||||
@Author : Shuaikang Zhou
|
|
||||||
@Time : 2022/12/13 15:07
|
|
||||||
@IDE : Pycharm
|
|
||||||
@Version : Python3.10
|
|
||||||
@comment : 主窗口
|
|
||||||
"""
|
|
||||||
from PyQt5.QtCore import *
|
|
||||||
from PyQt5.QtGui import *
|
|
||||||
from PyQt5.QtWidgets import *
|
|
||||||
|
|
||||||
from app import config
|
|
||||||
from app.DataBase import data
|
|
||||||
from app.Ui import mainwindow
|
|
||||||
from app.Ui.Icon import Icon
|
|
||||||
from app.Ui.chat import chat
|
|
||||||
from app.Ui.contact import contact
|
|
||||||
from app.components.prompt_bar import PromptBar
|
|
||||||
from app.person import Me
|
|
||||||
|
|
||||||
|
|
||||||
class MainWinController(QMainWindow, mainwindow.Ui_MainWindow):
|
|
||||||
exitSignal = pyqtSignal()
|
|
||||||
|
|
||||||
# username = ''
|
|
||||||
def __init__(self, username, parent=None):
|
|
||||||
super(MainWinController, self).__init__(parent)
|
|
||||||
self.setupUi(self)
|
|
||||||
self.setWindowIcon(Icon.MainWindow_Icon)
|
|
||||||
|
|
||||||
self.setAttribute(Qt.WA_AttributeCount)
|
|
||||||
self.Me = Me(data.get_myinfo())
|
|
||||||
self.chatView = chat.ChatController(self.Me, parent=None)
|
|
||||||
self.lay = QHBoxLayout()
|
|
||||||
self.page_chat.setLayout(self.lay)
|
|
||||||
self.lay.addWidget(self.chatView)
|
|
||||||
|
|
||||||
self.contactView = contact.ContactController(self.Me, parent=None)
|
|
||||||
self.lay0 = QHBoxLayout()
|
|
||||||
self.page_contact.setLayout(self.lay0)
|
|
||||||
self.lay0.addWidget(self.contactView)
|
|
||||||
|
|
||||||
self.btn_chat.clicked.connect(self.chat_view) # 聊天按钮
|
|
||||||
self.btn_contact.clicked.connect(self.contact_view)
|
|
||||||
# self.btn_myinfo.clicked.connect(self.myInfo)
|
|
||||||
self.btn_about.clicked.connect(self.about)
|
|
||||||
self.now_btn = self.btn_chat
|
|
||||||
self.btn_chat.setIcon(Icon.Chat_Icon)
|
|
||||||
self.btn_contact.setIcon(Icon.Contact_Icon)
|
|
||||||
self.btn_myinfo.setIcon(Icon.MyInfo_Icon)
|
|
||||||
self.btn_about.setIcon(Icon.MainWindow_Icon)
|
|
||||||
self.btn_about.setContextMenuPolicy(Qt.CustomContextMenu)
|
|
||||||
self.btn_about.customContextMenuRequested.connect(self.create_rightmenu) # 连接到菜单显示函数
|
|
||||||
self.last_btn = None
|
|
||||||
self.lastView = None
|
|
||||||
self.show_avatar()
|
|
||||||
self.init_ui()
|
|
||||||
self.menubar.setVisible(False)
|
|
||||||
self.statusbar.setVisible(False)
|
|
||||||
self.prompt_bar = PromptBar(self)
|
|
||||||
self.chat_view()
|
|
||||||
|
|
||||||
def init_ui(self):
|
|
||||||
# self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
|
|
||||||
self.menubar.setStyleSheet("background-color: rgb(240, 240, 240);")
|
|
||||||
|
|
||||||
def create_rightmenu(self):
|
|
||||||
# 菜单对象
|
|
||||||
self.groupBox_menu = QMenu(self)
|
|
||||||
|
|
||||||
self.actionA = QAction(QIcon('image/保存.png'), u'保存数据',
|
|
||||||
self) # self.actionA = self.contextMenu.addAction(QIcon("images/0.png"),u'| 动作A')
|
|
||||||
self.actionA.setShortcut('Ctrl+S') # 设置快捷键
|
|
||||||
self.groupBox_menu.addAction(self.actionA) # 把动作A选项添加到菜单
|
|
||||||
|
|
||||||
self.actionB = QAction(QIcon('image/删除.png'), u'删除数据', self)
|
|
||||||
self.groupBox_menu.addAction(self.actionB)
|
|
||||||
|
|
||||||
# self.actionA.triggered.connect(self.button) # 将动作A触发时连接到槽函数 button
|
|
||||||
# self.actionB.triggered.connect(self.button_2)
|
|
||||||
|
|
||||||
self.groupBox_menu.popup(QCursor.pos()) # 声明当鼠标在groupBox控件上右击时,在鼠标位置显示右键菜单 ,exec_,popup两个都可以,
|
|
||||||
|
|
||||||
def show_avatar(self):
|
|
||||||
avatar = self.Me.avatar
|
|
||||||
pixmap = QPixmap(avatar).scaled(60, 60) # 按指定路径找到图片
|
|
||||||
self.myavatar.setPixmap(pixmap) # 在label上显示图片
|
|
||||||
|
|
||||||
def chat_view(self):
|
|
||||||
"""
|
|
||||||
聊天窗口
|
|
||||||
"""
|
|
||||||
self.now_btn = self.btn_chat
|
|
||||||
self.now_btn.setStyleSheet(
|
|
||||||
"QPushButton {background-color: rgb(198,198,198);border:none;}")
|
|
||||||
if self.last_btn and self.last_btn != self.now_btn:
|
|
||||||
self.last_btn.setStyleSheet(
|
|
||||||
"QPushButton {"
|
|
||||||
"background-color: rgb(240,240,240);"
|
|
||||||
"border:none;"
|
|
||||||
"}"
|
|
||||||
"QPushButton:hover{background-color: rgb(209,209,209);}\n"
|
|
||||||
)
|
|
||||||
self.last_btn = self.btn_chat
|
|
||||||
# self.state_lable.setGeometry(20, 300, 32, 32)
|
|
||||||
self.stackedWidget.setCurrentIndex(0)
|
|
||||||
self.chatView.showChat()
|
|
||||||
|
|
||||||
def contact_view(self):
|
|
||||||
"""
|
|
||||||
联系人窗口
|
|
||||||
"""
|
|
||||||
self.now_btn = self.btn_contact
|
|
||||||
self.now_btn.setStyleSheet(
|
|
||||||
"QPushButton {background-color: rgb(198,198,198);border:none;}")
|
|
||||||
if self.last_btn and self.last_btn != self.now_btn:
|
|
||||||
self.last_btn.setStyleSheet("QPushButton {background-color: rgb(240,240,240);border:none;}"
|
|
||||||
"QPushButton:hover{background-color: rgb(209,209,209);}\n")
|
|
||||||
self.last_btn = self.btn_contact
|
|
||||||
# geometry = self.btn_chat.geometry()
|
|
||||||
# self.state_lable.setGeometry(geometry)
|
|
||||||
self.stackedWidget.setCurrentIndex(1)
|
|
||||||
|
|
||||||
def myInfo(self):
|
|
||||||
"""
|
|
||||||
显示我的个人信息
|
|
||||||
"""
|
|
||||||
self.now_btn = self.btn_myinfo
|
|
||||||
self.now_btn.setStyleSheet(
|
|
||||||
"QPushButton {background-color: rgb(198,198,198);}")
|
|
||||||
if self.last_btn and self.last_btn != self.now_btn:
|
|
||||||
self.last_btn.setStyleSheet("QPushButton {background-color: rgb(240,240,240);}"
|
|
||||||
"QPushButton:hover{background-color: rgb(209,209,209);}\n")
|
|
||||||
self.last_btn = self.now_btn
|
|
||||||
|
|
||||||
def about(self):
|
|
||||||
"""
|
|
||||||
关于
|
|
||||||
"""
|
|
||||||
QMessageBox.about(self, "关于",
|
|
||||||
f"版本:{config.version}\n"
|
|
||||||
f"QQ交流群:{config.contact}\n"
|
|
||||||
"地址:https://github.com/LC044/WeChatMsg"
|
|
||||||
)
|
|
@ -1,177 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'mainwindow.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_MainWindow(object):
|
|
||||||
def setupUi(self, MainWindow):
|
|
||||||
MainWindow.setObjectName("MainWindow")
|
|
||||||
MainWindow.resize(1280, 779)
|
|
||||||
MainWindow.setStyleSheet("QPushButton {\n"
|
|
||||||
"background-color: rgb(240,240,240);\n"
|
|
||||||
"border:none;\n"
|
|
||||||
"}\n"
|
|
||||||
"QPushButton:hover{\n"
|
|
||||||
"background-color: rgb(209,209,209);\n"
|
|
||||||
"}\n"
|
|
||||||
" ")
|
|
||||||
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
|
||||||
self.centralwidget.setObjectName("centralwidget")
|
|
||||||
self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
|
|
||||||
self.horizontalLayout.setContentsMargins(0, 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(80, 16777215))
|
|
||||||
self.frame_info.setStyleSheet("background-color:rgb(240,240,240)")
|
|
||||||
self.frame_info.setFrameShape(QtWidgets.QFrame.NoFrame)
|
|
||||||
self.frame_info.setFrameShadow(QtWidgets.QFrame.Plain)
|
|
||||||
self.frame_info.setObjectName("frame_info")
|
|
||||||
self.verticalLayoutWidget = QtWidgets.QWidget(self.frame_info)
|
|
||||||
self.verticalLayoutWidget.setGeometry(QtCore.QRect(0, 190, 77, 271))
|
|
||||||
self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
|
|
||||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
|
|
||||||
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.verticalLayout_2.setSpacing(0)
|
|
||||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
|
||||||
self.btn_chat = QtWidgets.QPushButton(self.verticalLayoutWidget)
|
|
||||||
self.btn_chat.setMinimumSize(QtCore.QSize(0, 60))
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setFamily("微软雅黑")
|
|
||||||
self.btn_chat.setFont(font)
|
|
||||||
self.btn_chat.setStyleSheet("QPushButton {\n"
|
|
||||||
"background-color: rgb(240,240,240);\n"
|
|
||||||
"border:none;\n"
|
|
||||||
"}\n"
|
|
||||||
"QPushButton:hover{background-color: rgb(209,209,209);}\n"
|
|
||||||
" ")
|
|
||||||
self.btn_chat.setAutoDefault(True)
|
|
||||||
self.btn_chat.setDefault(False)
|
|
||||||
self.btn_chat.setFlat(False)
|
|
||||||
self.btn_chat.setObjectName("btn_chat")
|
|
||||||
self.verticalLayout_2.addWidget(self.btn_chat)
|
|
||||||
self.btn_contact = QtWidgets.QPushButton(self.verticalLayoutWidget)
|
|
||||||
self.btn_contact.setMinimumSize(QtCore.QSize(0, 60))
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setFamily("微软雅黑")
|
|
||||||
self.btn_contact.setFont(font)
|
|
||||||
self.btn_contact.setStyleSheet("QPushButton {\n"
|
|
||||||
"background-color: rgb(240,240,240);\n"
|
|
||||||
"border:none;\n"
|
|
||||||
"}\n"
|
|
||||||
"QPushButton:hover{\n"
|
|
||||||
"background-color: rgb(209,209,209);\n"
|
|
||||||
"}\n"
|
|
||||||
" ")
|
|
||||||
self.btn_contact.setDefault(True)
|
|
||||||
self.btn_contact.setFlat(False)
|
|
||||||
self.btn_contact.setObjectName("btn_contact")
|
|
||||||
self.verticalLayout_2.addWidget(self.btn_contact)
|
|
||||||
self.btn_myinfo = QtWidgets.QPushButton(self.verticalLayoutWidget)
|
|
||||||
self.btn_myinfo.setMinimumSize(QtCore.QSize(60, 60))
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setFamily("微软雅黑")
|
|
||||||
self.btn_myinfo.setFont(font)
|
|
||||||
self.btn_myinfo.setFlat(False)
|
|
||||||
self.btn_myinfo.setObjectName("btn_myinfo")
|
|
||||||
self.verticalLayout_2.addWidget(self.btn_myinfo)
|
|
||||||
self.btn_about = QtWidgets.QPushButton(self.verticalLayoutWidget)
|
|
||||||
self.btn_about.setMinimumSize(QtCore.QSize(60, 60))
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setFamily("微软雅黑")
|
|
||||||
self.btn_about.setFont(font)
|
|
||||||
self.btn_about.setStyleSheet("QPushButton {background-color: rgb(240,240,240);}\n"
|
|
||||||
" QPushButton:hover{background-color: rgb(209,209,209);}\n"
|
|
||||||
" ")
|
|
||||||
self.btn_about.setFlat(False)
|
|
||||||
self.btn_about.setObjectName("btn_about")
|
|
||||||
self.verticalLayout_2.addWidget(self.btn_about)
|
|
||||||
self.verticalLayout_2.setStretch(0, 1)
|
|
||||||
self.verticalLayout_2.setStretch(1, 1)
|
|
||||||
self.verticalLayout_2.setStretch(2, 1)
|
|
||||||
self.verticalLayout_2.setStretch(3, 1)
|
|
||||||
self.myavatar = QtWidgets.QLabel(self.frame_info)
|
|
||||||
self.myavatar.setGeometry(QtCore.QRect(10, 40, 60, 60))
|
|
||||||
self.myavatar.setObjectName("myavatar")
|
|
||||||
self.horizontalLayout.addWidget(self.frame_info)
|
|
||||||
self.stackedWidget = QtWidgets.QStackedWidget(self.centralwidget)
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setFamily("微软雅黑")
|
|
||||||
font.setBold(False)
|
|
||||||
font.setWeight(50)
|
|
||||||
self.stackedWidget.setFont(font)
|
|
||||||
self.stackedWidget.setObjectName("stackedWidget")
|
|
||||||
self.page_chat = QtWidgets.QWidget()
|
|
||||||
self.page_chat.setObjectName("page_chat")
|
|
||||||
self.stackedWidget.addWidget(self.page_chat)
|
|
||||||
self.page_contact = QtWidgets.QWidget()
|
|
||||||
self.page_contact.setObjectName("page_contact")
|
|
||||||
self.stackedWidget.addWidget(self.page_contact)
|
|
||||||
self.page_myinfo = QtWidgets.QWidget()
|
|
||||||
self.page_myinfo.setObjectName("page_myinfo")
|
|
||||||
self.stackedWidget.addWidget(self.page_myinfo)
|
|
||||||
self.page_2 = QtWidgets.QWidget()
|
|
||||||
self.page_2.setObjectName("page_2")
|
|
||||||
self.stackedWidget.addWidget(self.page_2)
|
|
||||||
self.horizontalLayout.addWidget(self.stackedWidget)
|
|
||||||
MainWindow.setCentralWidget(self.centralwidget)
|
|
||||||
self.menubar = QtWidgets.QMenuBar(MainWindow)
|
|
||||||
self.menubar.setGeometry(QtCore.QRect(0, 0, 1280, 23))
|
|
||||||
self.menubar.setObjectName("menubar")
|
|
||||||
self.menu_F = QtWidgets.QMenu(self.menubar)
|
|
||||||
self.menu_F.setObjectName("menu_F")
|
|
||||||
self.menu = QtWidgets.QMenu(self.menubar)
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setFamily("微软雅黑")
|
|
||||||
self.menu.setFont(font)
|
|
||||||
self.menu.setObjectName("menu")
|
|
||||||
self.menu_2 = QtWidgets.QMenu(self.menubar)
|
|
||||||
self.menu_2.setObjectName("menu_2")
|
|
||||||
MainWindow.setMenuBar(self.menubar)
|
|
||||||
self.statusbar = QtWidgets.QStatusBar(MainWindow)
|
|
||||||
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 = QtWidgets.QAction(MainWindow)
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setFamily("Microsoft YaHei UI")
|
|
||||||
self.action.setFont(font)
|
|
||||||
self.action.setObjectName("action")
|
|
||||||
self.menu_F.addSeparator()
|
|
||||||
self.menu_F.addSeparator()
|
|
||||||
self.menu_F.addAction(self.action_3)
|
|
||||||
self.menu_F.addAction(self.action_4)
|
|
||||||
self.menu_2.addAction(self.action)
|
|
||||||
self.menubar.addAction(self.menu_F.menuAction())
|
|
||||||
self.menubar.addAction(self.menu.menuAction())
|
|
||||||
self.menubar.addAction(self.menu_2.menuAction())
|
|
||||||
|
|
||||||
self.retranslateUi(MainWindow)
|
|
||||||
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
|
||||||
|
|
||||||
def retranslateUi(self, MainWindow):
|
|
||||||
_translate = QtCore.QCoreApplication.translate
|
|
||||||
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
|
|
||||||
self.btn_chat.setText(_translate("MainWindow", "聊天"))
|
|
||||||
self.btn_contact.setText(_translate("MainWindow", "好友"))
|
|
||||||
self.btn_myinfo.setText(_translate("MainWindow", "我的"))
|
|
||||||
self.btn_about.setText(_translate("MainWindow", "关于"))
|
|
||||||
self.myavatar.setText(_translate("MainWindow", "avatar"))
|
|
||||||
self.menu_F.setTitle(_translate("MainWindow", "文件(F)"))
|
|
||||||
self.menu.setTitle(_translate("MainWindow", "编辑"))
|
|
||||||
self.menu_2.setTitle(_translate("MainWindow", "帮助"))
|
|
||||||
self.action_3.setText(_translate("MainWindow", "保存"))
|
|
||||||
self.action_4.setText(_translate("MainWindow", "退出"))
|
|
||||||
self.action.setText(_translate("MainWindow", "关于"))
|
|
@ -1,40 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
@File : contact.py
|
|
||||||
@Author : Shuaikang Zhou
|
|
||||||
@Time : 2022/12/13 15:07
|
|
||||||
@IDE : Pycharm
|
|
||||||
@Version : Python3.10
|
|
||||||
@comment : ···
|
|
||||||
"""
|
|
||||||
from PyQt5.QtCore import *
|
|
||||||
from PyQt5.QtGui import *
|
|
||||||
from PyQt5.QtWidgets import *
|
|
||||||
|
|
||||||
from .userinfoUi import *
|
|
||||||
from ...DataBase import data
|
|
||||||
|
|
||||||
|
|
||||||
class MyinfoController(QWidget, Ui_Dialog):
|
|
||||||
exitSignal = pyqtSignal()
|
|
||||||
urlSignal = pyqtSignal(QUrl)
|
|
||||||
|
|
||||||
# username = ''
|
|
||||||
|
|
||||||
def __init__(self, Me, parent=None):
|
|
||||||
super(MyinfoController, self).__init__(parent)
|
|
||||||
self.setupUi(self)
|
|
||||||
self.setWindowTitle('WeChat')
|
|
||||||
self.setWindowIcon(QIcon('./app/data/icon.png'))
|
|
||||||
self.Me = Me
|
|
||||||
self.initui()
|
|
||||||
|
|
||||||
def initui(self):
|
|
||||||
self.myinfo = data.get_myInfo()
|
|
||||||
avatar = self.Me.my_avatar
|
|
||||||
pixmap = QPixmap(avatar).scaled(80, 80) # 按指定路径找到图片
|
|
||||||
self.label_avatar.setPixmap(pixmap) # 在label上显示图片
|
|
||||||
self.label_name.setText(self.myinfo['name'])
|
|
||||||
self.label_wxid.setText('微信号:' + self.myinfo['username'])
|
|
||||||
city = f"地区:{self.myinfo['province']}{self.myinfo['city']}"
|
|
||||||
self.label_city.setText(city)
|
|
@ -1,59 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'userinfoUi.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(1120, 720)
|
|
||||||
Dialog.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
|
|
||||||
Dialog.setAutoFillBackground(False)
|
|
||||||
self.frame_2 = QtWidgets.QFrame(Dialog)
|
|
||||||
self.frame_2.setGeometry(QtCore.QRect(0, 0, 1120, 720))
|
|
||||||
self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
|
||||||
self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
|
|
||||||
self.frame_2.setObjectName("frame_2")
|
|
||||||
self.horizontalLayoutWidget = QtWidgets.QWidget(self.frame_2)
|
|
||||||
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(340, 60, 291, 82))
|
|
||||||
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
|
|
||||||
self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
|
|
||||||
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
|
||||||
self.label_avatar = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
|
||||||
self.label_avatar.setMinimumSize(QtCore.QSize(80, 80))
|
|
||||||
self.label_avatar.setObjectName("label_avatar")
|
|
||||||
self.horizontalLayout.addWidget(self.label_avatar)
|
|
||||||
self.verticalLayout = QtWidgets.QVBoxLayout()
|
|
||||||
self.verticalLayout.setObjectName("verticalLayout")
|
|
||||||
self.label_name = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
|
||||||
self.label_name.setObjectName("label_name")
|
|
||||||
self.verticalLayout.addWidget(self.label_name)
|
|
||||||
self.label_wxid = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
|
||||||
self.label_wxid.setObjectName("label_wxid")
|
|
||||||
self.verticalLayout.addWidget(self.label_wxid)
|
|
||||||
self.label_city = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
|
||||||
self.label_city.setObjectName("label_city")
|
|
||||||
self.verticalLayout.addWidget(self.label_city)
|
|
||||||
self.horizontalLayout.addLayout(self.verticalLayout)
|
|
||||||
self.horizontalLayout.setStretch(0, 1)
|
|
||||||
self.horizontalLayout.setStretch(1, 3)
|
|
||||||
|
|
||||||
self.retranslateUi(Dialog)
|
|
||||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
|
||||||
|
|
||||||
def retranslateUi(self, Dialog):
|
|
||||||
_translate = QtCore.QCoreApplication.translate
|
|
||||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
|
||||||
self.label_avatar.setText(_translate("Dialog", "TextLabel"))
|
|
||||||
self.label_name.setText(_translate("Dialog", "TextLabel"))
|
|
||||||
self.label_wxid.setText(_translate("Dialog", "TextLabel"))
|
|
||||||
self.label_city.setText(_translate("Dialog", "TextLabel"))
|
|
108
app/person.py
108
app/person.py
@ -1,108 +0,0 @@
|
|||||||
import os.path
|
|
||||||
from typing import Dict
|
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt
|
|
||||||
from PyQt5.QtGui import QPixmap
|
|
||||||
|
|
||||||
from app.DataBase import data
|
|
||||||
from app.ui_pc.Icon import Icon
|
|
||||||
|
|
||||||
|
|
||||||
# from app.Ui.Icon import Icon
|
|
||||||
|
|
||||||
|
|
||||||
class Person:
|
|
||||||
def __init__(self, wxid: str):
|
|
||||||
|
|
||||||
self.wxid = wxid
|
|
||||||
self.conRemark = data.get_conRemark(wxid)
|
|
||||||
self.nickname, self.alias = data.get_nickname(wxid)
|
|
||||||
self.avatar_path = data.get_avator(wxid)
|
|
||||||
if os.path.exists(self.avatar_path):
|
|
||||||
self.avatar = QPixmap(self.avatar_path).scaled(60, 60)
|
|
||||||
else:
|
|
||||||
self.avatar_path = './app/data/icons/default_avatar.svg'
|
|
||||||
# self.avatar_path = Icon.Default_avatar_path
|
|
||||||
self.avatar = QPixmap(self.avatar_path).scaled(60, 60)
|
|
||||||
|
|
||||||
|
|
||||||
class Me(Person):
|
|
||||||
def __init__(self, wxid: str):
|
|
||||||
super(Me, self).__init__(wxid)
|
|
||||||
self.city = None
|
|
||||||
self.province = None
|
|
||||||
|
|
||||||
|
|
||||||
class Contact(Person):
|
|
||||||
def __init__(self, wxid: str):
|
|
||||||
super(Contact, self).__init__(wxid)
|
|
||||||
self.smallHeadImgUrl = ''
|
|
||||||
self.bigHeadImgUrl = ''
|
|
||||||
|
|
||||||
|
|
||||||
def singleton(cls):
|
|
||||||
_instance = {}
|
|
||||||
|
|
||||||
def inner():
|
|
||||||
if cls not in _instance:
|
|
||||||
_instance[cls] = cls()
|
|
||||||
return _instance[cls]
|
|
||||||
|
|
||||||
return inner
|
|
||||||
|
|
||||||
|
|
||||||
@singleton
|
|
||||||
class MePC:
|
|
||||||
def __init__(self):
|
|
||||||
self.avatar = QPixmap(Icon.Default_avatar_path)
|
|
||||||
self.avatar_path = 'D:\Project\Python\WeChatMsg\\app\data\icons\default_avatar.svg'
|
|
||||||
self.wxid = ''
|
|
||||||
self.wx_dir = ''
|
|
||||||
self.name = ''
|
|
||||||
self.mobile = ''
|
|
||||||
|
|
||||||
def set_avatar(self, img_bytes):
|
|
||||||
if not img_bytes:
|
|
||||||
self.avatar.load(Icon.Default_avatar_path)
|
|
||||||
return
|
|
||||||
if img_bytes[:4] == b'\x89PNG':
|
|
||||||
self.avatar.loadFromData(img_bytes, format='PNG')
|
|
||||||
else:
|
|
||||||
self.avatar.loadFromData(img_bytes, format='jfif')
|
|
||||||
|
|
||||||
|
|
||||||
class ContactPC:
|
|
||||||
def __init__(self, contact_info: Dict):
|
|
||||||
self.wxid = contact_info.get('UserName')
|
|
||||||
self.remark = contact_info.get('Remark')
|
|
||||||
# Alias,Type,Remark,NickName,PYInitial,RemarkPYInitial,ContactHeadImgUrl.smallHeadImgUrl,ContactHeadImgUrl,bigHeadImgUrl
|
|
||||||
self.alias = contact_info.get('Alias')
|
|
||||||
self.nickName = contact_info.get('NickName')
|
|
||||||
if not self.remark:
|
|
||||||
self.remark = self.nickName
|
|
||||||
self.smallHeadImgUrl = contact_info.get('smallHeadImgUrl')
|
|
||||||
self.smallHeadImgBLOG = b''
|
|
||||||
self.avatar = QPixmap()
|
|
||||||
self.avatar_path = 'D:\Project\Python\WeChatMsg\\app\data\icons\default_avatar.svg'
|
|
||||||
|
|
||||||
def set_avatar(self, img_bytes):
|
|
||||||
if not img_bytes:
|
|
||||||
self.avatar.load(Icon.Default_avatar_path)
|
|
||||||
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, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
|
|
||||||
|
|
||||||
|
|
||||||
class Group(Person):
|
|
||||||
def __init__(self, wxid: str):
|
|
||||||
super(Group, self).__init__(wxid)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
p1 = MePC()
|
|
||||||
p2 = MePC()
|
|
||||||
print(p1 == p2)
|
|
@ -5,7 +5,7 @@ from typing import Dict
|
|||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from PyQt5.QtGui import QPixmap
|
from PyQt5.QtGui import QPixmap
|
||||||
|
|
||||||
from app.ui_pc.Icon import Icon
|
from app.ui.Icon import Icon
|
||||||
|
|
||||||
|
|
||||||
def singleton(cls):
|
def singleton(cls):
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
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'
|
|
||||||
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')
|
|
@ -1 +0,0 @@
|
|||||||
from .chat_window import ChatWindow
|
|
@ -1,48 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'chatInfoUi.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, QtWidgets
|
|
||||||
|
|
||||||
|
|
||||||
class Ui_Form(object):
|
|
||||||
def setupUi(self, Form):
|
|
||||||
Form.setObjectName("Form")
|
|
||||||
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
|
|
||||||
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.verticalLayout.setSpacing(0)
|
|
||||||
self.verticalLayout.setObjectName("verticalLayout")
|
|
||||||
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.toolButton = QtWidgets.QToolButton(self.frame)
|
|
||||||
self.toolButton.setObjectName("toolButton")
|
|
||||||
self.horizontalLayout_2.addWidget(self.toolButton)
|
|
||||||
self.verticalLayout_2.addLayout(self.horizontalLayout_2)
|
|
||||||
|
|
||||||
self.verticalLayout.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", "TextLabel"))
|
|
||||||
self.toolButton.setText(_translate("Form", "..."))
|
|
@ -1,74 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'chatUi.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, 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("background:transparent;\n"
|
|
||||||
"border-radius:5px;\n"
|
|
||||||
"border-top: 0px solid #b2e281;\n"
|
|
||||||
"border-bottom: 0px solid #b2e281;\n"
|
|
||||||
"border-right: 0px solid #b2e281;\n"
|
|
||||||
"border-left: 0px solid #b2e281;\n"
|
|
||||||
"border-style:outset;\n"
|
|
||||||
"background-color:rgb(226,226,226);\n"
|
|
||||||
" ")
|
|
||||||
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"))
|
|
@ -1,160 +0,0 @@
|
|||||||
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_pc import MePC
|
|
||||||
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):
|
|
||||||
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 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 = MePC().avatar if is_send else self.contact.avatar
|
|
||||||
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
|
|
||||||
)
|
|
||||||
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, 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)
|
|
@ -1,165 +0,0 @@
|
|||||||
from PyQt5.QtCore import QThread, pyqtSignal
|
|
||||||
from PyQt5.QtWidgets import QWidget, QMessageBox, QAction, QLineEdit
|
|
||||||
|
|
||||||
from app.DataBase import micro_msg_db, misc_db, msg_db
|
|
||||||
from app.components import ContactQListWidgetItem
|
|
||||||
from app.person_pc import ContactPC
|
|
||||||
from app.ui_pc.Icon import Icon
|
|
||||||
from app.util import search
|
|
||||||
from .chatUi import Ui_Form
|
|
||||||
from .chat_info import ChatInfo
|
|
||||||
|
|
||||||
# 美化样式表
|
|
||||||
Stylesheet = """
|
|
||||||
|
|
||||||
/*去掉item虚线边框*/
|
|
||||||
QListWidget, QListView, QTreeWidget, QTreeView {
|
|
||||||
outline: 0px;
|
|
||||||
border:none;
|
|
||||||
background-color:rgb(240,240,240)
|
|
||||||
}
|
|
||||||
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
|
|
||||||
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(204, 204, 204);
|
|
||||||
border-bottom: 2px solid rgb(9, 187, 7);
|
|
||||||
border-left:none;
|
|
||||||
color: black;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
/*鼠标悬停颜色*/
|
|
||||||
HistoryPanel::item:hover {
|
|
||||||
background: rgb(52, 52, 52);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
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.currentRowChanged.connect(self.setCurrentIndex)
|
|
||||||
self.listWidget.setCurrentRow(0)
|
|
||||||
self.stackedWidget.setCurrentIndex(0)
|
|
||||||
|
|
||||||
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):
|
|
||||||
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)
|
|
||||||
self.stackedWidget.setCurrentIndex(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(ContactPC)
|
|
||||||
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 = ContactPC(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(ContactPC)
|
|
||||||
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 +0,0 @@
|
|||||||
from .contact_window import ContactWindow
|
|
@ -1,162 +0,0 @@
|
|||||||
from PyQt5.QtCore import pyqtSignal, QUrl, QThread
|
|
||||||
from PyQt5.QtGui import QDesktopServices
|
|
||||||
from PyQt5.QtWidgets import QWidget, QMenu, QAction, QToolButton, QMessageBox, QDialog
|
|
||||||
|
|
||||||
from app.DataBase.output_pc import Output
|
|
||||||
from app.ui_pc.Icon import Icon
|
|
||||||
from .contactInfoUi import Ui_Form
|
|
||||||
from .userinfo import userinfo
|
|
||||||
from ...person_pc import ContactPC
|
|
||||||
from .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.setupUi(self)
|
|
||||||
self.contact: ContactPC = 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.label_remark.setText(self.contact.remark)
|
|
||||||
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.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)
|
|
||||||
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)
|
|
||||||
|
|
||||||
def toolButton_show(self):
|
|
||||||
self.toolButton_output.showMenu()
|
|
||||||
|
|
||||||
def analysis(self):
|
|
||||||
QMessageBox.warning(self,
|
|
||||||
"别急别急",
|
|
||||||
"马上就实现该功能"
|
|
||||||
)
|
|
||||||
return
|
|
||||||
self.stackedWidget.setCurrentWidget(self.view_analysis)
|
|
||||||
if 'room' in self.contact.wxid:
|
|
||||||
QMessageBox.warning(
|
|
||||||
self, '警告',
|
|
||||||
'暂不支持群组'
|
|
||||||
)
|
|
||||||
return
|
|
||||||
self.view_analysis.start()
|
|
||||||
|
|
||||||
def annual_report(self):
|
|
||||||
# QMessageBox.warning(
|
|
||||||
# self,
|
|
||||||
# "提示",
|
|
||||||
# "敬请期待"
|
|
||||||
# )
|
|
||||||
# return
|
|
||||||
self.contact.save_avatar()
|
|
||||||
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("http://127.0.0.1:21314"))
|
|
||||||
|
|
||||||
def emotionale_Analysis(self):
|
|
||||||
QMessageBox.warning(self,
|
|
||||||
"别急别急",
|
|
||||||
"马上就实现该功能"
|
|
||||||
)
|
|
||||||
return
|
|
||||||
self.stackedWidget.setCurrentWidget(self.view_emotion)
|
|
||||||
if 'room' in self.contact.wxid:
|
|
||||||
QMessageBox.warning(
|
|
||||||
self, '警告',
|
|
||||||
'暂不支持群组'
|
|
||||||
)
|
|
||||||
return
|
|
||||||
self.view_emotion.start()
|
|
||||||
|
|
||||||
def back(self):
|
|
||||||
"""
|
|
||||||
将userinfo界面设置为可见,其他界面设置为不可见
|
|
||||||
"""
|
|
||||||
self.stackedWidget.setCurrentWidget(self.view_userinfo)
|
|
||||||
|
|
||||||
def output(self):
|
|
||||||
"""
|
|
||||||
导出聊天记录
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.stackedWidget.setCurrentWidget(self.view_userinfo)
|
|
||||||
if self.sender() == self.toDocxAct:
|
|
||||||
print('功能暂未实现')
|
|
||||||
QMessageBox.warning(self,
|
|
||||||
"别急别急",
|
|
||||||
"马上就实现该功能"
|
|
||||||
)
|
|
||||||
return
|
|
||||||
self.outputThread = Output(self.Me, self.contact.wxid)
|
|
||||||
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_()获取用户的操作结果
|
|
||||||
|
|
||||||
def hide_progress_bar(self, int):
|
|
||||||
reply = QMessageBox(self)
|
|
||||||
reply.setIcon(QMessageBox.Information)
|
|
||||||
reply.setWindowTitle('OK')
|
|
||||||
reply.setText(f"导出聊天记录成功\n在./data/目录下(跟exe文件在一起)")
|
|
||||||
reply.addButton("确认", QMessageBox.AcceptRole)
|
|
||||||
reply.addButton("取消", QMessageBox.RejectRole)
|
|
||||||
api = reply.exec_()
|
|
||||||
self.view_userinfo.progressBar.setVisible(False)
|
|
||||||
|
|
||||||
def output_progress(self, value):
|
|
||||||
self.view_userinfo.progressBar.setProperty('value', value)
|
|
||||||
|
|
||||||
def set_progressBar_range(self, value):
|
|
||||||
self.view_userinfo.progressBar.setVisible(True)
|
|
||||||
self.view_userinfo.progressBar.setRange(0, value)
|
|
||||||
|
|
||||||
|
|
||||||
class ReportThread(QThread):
|
|
||||||
okSignal = pyqtSignal(bool)
|
|
||||||
|
|
||||||
def __init__(self, contact):
|
|
||||||
super().__init__()
|
|
||||||
self.contact = contact
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
from app.web_ui import web
|
|
||||||
web.contact = self.contact
|
|
||||||
web.run(port='21314')
|
|
||||||
self.okSignal.emit(True)
|
|
@ -1,107 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'contactInfoUi.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_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.label_remark = QtWidgets.QLabel(Form)
|
|
||||||
self.label_remark.setMaximumSize(QtCore.QSize(120, 100))
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setPointSize(12)
|
|
||||||
self.label_remark.setFont(font)
|
|
||||||
self.label_remark.setText("")
|
|
||||||
self.label_remark.setObjectName("label_remark")
|
|
||||||
self.horizontalLayout_3.addWidget(self.label_remark)
|
|
||||||
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.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.horizontalLayout_3.setStretch(0, 1)
|
|
||||||
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.btn_back.setText(_translate("Form", "退出"))
|
|
||||||
self.toolButton_output.setText(_translate("Form", "导出聊天记录"))
|
|
@ -1,74 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'contactUi.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, 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("background:transparent;\n"
|
|
||||||
"border-radius:5px;\n"
|
|
||||||
"border-top: 0px solid #b2e281;\n"
|
|
||||||
"border-bottom: 0px solid #b2e281;\n"
|
|
||||||
"border-right: 0px solid #b2e281;\n"
|
|
||||||
"border-left: 0px solid #b2e281;\n"
|
|
||||||
"border-style:outset;\n"
|
|
||||||
"background-color:rgb(226,226,226);\n"
|
|
||||||
" ")
|
|
||||||
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"))
|
|
@ -1,155 +0,0 @@
|
|||||||
from PyQt5.QtCore import QThread, pyqtSignal
|
|
||||||
from PyQt5.QtWidgets import QWidget, QMessageBox, QAction, QLineEdit
|
|
||||||
|
|
||||||
from app.DataBase import micro_msg_db, misc_db
|
|
||||||
from app.components import ContactQListWidgetItem
|
|
||||||
from app.person_pc import ContactPC
|
|
||||||
from app.ui_pc.Icon import Icon
|
|
||||||
from .contactInfo import ContactInfo
|
|
||||||
from .contactUi import Ui_Form
|
|
||||||
from ...util import search
|
|
||||||
|
|
||||||
# 美化样式表
|
|
||||||
Stylesheet = """
|
|
||||||
QPushButton{
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
QPushButton:hover {
|
|
||||||
background-color: lightgray;
|
|
||||||
}
|
|
||||||
/*去掉item虚线边框*/
|
|
||||||
QListWidget, QListView, QTreeWidget, QTreeView {
|
|
||||||
outline: 0px;
|
|
||||||
border:none;
|
|
||||||
background-color:rgb(240,240,240)
|
|
||||||
}
|
|
||||||
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
|
|
||||||
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(204, 204, 204);
|
|
||||||
border-bottom: 2px solid rgb(9, 187, 7);
|
|
||||||
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.show_thread = None
|
|
||||||
self.setupUi(self)
|
|
||||||
self.ok_flag = False
|
|
||||||
self.setStyleSheet(Stylesheet)
|
|
||||||
self.init_ui()
|
|
||||||
self.contacts = [[], []]
|
|
||||||
self.show_contacts()
|
|
||||||
|
|
||||||
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.currentRowChanged.connect(self.setCurrentIndex)
|
|
||||||
self.listWidget.setCurrentRow(0)
|
|
||||||
self.stackedWidget.setCurrentIndex(0)
|
|
||||||
|
|
||||||
def show_contacts(self):
|
|
||||||
# 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):
|
|
||||||
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: ContactPC):
|
|
||||||
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)
|
|
||||||
contact_info_window = ContactInfo(contact)
|
|
||||||
self.stackedWidget.addWidget(contact_info_window)
|
|
||||||
|
|
||||||
def setCurrentIndex(self, row):
|
|
||||||
# print(row)
|
|
||||||
self.stackedWidget.setCurrentIndex(row)
|
|
||||||
|
|
||||||
|
|
||||||
class ShowContactThread(QThread):
|
|
||||||
showSingal = pyqtSignal(ContactPC)
|
|
||||||
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 = ContactPC(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(ContactPC)
|
|
||||||
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,105 +0,0 @@
|
|||||||
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QDialog, QVBoxLayout, QCheckBox, QHBoxLayout, \
|
|
||||||
QProgressBar, QLabel, QMessageBox
|
|
||||||
|
|
||||||
from app.DataBase.output_pc import Output
|
|
||||||
|
|
||||||
types = {
|
|
||||||
'文本': 1,
|
|
||||||
'图片': 3,
|
|
||||||
'语音': 34,
|
|
||||||
'视频': 43,
|
|
||||||
'表情包': 47,
|
|
||||||
'拍一拍等系统消息': 10000
|
|
||||||
}
|
|
||||||
Stylesheet = """
|
|
||||||
QPushButton{
|
|
||||||
background-color: #ffffff;
|
|
||||||
}
|
|
||||||
QPushButton:hover {
|
|
||||||
background-color: lightgray;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
class ExportDialog(QDialog):
|
|
||||||
def __init__(self, contact=None, title="选择导出的类型", file_type="csv", parent=None):
|
|
||||||
super(ExportDialog, self).__init__(parent)
|
|
||||||
self.setStyleSheet(Stylesheet)
|
|
||||||
self.contact = contact
|
|
||||||
if file_type == 'html':
|
|
||||||
self.export_type = Output.HTML
|
|
||||||
self.export_choices = {"文本": True, "图片": True, "语音": True, "视频": True, "表情包": True,
|
|
||||||
'拍一拍等系统消息': 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} # 定义导出的数据类型,默认全部选择
|
|
||||||
else:
|
|
||||||
self.export_choices = {"文本": True, "图片": True, "视频": True, "表情包": True} # 定义导出的数据类型,默认全部选择
|
|
||||||
self.setWindowTitle(title)
|
|
||||||
layout = QVBoxLayout(self)
|
|
||||||
self.resize(400, 300)
|
|
||||||
self.worker = None # 导出线程
|
|
||||||
self.progress_bar = QProgressBar(self)
|
|
||||||
self.progress_label = QLabel(self)
|
|
||||||
for export_type, default_state in self.export_choices.items():
|
|
||||||
checkbox = QCheckBox(export_type)
|
|
||||||
checkbox.setChecked(default_state)
|
|
||||||
layout.addWidget(checkbox)
|
|
||||||
layout.addWidget(self.progress_bar)
|
|
||||||
layout.addWidget(self.progress_label)
|
|
||||||
hlayout = QHBoxLayout(self)
|
|
||||||
self.export_button = QPushButton("导出")
|
|
||||||
self.export_button.clicked.connect(self.export_data)
|
|
||||||
hlayout.addWidget(self.export_button)
|
|
||||||
|
|
||||||
self.cancel_button = QPushButton("取消")
|
|
||||||
self.cancel_button.clicked.connect(self.reject) # 使用reject关闭对话框
|
|
||||||
hlayout.addWidget(self.cancel_button)
|
|
||||||
layout.addLayout(hlayout)
|
|
||||||
self.setLayout(layout)
|
|
||||||
|
|
||||||
def export_data(self):
|
|
||||||
self.export_button.setEnabled(False)
|
|
||||||
self.cancel_button.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)
|
|
||||||
self.worker.progressSignal.connect(self.update_progress)
|
|
||||||
self.worker.okSignal.connect(self.export_finished)
|
|
||||||
self.worker.start()
|
|
||||||
# self.accept() # 使用accept关闭对话框
|
|
||||||
|
|
||||||
def export_finished(self):
|
|
||||||
self.export_button.setEnabled(True)
|
|
||||||
self.cancel_button.setEnabled(True)
|
|
||||||
reply = QMessageBox(self)
|
|
||||||
reply.setIcon(QMessageBox.Information)
|
|
||||||
reply.setWindowTitle('OK')
|
|
||||||
reply.setText(f"导出聊天记录成功\n在./data/目录下(跟exe文件在一起)")
|
|
||||||
reply.addButton("确认", QMessageBox.AcceptRole)
|
|
||||||
reply.addButton("取消", QMessageBox.RejectRole)
|
|
||||||
api = reply.exec_()
|
|
||||||
self.accept()
|
|
||||||
|
|
||||||
def update_progress(self, progress_percentage):
|
|
||||||
self.progress_bar.setValue(progress_percentage)
|
|
||||||
self.progress_label.setText(f"导出进度: {progress_percentage}%")
|
|
||||||
|
|
||||||
|
|
||||||
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_())
|
|
@ -1,9 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
@File : __init__.py.py
|
|
||||||
@Author : Shuaikang Zhou
|
|
||||||
@Time : 2022/12/24 10:34
|
|
||||||
@IDE : Pycharm
|
|
||||||
@Version : Python3.10
|
|
||||||
@comment : ···
|
|
||||||
"""
|
|
@ -1,15 +0,0 @@
|
|||||||
from PyQt5.QtWidgets import *
|
|
||||||
|
|
||||||
from .userinfoUi import Ui_Frame
|
|
||||||
|
|
||||||
|
|
||||||
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.progressBar.setVisible(False)
|
|
@ -1,123 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'userinfoUi.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_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_3 = QtWidgets.QHBoxLayout(Frame)
|
|
||||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
|
||||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
|
|
||||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
|
||||||
spacerItem = QtWidgets.QSpacerItem(40, 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 = QtWidgets.QGridLayout()
|
|
||||||
self.gridLayout.setHorizontalSpacing(6)
|
|
||||||
self.gridLayout.setObjectName("gridLayout")
|
|
||||||
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.setObjectName("l_avatar")
|
|
||||||
self.gridLayout.addWidget(self.l_avatar, 0, 0, 3, 1)
|
|
||||||
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.setObjectName("l_remark")
|
|
||||||
self.gridLayout.addWidget(self.l_remark, 0, 1, 1, 1)
|
|
||||||
self.l_nickname = QtWidgets.QLabel(Frame)
|
|
||||||
self.l_nickname.setMinimumSize(QtCore.QSize(0, 30))
|
|
||||||
self.l_nickname.setMaximumSize(QtCore.QSize(16777215, 30))
|
|
||||||
self.l_nickname.setObjectName("l_nickname")
|
|
||||||
self.gridLayout.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, 20))
|
|
||||||
self.l_username.setObjectName("l_username")
|
|
||||||
self.gridLayout.addWidget(self.l_username, 2, 1, 1, 1)
|
|
||||||
self.gridLayout.setRowStretch(0, 1)
|
|
||||||
self.gridLayout.setRowStretch(1, 1)
|
|
||||||
self.gridLayout.setRowStretch(2, 1)
|
|
||||||
self.verticalLayout.addLayout(self.gridLayout)
|
|
||||||
spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
|
||||||
self.verticalLayout.addItem(spacerItem2)
|
|
||||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
|
||||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
|
||||||
self.label = QtWidgets.QLabel(Frame)
|
|
||||||
self.label.setMinimumSize(QtCore.QSize(80, 0))
|
|
||||||
self.label.setMaximumSize(QtCore.QSize(80, 16777215))
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setPointSize(15)
|
|
||||||
self.label.setFont(font)
|
|
||||||
self.label.setObjectName("label")
|
|
||||||
self.horizontalLayout.addWidget(self.label)
|
|
||||||
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.horizontalLayout.addWidget(self.lineEdit)
|
|
||||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
|
||||||
spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
|
||||||
self.verticalLayout.addItem(spacerItem3)
|
|
||||||
self.progressBar = QtWidgets.QProgressBar(Frame)
|
|
||||||
self.progressBar.setProperty("value", 24)
|
|
||||||
self.progressBar.setObjectName("progressBar")
|
|
||||||
self.verticalLayout.addWidget(self.progressBar)
|
|
||||||
spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
|
||||||
self.verticalLayout.addItem(spacerItem4)
|
|
||||||
self.verticalLayout.setStretch(0, 2)
|
|
||||||
self.verticalLayout.setStretch(1, 3)
|
|
||||||
self.verticalLayout.setStretch(2, 4)
|
|
||||||
self.verticalLayout.setStretch(3, 1)
|
|
||||||
self.verticalLayout.setStretch(4, 4)
|
|
||||||
self.verticalLayout.setStretch(5, 1)
|
|
||||||
self.verticalLayout.setStretch(6, 2)
|
|
||||||
self.horizontalLayout_2.addLayout(self.verticalLayout)
|
|
||||||
spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
|
||||||
self.horizontalLayout_2.addItem(spacerItem5)
|
|
||||||
self.horizontalLayout_2.setStretch(0, 1)
|
|
||||||
self.horizontalLayout_2.setStretch(1, 2)
|
|
||||||
self.horizontalLayout_2.setStretch(2, 1)
|
|
||||||
self.horizontalLayout_3.addLayout(self.horizontalLayout_2)
|
|
||||||
|
|
||||||
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", "曹雨萱"))
|
|
@ -1,250 +0,0 @@
|
|||||||
# -*- 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
|
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSignal, QUrl, Qt, QThread, QSize
|
|
||||||
from PyQt5.QtGui import QPixmap, QFont, QDesktopServices
|
|
||||||
from PyQt5.QtWidgets import QMainWindow, QLabel, QListWidgetItem, QMessageBox
|
|
||||||
|
|
||||||
from app import config
|
|
||||||
from app.DataBase import msg_db, misc_db, micro_msg_db, hard_link_db
|
|
||||||
from app.ui_pc.Icon import Icon
|
|
||||||
from . import mainwindow
|
|
||||||
from .chat import ChatWindow
|
|
||||||
from .contact import ContactWindow
|
|
||||||
from .tool.tool_window import ToolWindow
|
|
||||||
from ..DataBase.output_pc import Output
|
|
||||||
from ..person_pc import MePC
|
|
||||||
|
|
||||||
# 美化样式表
|
|
||||||
Stylesheet = """
|
|
||||||
|
|
||||||
/*去掉item虚线边框*/
|
|
||||||
QListWidget, QListView, QTreeWidget, QTreeView {
|
|
||||||
outline: 0px;
|
|
||||||
}
|
|
||||||
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
|
|
||||||
QListWidget {
|
|
||||||
min-width: 120px;
|
|
||||||
max-width: 120px;
|
|
||||||
color: black;
|
|
||||||
background: white;
|
|
||||||
border:none;
|
|
||||||
}
|
|
||||||
QListWidget::item{
|
|
||||||
height:60;
|
|
||||||
}
|
|
||||||
/*被选中时的背景颜色和左边框颜色*/
|
|
||||||
QListWidget::item:selected {
|
|
||||||
background: rgb(204, 204, 204);
|
|
||||||
border-left: 4px solid rgb(9, 187, 7);
|
|
||||||
color: black;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
/*鼠标悬停颜色*/
|
|
||||||
HistoryPanel::item:hover {
|
|
||||||
background: rgb(52, 52, 52);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class MainWinController(QMainWindow, mainwindow.Ui_MainWindow):
|
|
||||||
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.setWindowIcon(Icon.MainWindow_Icon)
|
|
||||||
self.setStyleSheet(Stylesheet)
|
|
||||||
self.listWidget.clear()
|
|
||||||
self.resize(QSize(800, 600))
|
|
||||||
self.action_desc.triggered.connect(self.about)
|
|
||||||
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'))
|
|
||||||
|
|
||||||
def load_data(self, flag=True):
|
|
||||||
if os.path.exists('./app/data/info.json'):
|
|
||||||
with open('./app/data/info.json', 'r', encoding='utf-8') as f:
|
|
||||||
dic = json.loads(f.read())
|
|
||||||
wxid = dic.get('wxid')
|
|
||||||
if wxid:
|
|
||||||
me = MePC()
|
|
||||||
me.wxid = dic.get('wxid')
|
|
||||||
me.name = dic.get('name')
|
|
||||||
me.mobile = dic.get('mobile')
|
|
||||||
me.wx_dir = dic.get('wx_dir')
|
|
||||||
self.set_my_info(wxid)
|
|
||||||
self.load_flag = True
|
|
||||||
else:
|
|
||||||
QMessageBox.information(
|
|
||||||
self,
|
|
||||||
'温馨提示',
|
|
||||||
'点击 工具->获取信息 重启后可以显示本人头像哦'
|
|
||||||
)
|
|
||||||
|
|
||||||
def init_ui(self):
|
|
||||||
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_desc.setIcon(Icon.Help_Icon)
|
|
||||||
self.action_help_contact.triggered.connect(
|
|
||||||
lambda: QDesktopServices.openUrl(QUrl("https://blog.lc044.love/post/5")))
|
|
||||||
self.action_help_chat.triggered.connect(
|
|
||||||
lambda: QDesktopServices.openUrl(QUrl("https://blog.lc044.love/post/5")))
|
|
||||||
self.action_help_decrypt.triggered.connect(
|
|
||||||
lambda: QDesktopServices.openUrl(QUrl("https://blog.lc044.love/post/4")))
|
|
||||||
self.listWidget.setVisible(False)
|
|
||||||
self.stackedWidget.setVisible(False)
|
|
||||||
self.listWidget.currentRowChanged.connect(self.setCurrentIndex)
|
|
||||||
tool_item = QListWidgetItem(Icon.Tool_Icon, '工具', self.listWidget)
|
|
||||||
chat_item = QListWidgetItem(Icon.Chat_Icon, '聊天', self.listWidget)
|
|
||||||
contact_item = QListWidgetItem(Icon.Contact_Icon, '好友', self.listWidget)
|
|
||||||
myinfo_item = QListWidgetItem(Icon.Home_Icon, '我的', self.listWidget)
|
|
||||||
tool_window = ToolWindow()
|
|
||||||
tool_window.get_info_signal.connect(self.set_my_info)
|
|
||||||
tool_window.decrypt_success_signal.connect(self.decrypt_success)
|
|
||||||
tool_window.load_finish_signal.connect(self.loading)
|
|
||||||
self.stackedWidget.addWidget(tool_window)
|
|
||||||
self.chat_window = ChatWindow()
|
|
||||||
# chat_window = QWidget()
|
|
||||||
self.stackedWidget.addWidget(self.chat_window)
|
|
||||||
self.contact_window = ContactWindow()
|
|
||||||
self.stackedWidget.addWidget(self.contact_window)
|
|
||||||
label = QLabel('该功能暂不支持哦')
|
|
||||||
label.setFont(QFont("微软雅黑", 50))
|
|
||||||
label.setAlignment(Qt.AlignCenter)
|
|
||||||
self.stackedWidget.addWidget(label)
|
|
||||||
tool_window.load_finish_signal.connect(self.loading)
|
|
||||||
self.statusbar.showMessage('聊天窗口上划到顶部会加载新的聊天记录\n一次不行那就多来几次')
|
|
||||||
self.contact_window.load_finish_signal.connect(self.loading)
|
|
||||||
self.chat_window.load_finish_signal.connect(self.loading)
|
|
||||||
|
|
||||||
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()
|
|
||||||
try:
|
|
||||||
img_bytes = misc_db.get_avatar_buffer(wxid)
|
|
||||||
except AttributeError:
|
|
||||||
return
|
|
||||||
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)
|
|
||||||
me = MePC()
|
|
||||||
me.set_avatar(img_bytes)
|
|
||||||
self.myavatar.setScaledContents(True)
|
|
||||||
self.myavatar.setPixmap(self.avatar)
|
|
||||||
|
|
||||||
def stop_loading(self, a0):
|
|
||||||
self.label.setVisible(False)
|
|
||||||
|
|
||||||
def loading(self, a0):
|
|
||||||
self.load_num += 1
|
|
||||||
# self.label.setVisible(False)
|
|
||||||
print('加载一个了')
|
|
||||||
if self.load_num == 1:
|
|
||||||
print('ok了')
|
|
||||||
self.label.clear()
|
|
||||||
self.label.hide()
|
|
||||||
self.okSignal.emit(True)
|
|
||||||
self.listWidget.setVisible(True)
|
|
||||||
self.stackedWidget.setVisible(True)
|
|
||||||
if self.load_flag:
|
|
||||||
self.listWidget.setCurrentRow(1)
|
|
||||||
self.stackedWidget.setCurrentIndex(1)
|
|
||||||
else:
|
|
||||||
self.listWidget.setCurrentRow(0)
|
|
||||||
self.stackedWidget.setCurrentIndex(0)
|
|
||||||
|
|
||||||
def output(self):
|
|
||||||
if self.sender() == self.action_output_CSV:
|
|
||||||
self.outputThread = Output(None, type_=Output.CSV_ALL)
|
|
||||||
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.okSignal.connect(
|
|
||||||
lambda x: self.message('联系人导出成功'))
|
|
||||||
self.outputThread.start()
|
|
||||||
|
|
||||||
def message(self, msg):
|
|
||||||
QMessageBox.about(self, "提醒", msg)
|
|
||||||
|
|
||||||
def about(self):
|
|
||||||
"""
|
|
||||||
关于
|
|
||||||
"""
|
|
||||||
QMessageBox.about(self, "关于",
|
|
||||||
f'''版本:{config.version}<br>QQ交流群:{config.contact}<br>地址:<a href='https://github.com/LC044/WeChatMsg'>https://github.com/LC044/WeChatMsg</a><br>新特性:<br>{''.join(['' + i for i in config.description])}
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
|
|
||||||
def decrypt_success(self):
|
|
||||||
QMessageBox.about(self, "解密成功", "请重新启动")
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def close(self) -> bool:
|
|
||||||
super().close()
|
|
||||||
misc_db.close()
|
|
||||||
msg_db.close()
|
|
||||||
micro_msg_db.close()
|
|
||||||
hard_link_db.close()
|
|
||||||
self.contact_window.close()
|
|
||||||
self.exitSignal.emit(True)
|
|
||||||
|
|
||||||
|
|
||||||
class LoadWindowThread(QThread):
|
|
||||||
okSignal = pyqtSignal(bool)
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.num = 0
|
|
||||||
|
|
||||||
def loading(self):
|
|
||||||
self.num += 1
|
|
||||||
print('加载一个了')
|
|
||||||
if self.num == 2:
|
|
||||||
self.okSignal.emit(True)
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self.chat_window = ChatWindow()
|
|
||||||
self.contact_window = ContactWindow()
|
|
||||||
self.contact_window.load_finish_signal.connect(self.loading)
|
|
||||||
self.chat_window.load_finish_signal.connect(self.loading)
|
|
||||||
print('加载完成')
|
|
||||||
self.okSignal.emit(True)
|
|
@ -1,179 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'mainwindow.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_MainWindow(object):
|
|
||||||
def setupUi(self, MainWindow):
|
|
||||||
MainWindow.setObjectName("MainWindow")
|
|
||||||
MainWindow.resize(1280, 779)
|
|
||||||
MainWindow.setStyleSheet("\n"
|
|
||||||
" /*去掉item虚线边框*/\n"
|
|
||||||
" QListWidget, QListView, QTreeWidget, QTreeView {\n"
|
|
||||||
" outline: 0px;\n"
|
|
||||||
" }\n"
|
|
||||||
" /*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/\n"
|
|
||||||
" QListWidget {\n"
|
|
||||||
" min-width: 120px;\n"
|
|
||||||
" max-width: 120px;\n"
|
|
||||||
" color: black;\n"
|
|
||||||
" background: white;\n"
|
|
||||||
" border:none;\n"
|
|
||||||
" }\n"
|
|
||||||
" QListWidget::item{\n"
|
|
||||||
" height:80;\n"
|
|
||||||
" }\n"
|
|
||||||
" /*被选中时的背景颜色和左边框颜色*/\n"
|
|
||||||
" QListWidget::item:selected {\n"
|
|
||||||
" background: rgb(204, 204, 204);\n"
|
|
||||||
" border-left: 4px solid rgb(9, 187, 7);\n"
|
|
||||||
" }\n"
|
|
||||||
" /*鼠标悬停颜色*/\n"
|
|
||||||
" HistoryPanel::item:hover {\n"
|
|
||||||
" background: rgb(52, 52, 52);\n"
|
|
||||||
" }\n"
|
|
||||||
" ")
|
|
||||||
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
|
||||||
self.centralwidget.setObjectName("centralwidget")
|
|
||||||
self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
|
|
||||||
self.horizontalLayout.setContentsMargins(0, 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(80, 16777215))
|
|
||||||
self.frame_info.setStyleSheet("background-color:rgb(240,240,240)")
|
|
||||||
self.frame_info.setFrameShape(QtWidgets.QFrame.NoFrame)
|
|
||||||
self.frame_info.setFrameShadow(QtWidgets.QFrame.Plain)
|
|
||||||
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(120, 0))
|
|
||||||
self.listWidget.setMaximumSize(QtCore.QSize(120, 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("微软雅黑")
|
|
||||||
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, 1280, 23))
|
|
||||||
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("微软雅黑")
|
|
||||||
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")
|
|
||||||
self.menu_3 = QtWidgets.QMenu(self.menubar)
|
|
||||||
self.menu_3.setObjectName("menu_3")
|
|
||||||
MainWindow.setMenuBar(self.menubar)
|
|
||||||
self.statusbar = QtWidgets.QStatusBar(MainWindow)
|
|
||||||
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.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_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_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.menubar.addAction(self.menu_3.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.menu_3.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", "导出联系人"))
|
|
@ -1 +0,0 @@
|
|||||||
|
|
@ -1,3 +0,0 @@
|
|||||||
from .pc_decrypt import DecryptControl
|
|
||||||
|
|
||||||
__all__ = ['DecryptControl']
|
|
@ -1,197 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'decryptUi.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(611, 519)
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setFamily("微软雅黑")
|
|
||||||
Dialog.setFont(font)
|
|
||||||
Dialog.setLayoutDirection(QtCore.Qt.LeftToRight)
|
|
||||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout(Dialog)
|
|
||||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
|
||||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
|
|
||||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
|
||||||
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
|
|
||||||
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
|
|
||||||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
|
||||||
self.horizontalLayout_4.addItem(spacerItem)
|
|
||||||
self.btn_help = QtWidgets.QPushButton(Dialog)
|
|
||||||
self.btn_help.setMaximumSize(QtCore.QSize(200, 16777215))
|
|
||||||
self.btn_help.setObjectName("btn_help")
|
|
||||||
self.horizontalLayout_4.addWidget(self.btn_help)
|
|
||||||
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
|
||||||
self.horizontalLayout_4.addItem(spacerItem1)
|
|
||||||
self.verticalLayout_2.addLayout(self.horizontalLayout_4)
|
|
||||||
spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
|
||||||
self.verticalLayout_2.addItem(spacerItem2)
|
|
||||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
|
|
||||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
|
||||||
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
|
||||||
self.horizontalLayout_3.addItem(spacerItem3)
|
|
||||||
self.verticalLayout = QtWidgets.QVBoxLayout()
|
|
||||||
self.verticalLayout.setObjectName("verticalLayout")
|
|
||||||
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_2 = QtWidgets.QGridLayout()
|
|
||||||
self.gridLayout_2.setObjectName("gridLayout_2")
|
|
||||||
self.gridLayout = QtWidgets.QGridLayout()
|
|
||||||
self.gridLayout.setObjectName("gridLayout")
|
|
||||||
self.label_phone = QtWidgets.QLabel(Dialog)
|
|
||||||
self.label_phone.setText("")
|
|
||||||
self.label_phone.setObjectName("label_phone")
|
|
||||||
self.gridLayout.addWidget(self.label_phone, 2, 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.lineEdit = QtWidgets.QLineEdit(Dialog)
|
|
||||||
self.lineEdit.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.setFrame(False)
|
|
||||||
self.lineEdit.setObjectName("lineEdit")
|
|
||||||
self.gridLayout.addWidget(self.lineEdit, 4, 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.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.label = QtWidgets.QLabel(Dialog)
|
|
||||||
self.label.setObjectName("label")
|
|
||||||
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
|
|
||||||
self.label_2 = QtWidgets.QLabel(Dialog)
|
|
||||||
self.label_2.setObjectName("label_2")
|
|
||||||
self.gridLayout.addWidget(self.label_2, 2, 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_name = QtWidgets.QLabel(Dialog)
|
|
||||||
self.label_name.setText("")
|
|
||||||
self.label_name.setObjectName("label_name")
|
|
||||||
self.gridLayout.addWidget(self.label_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_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.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.gridLayout.setColumnMinimumWidth(0, 1)
|
|
||||||
self.gridLayout.setColumnStretch(0, 1)
|
|
||||||
self.gridLayout.setColumnStretch(1, 10)
|
|
||||||
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 2, 1)
|
|
||||||
self.btn_getinfo = QtWidgets.QPushButton(Dialog)
|
|
||||||
self.btn_getinfo.setMinimumSize(QtCore.QSize(0, 60))
|
|
||||||
self.btn_getinfo.setObjectName("btn_getinfo")
|
|
||||||
self.gridLayout_2.addWidget(self.btn_getinfo, 0, 1, 1, 1)
|
|
||||||
self.checkBox = QtWidgets.QCheckBox(Dialog)
|
|
||||||
self.checkBox.setText("")
|
|
||||||
self.checkBox.setObjectName("checkBox")
|
|
||||||
self.gridLayout_2.addWidget(self.checkBox, 0, 2, 1, 1)
|
|
||||||
self.btn_db_dir = QtWidgets.QPushButton(Dialog)
|
|
||||||
self.btn_db_dir.setMinimumSize(QtCore.QSize(0, 60))
|
|
||||||
self.btn_db_dir.setObjectName("btn_db_dir")
|
|
||||||
self.gridLayout_2.addWidget(self.btn_db_dir, 1, 1, 1, 1)
|
|
||||||
self.checkBox_2 = QtWidgets.QCheckBox(Dialog)
|
|
||||||
self.checkBox_2.setText("")
|
|
||||||
self.checkBox_2.setObjectName("checkBox_2")
|
|
||||||
self.gridLayout_2.addWidget(self.checkBox_2, 1, 2, 1, 1)
|
|
||||||
self.verticalLayout.addLayout(self.gridLayout_2)
|
|
||||||
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.pushButton_3 = QtWidgets.QPushButton(Dialog)
|
|
||||||
self.pushButton_3.setMinimumSize(QtCore.QSize(0, 60))
|
|
||||||
self.pushButton_3.setMaximumSize(QtCore.QSize(100, 16777215))
|
|
||||||
self.pushButton_3.setObjectName("pushButton_3")
|
|
||||||
self.horizontalLayout_2.addWidget(self.pushButton_3)
|
|
||||||
self.label_tip = QtWidgets.QLabel(Dialog)
|
|
||||||
self.label_tip.setObjectName("label_tip")
|
|
||||||
self.horizontalLayout_2.addWidget(self.label_tip)
|
|
||||||
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", 50)
|
|
||||||
self.progressBar.setObjectName("progressBar")
|
|
||||||
self.horizontalLayout.addWidget(self.progressBar)
|
|
||||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
|
||||||
self.horizontalLayout_3.addLayout(self.verticalLayout)
|
|
||||||
spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
|
||||||
self.horizontalLayout_3.addItem(spacerItem6)
|
|
||||||
self.verticalLayout_2.addLayout(self.horizontalLayout_3)
|
|
||||||
spacerItem7 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
|
||||||
self.verticalLayout_2.addItem(spacerItem7)
|
|
||||||
self.verticalLayout_3.addLayout(self.verticalLayout_2)
|
|
||||||
|
|
||||||
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_7.setText(_translate("Dialog", "版本"))
|
|
||||||
self.label_5.setText(_translate("Dialog", "微信昵称"))
|
|
||||||
self.label_6.setText(_translate("Dialog", "密钥"))
|
|
||||||
self.label.setText(_translate("Dialog", "PID"))
|
|
||||||
self.label_2.setText(_translate("Dialog", "手机号"))
|
|
||||||
self.label_4.setText(_translate("Dialog", "wxid"))
|
|
||||||
self.label_8.setText(_translate("Dialog", "微信路径"))
|
|
||||||
self.btn_getinfo.setText(_translate("Dialog", "获取信息"))
|
|
||||||
self.btn_db_dir.setText(_translate("Dialog", "设置微信路径"))
|
|
||||||
self.pushButton_3.setText(_translate("Dialog", "开始启动"))
|
|
||||||
self.label_tip.setText(_translate("Dialog", "TextLabel"))
|
|
||||||
self.label_ready.setText(_translate("Dialog", "未就绪"))
|
|
@ -1,259 +0,0 @@
|
|||||||
import json
|
|
||||||
import os.path
|
|
||||||
import time
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSignal, QThread, QUrl, QFile, QIODevice, QTextStream
|
|
||||||
from PyQt5.QtGui import QDesktopServices
|
|
||||||
from PyQt5.QtWidgets import QWidget, QMessageBox, QFileDialog
|
|
||||||
|
|
||||||
from app.DataBase import msg_db, misc_db
|
|
||||||
from app.DataBase.merge import merge_databases, merge_MediaMSG_databases
|
|
||||||
from app.decrypt import get_wx_info, decrypt
|
|
||||||
from app.log import logger
|
|
||||||
from app.util import path
|
|
||||||
from . import decryptUi
|
|
||||||
|
|
||||||
|
|
||||||
class DecryptControl(QWidget, decryptUi.Ui_Dialog):
|
|
||||||
DecryptSignal = pyqtSignal(bool)
|
|
||||||
get_wxidSignal = pyqtSignal(str)
|
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super(DecryptControl, self).__init__(parent)
|
|
||||||
self.setupUi(self)
|
|
||||||
|
|
||||||
self.pushButton_3.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.btn_help.clicked.connect(self.show_help)
|
|
||||||
self.label_tip.setVisible(False)
|
|
||||||
self.info = {}
|
|
||||||
self.lineEdit.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):
|
|
||||||
try:
|
|
||||||
file = QFile(':/data/version_list.json')
|
|
||||||
if file.open(QIODevice.ReadOnly | QIODevice.Text):
|
|
||||||
stream = QTextStream(file)
|
|
||||||
content = stream.readAll()
|
|
||||||
file.close()
|
|
||||||
VERSION_LIST = json.loads(content)
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
result = get_wx_info.get_info(VERSION_LIST)
|
|
||||||
print(result)
|
|
||||||
if result == -1:
|
|
||||||
QMessageBox.critical(self, "错误", "请登录微信")
|
|
||||||
elif result == -2:
|
|
||||||
QMessageBox.critical(self, "错误", "微信版本不匹配\n请更新微信版本为:3.9.8.15")
|
|
||||||
elif result == -3:
|
|
||||||
QMessageBox.critical(self, "错误", "WeChat WeChatWin.dll Not Found")
|
|
||||||
else:
|
|
||||||
self.ready = True
|
|
||||||
self.info = result[0]
|
|
||||||
self.label_key.setText(self.info['key'])
|
|
||||||
self.lineEdit.setText(self.info['wxid'])
|
|
||||||
self.label_name.setText(self.info['name'])
|
|
||||||
self.label_phone.setText(self.info['mobile'])
|
|
||||||
self.label_pid.setText(str(self.info['pid']))
|
|
||||||
self.label_version.setText(self.info['version'])
|
|
||||||
self.lineEdit.setFocus()
|
|
||||||
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.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('已就绪')
|
|
||||||
except Exception as e:
|
|
||||||
QMessageBox.critical(self, "未知错误", "请收集报错信息,发起issue解决问题")
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
def set_wxid_(self):
|
|
||||||
self.info['wxid'] = self.lineEdit.text()
|
|
||||||
|
|
||||||
def set_wxid(self):
|
|
||||||
self.info['wxid'] = self.lineEdit.text()
|
|
||||||
QMessageBox.information(self, "ok", f"wxid修改成功{self.info['wxid']}")
|
|
||||||
|
|
||||||
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.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.lineEdit.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请检查微信版本是否为最新和微信路径是否正确")
|
|
||||||
self.label_tip.setVisible(True)
|
|
||||||
self.label_tip.setText('点我之后没有反应那就多等儿吧,不要再点了')
|
|
||||||
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请检查微信版本是否为最新和微信路径是否正确")
|
|
||||||
)
|
|
||||||
self.thread2.start()
|
|
||||||
|
|
||||||
def btnEnterClicked(self):
|
|
||||||
# print("enter clicked")
|
|
||||||
# 中间可以添加处理逻辑
|
|
||||||
# QMessageBox.about(self, "解密成功", "数据库文件存储在app/DataBase/Msg文件夹下")
|
|
||||||
|
|
||||||
self.DecryptSignal.emit(True)
|
|
||||||
# self.close()
|
|
||||||
|
|
||||||
def setProgressBarMaxNum(self, 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']
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
os.makedirs('./app/data', exist_ok=True)
|
|
||||||
with open('./app/data/info.json', 'w', encoding='utf-8') as f:
|
|
||||||
f.write(json.dumps(dic))
|
|
||||||
except:
|
|
||||||
with open('./info.json', 'w', encoding='utf-8') as f:
|
|
||||||
f.write(json.dumps(dic))
|
|
||||||
# 目标数据库文件
|
|
||||||
target_database = "app/DataBase/Msg/MSG.db"
|
|
||||||
# 源数据库文件列表
|
|
||||||
source_databases = [f"app/DataBase/Msg/MSG{i}.db" for i in range(1, 20)]
|
|
||||||
import shutil
|
|
||||||
shutil.copy("app/DataBase/Msg/MSG0.db", target_database) # 使用一个数据库文件作为模板
|
|
||||||
# 合并数据库
|
|
||||||
try:
|
|
||||||
merge_databases(source_databases, target_database)
|
|
||||||
except FileNotFoundError:
|
|
||||||
QMessageBox.critical(self, "错误", "数据库不存在\n请检查微信版本是否为最新")
|
|
||||||
|
|
||||||
# 音频数据库文件
|
|
||||||
target_database = "app/DataBase/Msg/MediaMSG.db"
|
|
||||||
# 源数据库文件列表
|
|
||||||
source_databases = [f"app/DataBase/Msg/MediaMSG{i}.db" for i in range(1, 20)]
|
|
||||||
import shutil
|
|
||||||
shutil.copy("app/DataBase/Msg/MediaMSG0.db", target_database) # 使用一个数据库文件作为模板
|
|
||||||
# 合并数据库
|
|
||||||
try:
|
|
||||||
merge_MediaMSG_databases(source_databases, target_database)
|
|
||||||
except FileNotFoundError:
|
|
||||||
QMessageBox.critical(self, "错误", "数据库不存在\n请检查微信版本是否为最新")
|
|
||||||
|
|
||||||
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):
|
|
||||||
misc_db.close()
|
|
||||||
msg_db.close()
|
|
||||||
# micro_msg_db.close()
|
|
||||||
# hard_link_db.close()
|
|
||||||
output_dir = 'app/DataBase/Msg'
|
|
||||||
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])
|
|
||||||
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)
|
|
||||||
self.okSignal.emit('ok')
|
|
||||||
# self.signal.emit('100')
|
|
||||||
|
|
||||||
|
|
||||||
class MyThread(QThread):
|
|
||||||
signal = pyqtSignal(str)
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super(MyThread, self).__init__()
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
for i in range(100):
|
|
||||||
self.signal.emit(str(i))
|
|
||||||
time.sleep(0.1)
|
|
@ -1,83 +0,0 @@
|
|||||||
# -*- 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.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)
|
|
@ -1,89 +0,0 @@
|
|||||||
from PyQt5.QtCore import Qt, pyqtSignal
|
|
||||||
from PyQt5.QtGui import QFont
|
|
||||||
from PyQt5.QtWidgets import QWidget, QListWidgetItem, QLabel
|
|
||||||
|
|
||||||
from app.ui_pc.Icon import Icon
|
|
||||||
from .pc_decrypt import DecryptControl
|
|
||||||
from .toolUI import Ui_Dialog
|
|
||||||
|
|
||||||
# 美化样式表
|
|
||||||
Stylesheet = """
|
|
||||||
QPushButton{
|
|
||||||
background-color: #ffffff;
|
|
||||||
}
|
|
||||||
QPushButton:hover {
|
|
||||||
background-color: lightgray;
|
|
||||||
}
|
|
||||||
/*去掉item虚线边框*/
|
|
||||||
QListWidget, QListView, QTreeWidget, QTreeView {
|
|
||||||
outline: 0px;
|
|
||||||
border:none;
|
|
||||||
background-color:rgb(240,240,240)
|
|
||||||
}
|
|
||||||
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
|
|
||||||
QListWidget {
|
|
||||||
min-width: 400px;
|
|
||||||
max-width: 400px;
|
|
||||||
min-height: 80px;
|
|
||||||
max-height: 80px;
|
|
||||||
color: black;
|
|
||||||
border:none;
|
|
||||||
}
|
|
||||||
QListWidget::item{
|
|
||||||
height:80px;
|
|
||||||
width:80px;
|
|
||||||
}
|
|
||||||
/*被选中时的背景颜色和左边框颜色*/
|
|
||||||
QListWidget::item:selected {
|
|
||||||
background: rgb(204, 204, 204);
|
|
||||||
border-bottom: 4px solid rgb(9, 187, 7);
|
|
||||||
border-left:none;
|
|
||||||
color: black;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
/*鼠标悬停颜色*/
|
|
||||||
HistoryPanel::item:hover {
|
|
||||||
background: rgb(52, 52, 52);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
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.Chat_Icon, '解密', self.listWidget)
|
|
||||||
contact_item = QListWidgetItem(Icon.Contact_Icon, '别点', self.listWidget)
|
|
||||||
myinfo_item = QListWidgetItem(Icon.MyInfo_Icon, '别点', self.listWidget)
|
|
||||||
tool_item = QListWidgetItem(Icon.MyInfo_Icon, '别点', self.listWidget)
|
|
||||||
decrypt_window = DecryptControl()
|
|
||||||
decrypt_window.get_wxidSignal.connect(self.get_info_signal)
|
|
||||||
decrypt_window.DecryptSignal.connect(self.decrypt_success_signal)
|
|
||||||
self.stackedWidget.addWidget(decrypt_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.stackedWidget.addWidget(label)
|
|
||||||
self.stackedWidget.addWidget(label)
|
|
||||||
self.listWidget.setCurrentRow(0)
|
|
||||||
self.stackedWidget.setCurrentIndex(0)
|
|
||||||
|
|
||||||
def setCurrentIndex(self, row):
|
|
||||||
print(row)
|
|
||||||
self.stackedWidget.setCurrentIndex(row)
|
|
@ -1,41 +0,0 @@
|
|||||||
import ctypes
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from PyQt5.QtGui import QIcon
|
|
||||||
from PyQt5.QtWidgets import QApplication, QMessageBox, QWidget
|
|
||||||
|
|
||||||
from app.resources import resource_rc
|
|
||||||
from app.ui_pc.tool.pc_decrypt import pc_decrypt
|
|
||||||
|
|
||||||
var = resource_rc.qt_resource_name
|
|
||||||
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("WeChatReport")
|
|
||||||
|
|
||||||
|
|
||||||
class ViewController(QWidget):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.setWindowTitle('解密')
|
|
||||||
self.setWindowIcon(QIcon(':/icons/icons/logo.svg'))
|
|
||||||
self.viewMainWIn = None
|
|
||||||
self.viewDecrypt = None
|
|
||||||
|
|
||||||
def loadPCDecryptView(self):
|
|
||||||
"""
|
|
||||||
登录界面
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.viewDecrypt = pc_decrypt.DecryptControl(self)
|
|
||||||
self.viewDecrypt.DecryptSignal.connect(self.show_success)
|
|
||||||
# self.viewDecrypt.show()
|
|
||||||
|
|
||||||
def show_success(self):
|
|
||||||
QMessageBox.about(self, "解密成功", "数据库文件存储在\napp/DataBase/Msg\n文件夹下")
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
view = ViewController()
|
|
||||||
view.loadPCDecryptView()
|
|
||||||
view.show()
|
|
||||||
sys.exit(app.exec_())
|
|
@ -56,7 +56,7 @@ pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
|
|||||||
1. 运行程序
|
1. 运行程序
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
python main_pc.py
|
python main.py
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 选择联系人
|
2. 选择联系人
|
||||||
|
65
main.py
65
main.py
@ -1,40 +1,31 @@
|
|||||||
import ctypes
|
import ctypes
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from PyQt5.QtGui import QFont
|
||||||
from PyQt5.QtWidgets import *
|
from PyQt5.QtWidgets import *
|
||||||
|
|
||||||
import app.DataBase.data as DB
|
from app.log import logger
|
||||||
from app.Ui import decrypt, mainview
|
from app.ui import mainview
|
||||||
|
from app.ui.tool.pc_decrypt import pc_decrypt
|
||||||
|
from app.config import version
|
||||||
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("WeChatReport")
|
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("WeChatReport")
|
||||||
|
|
||||||
|
|
||||||
class ViewController:
|
class ViewController(QWidget):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.viewMainWIn = None
|
super().__init__()
|
||||||
|
self.viewMainWindow = None
|
||||||
self.viewDecrypt = None
|
self.viewDecrypt = None
|
||||||
|
|
||||||
def loadDecryptView(self):
|
|
||||||
"""
|
|
||||||
登录界面
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if DB.is_db_exist():
|
|
||||||
self.loadMainWinView()
|
|
||||||
else:
|
|
||||||
self.viewDecrypt = decrypt.DecryptControl() # 需要将view login设为成员变量
|
|
||||||
self.viewDecrypt.DecryptSignal.connect(self.loadMainWinView)
|
|
||||||
self.viewDecrypt.show()
|
|
||||||
self.viewDecrypt.db_exist()
|
|
||||||
|
|
||||||
def loadPCDecryptView(self):
|
def loadPCDecryptView(self):
|
||||||
"""
|
"""
|
||||||
登录界面
|
登录界面
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
self.viewDecrypt = pc_decrypt.DecryptControl()
|
self.viewDecrypt = pc_decrypt.DecryptControl()
|
||||||
self.viewDecrypt.DecryptSignal.connect(self.loadMainWinView)
|
self.viewDecrypt.DecryptSignal.connect(self.show_success)
|
||||||
self.viewDecrypt.show()
|
self.viewDecrypt.show()
|
||||||
|
|
||||||
def loadMainWinView(self, username=None):
|
def loadMainWinView(self, username=None):
|
||||||
@ -45,21 +36,31 @@ class ViewController:
|
|||||||
"""
|
"""
|
||||||
username = ''
|
username = ''
|
||||||
start = time.time()
|
start = time.time()
|
||||||
self.viewMainWIn = mainview.MainWinController(username=username)
|
self.viewMainWindow = mainview.MainWinController(username=username)
|
||||||
self.viewMainWIn.setWindowTitle("Chat")
|
self.viewMainWindow.exitSignal.connect(self.close)
|
||||||
# print(username)
|
try:
|
||||||
self.viewMainWIn.username = username
|
self.viewMainWindow.setWindowTitle(f"留痕-{version}")
|
||||||
# self.viewMainWIn.exitSignal.connect(self.loadDecryptView) # 不需要回到登录界面可以省略
|
self.viewMainWindow.show()
|
||||||
self.viewMainWIn.show()
|
end = time.time()
|
||||||
end = time.time()
|
print('ok', '本次加载用了', end - start, 's')
|
||||||
print('ok', end - start)
|
self.viewMainWindow.init_ui()
|
||||||
# self.viewMainWIn.signUp()
|
except Exception as e:
|
||||||
|
print(f"Exception: {e}")
|
||||||
|
logger.error(traceback.print_exc())
|
||||||
|
|
||||||
|
def show_success(self):
|
||||||
|
QMessageBox.about(self, "解密成功", "数据库文件存储在\napp/DataBase/Msg\n文件夹下")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
view = ViewController()
|
view = ViewController()
|
||||||
# view.loadPCDecryptView()
|
try:
|
||||||
view.loadDecryptView() # 进入登录界面,如果view login不是成员变量,则离开作用域后失效。
|
# view.loadPCDecryptView()
|
||||||
# view.loadMainWinView('102')
|
view.loadMainWinView()
|
||||||
sys.exit(app.exec_())
|
# view.show()
|
||||||
|
# view.show_success()
|
||||||
|
sys.exit(app.exec_())
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Exception: {e}")
|
||||||
|
logger.error(traceback.print_exc())
|
||||||
|
66
main_pc.py
66
main_pc.py
@ -1,66 +0,0 @@
|
|||||||
import ctypes
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
from PyQt5.QtGui import QFont
|
|
||||||
from PyQt5.QtWidgets import *
|
|
||||||
|
|
||||||
from app.log import logger
|
|
||||||
from app.ui_pc import mainview
|
|
||||||
from app.ui_pc.tool.pc_decrypt import pc_decrypt
|
|
||||||
from app.config import version
|
|
||||||
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("WeChatReport")
|
|
||||||
|
|
||||||
|
|
||||||
class ViewController(QWidget):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.viewMainWindow = None
|
|
||||||
self.viewDecrypt = None
|
|
||||||
|
|
||||||
def loadPCDecryptView(self):
|
|
||||||
"""
|
|
||||||
登录界面
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.viewDecrypt = pc_decrypt.DecryptControl()
|
|
||||||
self.viewDecrypt.DecryptSignal.connect(self.show_success)
|
|
||||||
self.viewDecrypt.show()
|
|
||||||
|
|
||||||
def loadMainWinView(self, username=None):
|
|
||||||
"""
|
|
||||||
聊天界面
|
|
||||||
:param username: 账号
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
username = ''
|
|
||||||
start = time.time()
|
|
||||||
self.viewMainWindow = mainview.MainWinController(username=username)
|
|
||||||
self.viewMainWindow.exitSignal.connect(self.close)
|
|
||||||
try:
|
|
||||||
self.viewMainWindow.setWindowTitle(f"留痕-{version}")
|
|
||||||
self.viewMainWindow.show()
|
|
||||||
end = time.time()
|
|
||||||
print('ok', '本次加载用了', end - start, 's')
|
|
||||||
self.viewMainWindow.init_ui()
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Exception: {e}")
|
|
||||||
logger.error(traceback.print_exc())
|
|
||||||
|
|
||||||
def show_success(self):
|
|
||||||
QMessageBox.about(self, "解密成功", "数据库文件存储在\napp/DataBase/Msg\n文件夹下")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
view = ViewController()
|
|
||||||
try:
|
|
||||||
# view.loadPCDecryptView()
|
|
||||||
view.loadMainWinView()
|
|
||||||
# view.show()
|
|
||||||
# view.show_success()
|
|
||||||
sys.exit(app.exec_())
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Exception: {e}")
|
|
||||||
logger.error(traceback.print_exc())
|
|
66
readme.md
66
readme.md
@ -97,7 +97,7 @@
|
|||||||
# Python>=3.10
|
# Python>=3.10
|
||||||
git clone https://github.com/LC044/WeChatMsg
|
git clone https://github.com/LC044/WeChatMsg
|
||||||
cd WeChatMsg
|
cd WeChatMsg
|
||||||
pip install -r requirements_pc.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
|
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 使用
|
### 2. 使用
|
||||||
@ -113,7 +113,7 @@ pip install -r requirements_pc.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
|
|||||||
2. 运行程序
|
2. 运行程序
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
python main_pc.py
|
python main.py
|
||||||
```
|
```
|
||||||
|
|
||||||
3. 点击获取信息
|
3. 点击获取信息
|
||||||
@ -188,13 +188,6 @@ python main_pc.py
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
如果您遇到下图所示的问题,需要先运行`decrypt_window`的可执行文件或者源代码文件
|
|
||||||
|
|
||||||
```
|
|
||||||
python decrypt_window.py
|
|
||||||
```
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
如果您在运行可执行程序的时候出现闪退的现象,请右击软件使用管理员权限运行。
|
如果您在运行可执行程序的时候出现闪退的现象,请右击软件使用管理员权限运行。
|
||||||
|
|
||||||
@ -205,7 +198,7 @@ python decrypt_window.py
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
如果出现如图所示的报错信息,将`app/database/msg`文件夹删除,重新运行`main_pc.py`。
|
如果出现如图所示的报错信息,将`app/database/msg`文件夹删除,重新运行`main.py`。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@ -221,59 +214,6 @@ python decrypt_window.py
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## 使用模拟器(支持可视化分析)
|
|
||||||
|
|
||||||
<details>
|
|
||||||
|
|
||||||
**不推荐使用,PC端微信可视化功能马上实现**
|
|
||||||
|
|
||||||
1. 根据[教程](https://blog.csdn.net/m0_59452630/article/details/124222235?spm=1001.2014.3001.5501)获得两个文件
|
|
||||||
- auth_info_key_prefs.xml——解析数据库密码
|
|
||||||
- EnMicroMsg.db——聊天数据库
|
|
||||||
- **上面这两个文件就可以**
|
|
||||||
2. 安装依赖库
|
|
||||||
|
|
||||||
python版本>=3.10
|
|
||||||
|
|
||||||
**说明:用到了python3.10的match语法,不方便更换python版本的小伙伴可以把match(运行报错的地方)更改为if else**
|
|
||||||
|
|
||||||
命令行运行以下代码(**建议使用Pycharm打开项目,Pycharm会自动配置好所有东西,直接运行main.py即可**)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
|
|
||||||
```
|
|
||||||
|
|
||||||
运行main.py
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python main.py
|
|
||||||
```
|
|
||||||
|
|
||||||
3. 出现解密界面
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
按照提示选择上面获得的两个文件,等待解密完成,重新运行程序
|
|
||||||
|
|
||||||
4. 进入主界面
|
|
||||||
|
|
||||||
这时候不显示头像,因为头像文件没有导入进来
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
根据[教程](https://blog.csdn.net/m0_59452630/article/details/124222235?spm=1001.2014.3001.5501)
|
|
||||||
将头像文件夹avatar复制到工程目录./app/data/目录下
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
如果想要显示聊天图像就把[教程](https://blog.csdn.net/m0_59452630/article/details/124222235?spm=1001.2014.3001.5501)
|
|
||||||
里的image2文件夹复制到./app/data文件夹里,效果跟上图一样
|
|
||||||
|
|
||||||
复制进来之后再运行程序就有图像了
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
# 🏆致谢
|
# 🏆致谢
|
||||||
|
|
||||||
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
@ -1,10 +0,0 @@
|
|||||||
PyQt5
|
|
||||||
psutil
|
|
||||||
pycryptodomex
|
|
||||||
pywin32
|
|
||||||
pymem
|
|
||||||
silk-python
|
|
||||||
pyaudio
|
|
||||||
fuzzywuzzy
|
|
||||||
python-Levenshtein
|
|
||||||
lz4
|
|
@ -1,19 +0,0 @@
|
|||||||
PyQt5
|
|
||||||
psutil
|
|
||||||
pycryptodomex
|
|
||||||
pywin32
|
|
||||||
pymem
|
|
||||||
silk-python
|
|
||||||
pyaudio
|
|
||||||
fuzzywuzzy
|
|
||||||
python-Levenshtein
|
|
||||||
Pillow==10.1.0
|
|
||||||
requests
|
|
||||||
flask==3.0.0
|
|
||||||
pyecharts==2.0.1
|
|
||||||
jieba==0.42.1
|
|
||||||
google==3.0.0
|
|
||||||
protobuf==4.25.1
|
|
||||||
soupsieve==2.5
|
|
||||||
lz4==4.3.2
|
|
||||||
pilk==0.2.4
|
|
@ -1,5 +0,0 @@
|
|||||||
PRAGMA key = '10f35f1';
|
|
||||||
PRAGMA cipher_migrate;
|
|
||||||
ATTACH DATABASE 'plaintext.db' AS plaintext KEY '';
|
|
||||||
SELECT sqlcipher_export('plaintext');
|
|
||||||
DETACH DATABASE plaintext;
|
|
@ -1,3 +0,0 @@
|
|||||||
1.将要加密的数据名称改为encrypt.db,并放到当前bin目录下
|
|
||||||
2.编辑adb.txt 文件 PRAGMA key = 'password';这里的password是加密数据的密码
|
|
||||||
3.修改保存完,双击sqlcipher.bat文件
|
|
@ -1,3 +0,0 @@
|
|||||||
sqlcipher-shell32.exe encrypt.db < adb.txt
|
|
||||||
echo 解密完成
|
|
||||||
pause
|
|
Binary file not shown.
Binary file not shown.
@ -1,3 +0,0 @@
|
|||||||
sqlcipher-shell32.exe encrypt.db < adb.txt
|
|
||||||
echo 解密完成
|
|
||||||
pause
|
|
Loading…
Reference in New Issue
Block a user