mirror of
https://github.com/LC044/WeChatMsg
synced 2025-02-21 01:52:35 +08:00
修复HTML卡顿的问题
This commit is contained in:
parent
12b14316ce
commit
3414d74bed
@ -4,19 +4,10 @@
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="84e65474-7da9-466d-baf3-cc88dde3ffdd" name="变更" comment="支持显示聊天图片">
|
||||
<list default="true" id="84e65474-7da9-466d-baf3-cc88dde3ffdd" name="变更" comment="支持导出HTML">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/DataBase/msg.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/DataBase/msg.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/DataBase/output_pc.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/DataBase/output_pc.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/data/html/0.html" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/data/html/1.html" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/data/html/2.html" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/data/html/3.html" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/data/html/4.html" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/data/html/5.html" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/data/html/6.html" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/data/html/index.html" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/person.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/person.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/ui_pc/chat/chat_info.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/chat/chat_info.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/ui_pc/contact/contactInfo.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/contact/contactInfo.py" afterDir="false" />
|
||||
</list>
|
||||
@ -289,13 +280,6 @@
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1672848140146</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00038" summary="修复部分bug">
|
||||
<created>1698853140384</created>
|
||||
<option name="number" value="00038" />
|
||||
<option name="presentableId" value="LOCAL-00038" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1698853140384</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00039" summary="替换chat里的contact">
|
||||
<created>1698940208580</created>
|
||||
<option name="number" value="00039" />
|
||||
@ -632,7 +616,14 @@
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1700574536724</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="87" />
|
||||
<task id="LOCAL-00087" summary="支持导出HTML">
|
||||
<created>1700576604990</created>
|
||||
<option name="number" value="00087" />
|
||||
<option name="presentableId" value="LOCAL-00087" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1700576604990</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="88" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="UnknownFeatures">
|
||||
@ -668,7 +659,6 @@
|
||||
</option>
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<MESSAGE value="修改UI" />
|
||||
<MESSAGE value="新增联系人头像组件" />
|
||||
<MESSAGE value="头像支持显示二进制" />
|
||||
<MESSAGE value="显示联系人信息" />
|
||||
@ -693,7 +683,8 @@
|
||||
<MESSAGE value="更新wx选择的路径" />
|
||||
<MESSAGE value="显示聊天图片" />
|
||||
<MESSAGE value="支持显示聊天图片" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="支持显示聊天图片" />
|
||||
<MESSAGE value="支持导出HTML" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="支持导出HTML" />
|
||||
<option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="true" />
|
||||
<option name="REFORMAT_BEFORE_PROJECT_COMMIT" value="true" />
|
||||
</component>
|
||||
|
@ -67,7 +67,7 @@ def get_message_by_num(username_, local_id):
|
||||
from MSG
|
||||
where StrTalker = ? and localId < ?
|
||||
order by CreateTime desc
|
||||
limit 30
|
||||
limit 10
|
||||
'''
|
||||
result = []
|
||||
try:
|
||||
|
@ -54,224 +54,7 @@ class Output(QThread):
|
||||
self.okSignal.emit('ok')
|
||||
|
||||
def to_html(self):
|
||||
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
|
||||
if not os.path.exists(origin_docx_path):
|
||||
os.mkdir(origin_docx_path)
|
||||
messages = msg.get_messages(self.contact.wxid)
|
||||
filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}.html"
|
||||
f = open(filename, 'w', encoding='utf-8')
|
||||
html_head = '''
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
<style>
|
||||
|
||||
*{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
body{
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.container{
|
||||
height: 760px;
|
||||
width: 900px;
|
||||
border-radius: 4px;
|
||||
border: 0.5px solid #e0e0e0;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.content{
|
||||
width: calc(100% - 40px);
|
||||
padding: 20px;
|
||||
overflow-y: scroll;
|
||||
flex: 1;
|
||||
}
|
||||
.content:hover::-webkit-scrollbar-thumb{
|
||||
background:rgba(0,0,0,0.1);
|
||||
}
|
||||
.bubble{
|
||||
max-width: 400px;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
color: #000;
|
||||
word-wrap:break-word;
|
||||
word-break:normal;
|
||||
}
|
||||
.item-left .bubble{
|
||||
margin-left: 15px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.item-left .bubble:before{
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 10px solid transparent;
|
||||
border-top: 10px solid transparent;
|
||||
border-right: 10px solid #fff;
|
||||
border-bottom: 10px solid transparent;
|
||||
left: -20px;
|
||||
}
|
||||
.item-right .bubble{
|
||||
margin-right: 15px;
|
||||
background-color: #9eea6a;
|
||||
}
|
||||
.item-right .bubble:before{
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 10px solid #9eea6a;
|
||||
border-top: 10px solid transparent;
|
||||
border-right: 10px solid transparent;
|
||||
border-bottom: 10px solid transparent;
|
||||
right: -20px;
|
||||
}
|
||||
.item{
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.item.item-right{
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.item.item-center{
|
||||
justify-content: center;
|
||||
}
|
||||
.item.item-center span{
|
||||
font-size: 12px;
|
||||
padding: 2px 4px;
|
||||
color: #fff;
|
||||
background-color: #dadada;
|
||||
border-radius: 3px;
|
||||
-moz-user-select:none; /*火狐*/
|
||||
-webkit-user-select:none; /*webkit浏览器*/
|
||||
-ms-user-select:none; /*IE10*/
|
||||
-khtml-user-select:none; /*早期浏览器*/
|
||||
user-select:none;
|
||||
}
|
||||
|
||||
.avatar img{
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.input-area{
|
||||
border-top:0.5px solid #e0e0e0;
|
||||
height: 150px;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
background-color: #fff;
|
||||
}
|
||||
textarea{
|
||||
flex: 1;
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
outline:none;
|
||||
resize:none;
|
||||
}
|
||||
.button-area{
|
||||
display: flex;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
line-height: 40px;
|
||||
padding: 5px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.button-area button{
|
||||
width: 80px;
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: 4px;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 设置滚动条的样式 */
|
||||
::-webkit-scrollbar {
|
||||
width:10px;
|
||||
}
|
||||
/* 滚动槽 */
|
||||
::-webkit-scrollbar-track {
|
||||
-webkit-box-shadow:inset006pxrgba(0,0,0,0.3);
|
||||
border-radius:8px;
|
||||
}
|
||||
/* 滚动条滑块 */
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius:10px;
|
||||
background:rgba(0,0,0,0);
|
||||
-webkit-box-shadow:inset006pxrgba(0,0,0,0.5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
'''
|
||||
f.write(html_head)
|
||||
MePC().avatar.save(os.path.join(origin_docx_path, 'myhead.png'))
|
||||
self.contact.avatar.save(os.path.join(origin_docx_path, 'tahead.png'))
|
||||
for message in messages:
|
||||
type_ = message[2]
|
||||
str_content = message[7]
|
||||
str_time = message[8]
|
||||
# print(type_, type(type_))
|
||||
is_send = message[4]
|
||||
avatar = MePC().avatar_path if is_send else self.contact.avatar_path
|
||||
timestamp = message[5]
|
||||
if type_ == 1:
|
||||
if self.is_5_min(timestamp):
|
||||
f.write(
|
||||
f'''
|
||||
<div class="item item-center"><span>{str_time}</span></div>
|
||||
'''
|
||||
)
|
||||
if is_send:
|
||||
f.write(
|
||||
f'''
|
||||
<div class="item item-right">
|
||||
<div class="bubble bubble-right">{str_content}</div>
|
||||
<div class="avatar">
|
||||
<img src="myhead.png" />
|
||||
</div>
|
||||
</div>
|
||||
'''
|
||||
)
|
||||
else:
|
||||
f.write(
|
||||
f'''
|
||||
<div class="item item-left">
|
||||
<div class="avatar">
|
||||
<img src="tahead.png" />
|
||||
</div>
|
||||
<div class="bubble bubble-left">{str_content}
|
||||
</div>
|
||||
</div>
|
||||
'''
|
||||
)
|
||||
html_end = '''
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
f.write(html_end)
|
||||
f.close()
|
||||
self.okSignal.emit('ok')
|
||||
|
||||
def is_5_min(self, timestamp):
|
||||
@ -281,6 +64,9 @@ class Output(QThread):
|
||||
return True
|
||||
return False
|
||||
|
||||
def progress(self, value):
|
||||
self.progressSignal.emit(value)
|
||||
|
||||
def run(self):
|
||||
if self.output_type == self.DOCX:
|
||||
return
|
||||
@ -288,4 +74,661 @@ class Output(QThread):
|
||||
# print("线程导出csv")
|
||||
self.to_csv(self.ta_username, "path")
|
||||
elif self.output_type == self.HTML:
|
||||
self.to_html()
|
||||
# self.to_html()
|
||||
self.Child0 = ChildThread(self.contact, type_=ChildThread.HTML)
|
||||
self.Child0.progressSignal.connect(self.progress)
|
||||
self.Child0.rangeSignal.connect(self.rangeSignal)
|
||||
self.Child0.okSignal.connect(self.okSignal)
|
||||
self.Child0.run()
|
||||
# self.okSignal.emit(1)
|
||||
|
||||
|
||||
class ChildThread(QThread):
|
||||
"""
|
||||
子线程,用于导出部分聊天记录
|
||||
"""
|
||||
progressSignal = pyqtSignal(int)
|
||||
rangeSignal = pyqtSignal(int)
|
||||
okSignal = pyqtSignal(int)
|
||||
i = 1
|
||||
CSV = 0
|
||||
DOCX = 1
|
||||
HTML = 2
|
||||
|
||||
def __init__(self, contact, parent=None, type_=DOCX):
|
||||
super().__init__(parent)
|
||||
self.contact = contact
|
||||
self.last_timestamp = 0
|
||||
self.sec = 2 # 默认1000秒
|
||||
self.msg_id = 0
|
||||
self.output_type = type_
|
||||
|
||||
def is_5_min(self, timestamp):
|
||||
if abs(timestamp - self.last_timestamp) > 300:
|
||||
self.last_timestamp = timestamp
|
||||
|
||||
return True
|
||||
return False
|
||||
|
||||
def text(self, doc, isSend, message, status):
|
||||
return
|
||||
|
||||
def image(self, doc, isSend, Type, content, imgPath):
|
||||
return
|
||||
|
||||
def emoji(self, doc, isSend, content, imgPath):
|
||||
return
|
||||
|
||||
def wx_file(self, doc, isSend, content, status):
|
||||
return
|
||||
|
||||
def retract_message(self, doc, isSend, content, status):
|
||||
return
|
||||
|
||||
def reply(self, doc, isSend, content, status):
|
||||
return
|
||||
|
||||
def pat_a_pat(self, doc, isSend, content, status):
|
||||
return
|
||||
|
||||
def video(self, doc, isSend, content, status, img_path):
|
||||
return
|
||||
|
||||
def to_html(self):
|
||||
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
|
||||
if not os.path.exists(origin_docx_path):
|
||||
os.mkdir(origin_docx_path)
|
||||
messages = msg.get_messages(self.contact.wxid)
|
||||
filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}.html"
|
||||
f = open(filename, 'w', encoding='utf-8')
|
||||
html_head = '''
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
<style>
|
||||
|
||||
*{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
body{
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.container{
|
||||
height: 760px;
|
||||
width: 900px;
|
||||
border-radius: 4px;
|
||||
border: 0.5px solid #e0e0e0;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.content{
|
||||
width: calc(100% - 40px);
|
||||
padding: 20px;
|
||||
overflow-y: scroll;
|
||||
flex: 1;
|
||||
}
|
||||
.content:hover::-webkit-scrollbar-thumb{
|
||||
background:rgba(0,0,0,0.1);
|
||||
}
|
||||
.bubble{
|
||||
max-width: 400px;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
color: #000;
|
||||
word-wrap:break-word;
|
||||
word-break:normal;
|
||||
}
|
||||
.item-left .bubble{
|
||||
margin-left: 15px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.item-left .bubble:before{
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 10px solid transparent;
|
||||
border-top: 10px solid transparent;
|
||||
border-right: 10px solid #fff;
|
||||
border-bottom: 10px solid transparent;
|
||||
left: -20px;
|
||||
}
|
||||
.item-right .bubble{
|
||||
margin-right: 15px;
|
||||
background-color: #9eea6a;
|
||||
}
|
||||
.item-right .bubble:before{
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 10px solid #9eea6a;
|
||||
border-top: 10px solid transparent;
|
||||
border-right: 10px solid transparent;
|
||||
border-bottom: 10px solid transparent;
|
||||
right: -20px;
|
||||
}
|
||||
.item{
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.item.item-right{
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.item.item-center{
|
||||
justify-content: center;
|
||||
}
|
||||
.item.item-center span{
|
||||
font-size: 12px;
|
||||
padding: 2px 4px;
|
||||
color: #fff;
|
||||
background-color: #dadada;
|
||||
border-radius: 3px;
|
||||
-moz-user-select:none; /*火狐*/
|
||||
-webkit-user-select:none; /*webkit浏览器*/
|
||||
-ms-user-select:none; /*IE10*/
|
||||
-khtml-user-select:none; /*早期浏览器*/
|
||||
user-select:none;
|
||||
}
|
||||
|
||||
.avatar img{
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.input-area{
|
||||
border-top:0.5px solid #e0e0e0;
|
||||
height: 150px;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
background-color: #fff;
|
||||
}
|
||||
textarea{
|
||||
flex: 1;
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
outline:none;
|
||||
resize:none;
|
||||
}
|
||||
.button-area{
|
||||
display: flex;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
line-height: 40px;
|
||||
padding: 5px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.button-area button{
|
||||
width: 80px;
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: 4px;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 设置滚动条的样式 */
|
||||
::-webkit-scrollbar {
|
||||
width:10px;
|
||||
}
|
||||
/* 滚动槽 */
|
||||
::-webkit-scrollbar-track {
|
||||
-webkit-box-shadow:inset006pxrgba(0,0,0,0.3);
|
||||
border-radius:8px;
|
||||
}
|
||||
/* 滚动条滑块 */
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius:10px;
|
||||
background:rgba(0,0,0,0);
|
||||
-webkit-box-shadow:inset006pxrgba(0,0,0,0.5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container" id="container" onscroll="handleScroll()">
|
||||
<div class="content">
|
||||
'''
|
||||
f.write(html_head)
|
||||
MePC().avatar.save(os.path.join(origin_docx_path, 'myhead.png'))
|
||||
self.contact.avatar.save(os.path.join(origin_docx_path, 'tahead.png'))
|
||||
self.rangeSignal.emit(len(messages))
|
||||
for index, message in enumerate(messages):
|
||||
type_ = message[2]
|
||||
str_content = message[7]
|
||||
str_time = message[8]
|
||||
# print(type_, type(type_))
|
||||
is_send = message[4]
|
||||
avatar = MePC().avatar_path if is_send else self.contact.avatar_path
|
||||
timestamp = message[5]
|
||||
self.progressSignal.emit(index)
|
||||
if type_ == 1:
|
||||
if self.is_5_min(timestamp):
|
||||
f.write(
|
||||
f'''
|
||||
<div class="item item-center"><span>{str_time}</span></div>
|
||||
'''
|
||||
)
|
||||
if is_send:
|
||||
f.write(
|
||||
f'''
|
||||
<div class="item item-right">
|
||||
<div class="bubble bubble-right">{str_content}</div>
|
||||
<div class="avatar">
|
||||
<img src="myhead.png" />
|
||||
</div>
|
||||
</div>
|
||||
'''
|
||||
)
|
||||
else:
|
||||
f.write(
|
||||
f'''
|
||||
<div class="item item-left">
|
||||
<div class="avatar">
|
||||
<img src="tahead.png" />
|
||||
</div>
|
||||
<div class="bubble bubble-left">{str_content}
|
||||
</div>
|
||||
</div>
|
||||
'''
|
||||
)
|
||||
html_end = '''
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const container = document.getElementById('container');
|
||||
const content = document.getElementById('content');
|
||||
|
||||
const totalItems = 1000;
|
||||
const itemsPerPage = 20;
|
||||
const itemHeight = 50;
|
||||
|
||||
function updateContent() {
|
||||
const scrollTop = container.scrollTop;
|
||||
const startIndex = Math.floor(scrollTop / itemHeight);
|
||||
const endIndex = Math.min(startIndex + itemsPerPage, totalItems);
|
||||
|
||||
// Remove existing items
|
||||
content.innerHTML = '';
|
||||
|
||||
// Add new items
|
||||
for (let i = startIndex; i < endIndex; i++) {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'item';
|
||||
item.textContent = `Item ${i}`;
|
||||
content.appendChild(item);
|
||||
}
|
||||
|
||||
// Update container height to show correct scrollbar
|
||||
container.style.height = totalItems * itemHeight + 'px';
|
||||
}
|
||||
|
||||
function handleScroll() {
|
||||
updateContent();
|
||||
}
|
||||
|
||||
// Initial content rendering
|
||||
updateContent();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
f.write(html_end)
|
||||
f.close()
|
||||
self.okSignal.emit(1)
|
||||
|
||||
def to_html_(self):
|
||||
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
|
||||
if not os.path.exists(origin_docx_path):
|
||||
os.mkdir(origin_docx_path)
|
||||
messages = msg.get_messages(self.contact.wxid)
|
||||
filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}.html"
|
||||
f = open(filename, 'w', encoding='utf-8')
|
||||
html_head = '''
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Chat Records</title>
|
||||
<style>
|
||||
|
||||
*{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
body{
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.container{
|
||||
height: 760px;
|
||||
width: 900px;
|
||||
border-radius: 4px;
|
||||
border: 0.5px solid #e0e0e0;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.content{
|
||||
width: calc(100% - 40px);
|
||||
padding: 20px;
|
||||
overflow-y: scroll;
|
||||
flex: 1;
|
||||
}
|
||||
.content:hover::-webkit-scrollbar-thumb{
|
||||
background:rgba(0,0,0,0.1);
|
||||
}
|
||||
.bubble{
|
||||
max-width: 400px;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
color: #000;
|
||||
word-wrap:break-word;
|
||||
word-break:normal;
|
||||
}
|
||||
.item-left .bubble{
|
||||
margin-left: 15px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.item-left .bubble:before{
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 10px solid transparent;
|
||||
border-top: 10px solid transparent;
|
||||
border-right: 10px solid #fff;
|
||||
border-bottom: 10px solid transparent;
|
||||
left: -20px;
|
||||
}
|
||||
.item-right .bubble{
|
||||
margin-right: 15px;
|
||||
background-color: #9eea6a;
|
||||
}
|
||||
.item-right .bubble:before{
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 10px solid #9eea6a;
|
||||
border-top: 10px solid transparent;
|
||||
border-right: 10px solid transparent;
|
||||
border-bottom: 10px solid transparent;
|
||||
right: -20px;
|
||||
}
|
||||
.item{
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.item.item-right{
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.item.item-center{
|
||||
justify-content: center;
|
||||
}
|
||||
.item.item-center span{
|
||||
font-size: 12px;
|
||||
padding: 2px 4px;
|
||||
color: #fff;
|
||||
background-color: #dadada;
|
||||
border-radius: 3px;
|
||||
-moz-user-select:none; /*火狐*/
|
||||
-webkit-user-select:none; /*webkit浏览器*/
|
||||
-ms-user-select:none; /*IE10*/
|
||||
-khtml-user-select:none; /*早期浏览器*/
|
||||
user-select:none;
|
||||
}
|
||||
|
||||
.avatar img{
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.input-area{
|
||||
border-top:0.5px solid #e0e0e0;
|
||||
height: 150px;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
background-color: #fff;
|
||||
}
|
||||
textarea{
|
||||
flex: 1;
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
outline:none;
|
||||
resize:none;
|
||||
}
|
||||
.button-area{
|
||||
display: flex;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
line-height: 40px;
|
||||
padding: 5px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.button-area button{
|
||||
width: 80px;
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: 4px;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 设置滚动条的样式 */
|
||||
::-webkit-scrollbar {
|
||||
width:10px;
|
||||
}
|
||||
/* 滚动槽 */
|
||||
::-webkit-scrollbar-track {
|
||||
-webkit-box-shadow:inset006pxrgba(0,0,0,0.3);
|
||||
border-radius:8px;
|
||||
}
|
||||
/* 滚动条滑块 */
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius:10px;
|
||||
background:rgba(0,0,0,0);
|
||||
-webkit-box-shadow:inset006pxrgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="content" id="chat-container">
|
||||
<div class="item item-center"><span>昨天 12:35</span></div>
|
||||
<div class="item item-center"><span>你已添加了凡繁烦,现在可以开始聊天了。</span></div>
|
||||
<div class="item item-left">
|
||||
<div class="avatar">
|
||||
<img src="https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=25668084,2889217189&fm=26&gp=0.jpg" />
|
||||
</div>
|
||||
<div class="bubble bubble-left">您好,我在武汉,你可以直接送过来吗,我有时间的话,可以自己过去拿<br/>!!!<br/>123
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item item-right">
|
||||
<div class="bubble bubble-right">hello<br/>你好呀</div>
|
||||
<div class="avatar">
|
||||
<img src="https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3313909130,2406410525&fm=15&gp=0.jpg" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="item item-center">
|
||||
<span>昨天 13:15</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div></div>
|
||||
<div>
|
||||
<button onclick="prevPage()">上一页</button>
|
||||
<div id = "paginationInfo"></div>
|
||||
<button onclick="nextPage()">下一页</button>
|
||||
<div></div>
|
||||
<input type="number" id="gotoPageInput" placeholder="跳转到第几页">
|
||||
<button onclick="gotoPage()">跳转</button>
|
||||
</div>
|
||||
<script>
|
||||
const chatContainer = document.getElementById('chat-container');
|
||||
// Sample chat messages (replace this with your actual data)
|
||||
const chatMessages = [
|
||||
'''
|
||||
f.write(html_head)
|
||||
MePC().avatar.save(os.path.join(origin_docx_path, 'myhead.png'))
|
||||
self.contact.avatar.save(os.path.join(origin_docx_path, 'tahead.png'))
|
||||
self.rangeSignal.emit(len(messages))
|
||||
for index, message in enumerate(messages):
|
||||
type_ = message[2]
|
||||
str_content = message[7]
|
||||
str_time = message[8]
|
||||
# print(type_, type(type_))
|
||||
is_send = message[4]
|
||||
# avatar = MePC().avatar_path if is_send else self.contact.avatar_path
|
||||
# avatar = avatar.replace('\\', '\\\\')
|
||||
avatar = 'myhead.png' if is_send else 'tahead.png'
|
||||
timestamp = message[5]
|
||||
self.progressSignal.emit(index)
|
||||
str_content = str_content.replace('"', '\\"').replace('{', '\\{').replace('}', '\\}').replace('\n',
|
||||
'\\n').replace(
|
||||
"'", "\\'")
|
||||
if type_ == 1:
|
||||
if self.is_5_min(timestamp):
|
||||
f.write(
|
||||
f'''{{ type:0, text: '{str_time}',is_send:0,avatar_path:''}},'''
|
||||
)
|
||||
f.write(
|
||||
f'''{{ type:{type_}, text: '{str_content}',is_send:{is_send},avatar_path:'{avatar}'}},'''
|
||||
)
|
||||
html_end = '''
|
||||
];
|
||||
function renderMessages(messages) {
|
||||
for (const message of messages) {
|
||||
const messageElement = document.createElement('div');
|
||||
if (message.type == 1){
|
||||
if (message.is_send == 1){
|
||||
messageElement.className = "item item-right";
|
||||
messageElement.innerHTML = `<div class='bubble bubble-right'>${message.text}</div><div class='avatar'><img src="${message.avatar_path}" /></div>`
|
||||
}
|
||||
else if(message.is_send==0){
|
||||
messageElement.className = "item item-left";
|
||||
messageElement.innerHTML = `<div class='avatar'><img src="${message.avatar_path}" /></div><div class='bubble bubble-right'>${message.text}</div>`
|
||||
}
|
||||
}
|
||||
else if(message.type == 0){
|
||||
messageElement.className = "item item-center";
|
||||
messageElement.innerHTML = `<span>${message.text}</span>`
|
||||
}
|
||||
chatContainer.appendChild(messageElement);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const itemsPerPage = 100; // 每页显示的元素个数
|
||||
let currentPage = 1; // 当前页
|
||||
|
||||
function renderPage(page) {
|
||||
const container = document.getElementById('chat-container');
|
||||
container.innerHTML = ''; // 清空容器
|
||||
|
||||
// 计算当前页应该显示的元素范围
|
||||
const startIndex = (page - 1) * itemsPerPage;
|
||||
const endIndex = startIndex + itemsPerPage;
|
||||
console.log(page);
|
||||
// 从数据列表中取出对应范围的元素并添加到容器中
|
||||
for (let i = startIndex; i < endIndex && i < chatMessages.length; i++) {
|
||||
const message = chatMessages[i];
|
||||
const messageElement = document.createElement('div');
|
||||
if (message.type == 1){
|
||||
if (message.is_send == 1){
|
||||
messageElement.className = "item item-right";
|
||||
messageElement.innerHTML = `<div class='bubble bubble-right'>${message.text}</div><div class='avatar'><img src="${message.avatar_path}" /></div>`
|
||||
}
|
||||
else if(message.is_send==0){
|
||||
messageElement.className = "item item-left";
|
||||
messageElement.innerHTML = `<div class='avatar'><img src="${message.avatar_path}" /></div><div class='bubble bubble-right'>${message.text}</div>`
|
||||
}
|
||||
}
|
||||
else if(message.type == 0){
|
||||
messageElement.className = "item item-center";
|
||||
messageElement.innerHTML = `<span>${message.text}</span>`
|
||||
}
|
||||
chatContainer.appendChild(messageElement);
|
||||
}
|
||||
updatePaginationInfo();
|
||||
}
|
||||
|
||||
function prevPage() {
|
||||
if (currentPage > 1) {
|
||||
currentPage--;
|
||||
renderPage(currentPage);
|
||||
}
|
||||
}
|
||||
|
||||
function nextPage() {
|
||||
const totalPages = Math.ceil(chatMessages.length / itemsPerPage);
|
||||
if (currentPage < totalPages) {
|
||||
currentPage++;
|
||||
renderPage(currentPage);
|
||||
}
|
||||
}
|
||||
function updatePaginationInfo() {
|
||||
const totalPages = Math.ceil(chatMessages.length / itemsPerPage);
|
||||
const paginationInfo = document.getElementById('paginationInfo');
|
||||
paginationInfo.textContent = `共 ${totalPages} 页,当前第 ${currentPage} 页`;
|
||||
}
|
||||
function gotoPage() {
|
||||
const totalPages = Math.ceil(chatMessages.length / itemsPerPage);
|
||||
const inputElement = document.getElementById('gotoPageInput');
|
||||
const targetPage = parseInt(inputElement.value);
|
||||
|
||||
if (targetPage >= 1 && targetPage <= totalPages) {
|
||||
currentPage = targetPage;
|
||||
renderPage(currentPage);
|
||||
} else {
|
||||
alert('请输入有效的页码');
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化页面
|
||||
renderPage(currentPage);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
f.write(html_end)
|
||||
f.close()
|
||||
self.okSignal.emit(1)
|
||||
|
||||
def run(self):
|
||||
if self.output_type == self.DOCX:
|
||||
return
|
||||
elif self.output_type == self.CSV:
|
||||
return
|
||||
elif self.output_type == self.HTML:
|
||||
self.to_html_()
|
||||
|
@ -100,7 +100,7 @@ class ChatInfo(QWidget):
|
||||
)
|
||||
self.chat_window.add_message_item(bubble_message, 0)
|
||||
elif type_ == 3:
|
||||
return
|
||||
# return
|
||||
if self.is_5_min(timestamp):
|
||||
time_message = Notice(self.last_str_time)
|
||||
self.last_str_time = str_time
|
||||
|
@ -115,12 +115,7 @@ class ContactInfo(QWidget, Ui_Form):
|
||||
print('导出csv')
|
||||
elif self.sender() == self.toHtmlAct:
|
||||
self.outputThread = Output(self.contact, type_=Output.HTML)
|
||||
# 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)
|
||||
@ -140,5 +135,6 @@ class ContactInfo(QWidget, Ui_Form):
|
||||
self.view_userinfo.progressBar.setProperty('value', value)
|
||||
|
||||
def set_progressBar_range(self, value):
|
||||
print('进度条范围', value)
|
||||
self.view_userinfo.progressBar.setVisible(True)
|
||||
self.view_userinfo.progressBar.setRange(0, value)
|
||||
|
Loading…
Reference in New Issue
Block a user