From 5faa0cb1e68f9a9cef84126720e4310c4e7973b8 Mon Sep 17 00:00:00 2001 From: shuaikangzhou <863909694@qq.com> Date: Fri, 31 Mar 2023 11:15:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TEST.py | 61 +++-- app/DataBase/data.py | 332 +++++++++++++++++++++-- app/DataBase/output.py | 34 ++- app/Ui/chat/chat.py | 41 +-- app/Ui/contact/analysis/analysis.py | 30 ++- app/Ui/contact/analysis/charts.py | 359 ++++++++++++++++++++++++- app/Ui/decrypt/decrypt.py | 9 +- app/Ui/mainview.py | 10 +- app/Ui/mainviewUi.py | 15 -- app/Ui/mainviewUi.ui | 396 +++++++++++++--------------- app/data/icon.png | Bin 18535 -> 910 bytes main.py | 17 +- test.html | 129 +++++---- wechat.html | 203 ++++---------- 14 files changed, 1079 insertions(+), 557 deletions(-) diff --git a/TEST.py b/TEST.py index cd02973..43c5642 100644 --- a/TEST.py +++ b/TEST.py @@ -1,25 +1,40 @@ -import os -import openai +import json -print("欢迎使用ChatGPT智能问答,请在Q:后面输入你的问题,输入quit退出!") -openai.api_key = '''eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik1UaEVOVUpHTkVNMVFURTRNMEZCTWpkQ05UZzVNRFUxUlRVd1FVSkRNRU13UmtGRVFrRXpSZyJ9.eyJodHRwczovL2FwaS5vcGVuYWkuY29tL3Byb2ZpbGUiOnsiZW1haWwiOiI4NjM5MDk2OTRAcXEuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImdlb2lwX2NvdW50cnkiOiJVUyJ9LCJodHRwczovL2FwaS5vcGVuYWkuY29tL2F1dGgiOnsidXNlcl9pZCI6InVzZXItdmdiMG1IeU5MQUNHRG1qRndrekVMNVM3In0sImlzcyI6Imh0dHBzOi8vYXV0aDAub3BlbmFpLmNvbS8iLCJzdWIiOiJhdXRoMHw2M2RjYmNiZWRiNzFkNmVhMzA5YmEzYzciLCJhdWQiOlsiaHR0cHM6Ly9hcGkub3BlbmFpLmNvbS92MSIsImh0dHBzOi8vb3BlbmFpLm9wZW5haS5hdXRoMGFwcC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNjc1NDEyNTg2LCJleHAiOjE2NzYwMTczODYsImF6cCI6IlRkSkljYmUxNldvVEh0Tjk1bnl5d2g1RTR5T282SXRHIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCBtb2RlbC5yZWFkIG1vZGVsLnJlcXVlc3Qgb3JnYW5pemF0aW9uLnJlYWQgb2ZmbGluZV9hY2Nlc3MifQ.dlTy6oc0eIDIJg0AqlFdarXWh7h-n7C6id3Kv5-uOrASoYB3qtfhPMuj15yV0VOOmFyj_L7v3MCpPEnsJp08NJo1Jn32jKtCkKD-sy8DpT5rafj_B6TKNvEBsqdXgDENg0ly9KiAjS-HDlCmQoBEqg-kc2VaqlpPIfk-164WI2SCTgQb50GNKWu0jwG-lx8BHnY8gUqC7sGVx4Hg9sLHccyAL93kMu4NS-S9CsqNefYAolLbqQLPBOG9MFaTD1jvyZpuqwm3eiv7HwgHempVWAfCK9sfGBblExHRT5zi0oSGwwBGmi2EnBHjEX185RRqtuH_uKRwp47m0TcHulJsfQ''' +from pyecharts import options as opts +from pyecharts.charts import Graph -start_sequence = "\nA:" -restart_sequence = "\nQ: " -while True: - prompt = input(restart_sequence) - if prompt == 'quit': - break - else: - try: - response = openai.Completion.create( - model="text-davinci-003", # 这里我们使用的是davinci-003的模型,准确度更高。 - prompt=prompt, - temperature=1, - max_tokens=2000, # 这里限制的是回答的长度,你可以可以限制字数,如:写一个300字作文等。 - frequency_penalty=0, - presence_penalty=0 - ) - print(start_sequence, response["choices"][0]["text"].strip()) - except Exception as exc: # 捕获异常后打印出来 - print(exc) +with open(r'data/npmdepgraph.min10.json', 'r') as f: + data = json.load(f) + +nodes = [ + { + 'x': node['x'], + 'y': node['y'], + 'name': node['label'], + 'symbolSize': node['size'], + 'itemStyle': {'color': node['color']} + } + for node in data['nodes'] +] + +edges = [ + { + 'source': edge['sourceID'], + 'target': edge['targetID'] + } + for edge in data['edges'] +] + +G = Graph(init_opts=opts.InitOpts(width='900', height='900')) +G.add( + series_name='', + nodes=nodes, + links=edges, + layout='none', + is_roam=True, + is_focusnode=True, + label_opts=opts.LabelOpts(is_show=True), + linestyle_opts=opts.LineStyleOpts(width=0.5, curve=0.3, opacity=0.7) +) +G.set_global_opts(title_opts=opts.TitleOpts(title='NPM Dependencies')) +G.render('npm_dependencies.html') diff --git a/app/DataBase/data.py b/app/DataBase/data.py index 1dcf093..e21eb3a 100644 --- a/app/DataBase/data.py +++ b/app/DataBase/data.py @@ -11,6 +11,7 @@ import hashlib import os import sqlite3 import time + import requests DB = None @@ -66,6 +67,7 @@ def mkdir(path): return True +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) @@ -96,7 +98,7 @@ def decrypt(db, key): if os.path.exists('./app/DataBase/Msg.db'): print('/app/DataBase/Msg.db 已经存在') return True - cmd = '/sqlcipher-3.0.1/bin/sqlcipher-shell32.exe' + cmd = './sqlcipher-3.0.1/bin/sqlcipher-shell32.exe' print(os.path.abspath('.')) param = f""" PRAGMA key = '{key}'; @@ -105,9 +107,10 @@ def decrypt(db, key): SELECT sqlcipher_export('Msg'); DETACH DATABASE Msg; """ - with open('./app/DataBase/config.txt', 'w') as f: + + with open('./app/data/config.txt', 'w') as f: f.write(param) - p = os.system(f"{os.path.abspath('.')}{cmd} {db} < ./app/DataBase/config.txt") + 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) @@ -155,10 +158,12 @@ def get_conRemark(username): sql = 'select conRemark,nickname from rcontact where username=?' cursor.execute(sql, [username]) result = cursor.fetchone() - if result[0]: - return result[0] - else: - return result[1] + if result: + if result[0]: + return result[0] + else: + return result[1] + return False def get_nickname(username): @@ -260,9 +265,14 @@ def get_emoji(imgPath): def download_emoji(imgPath, url): - resp = requests.get(url) - with open(imgPath, 'wb') as f: - f.write(resp.content) + 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 @@ -308,6 +318,15 @@ def recv_nums(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 @@ -330,7 +349,7 @@ def msg_type_num(username): def get_msg_start_time(username): sql = ''' - select createTime from message + select strftime('%Y-%m-%d %H:%M:%S',createTime/1000,'unixepoch','localtime') from message where talker = ? order by msgId limit 1 @@ -341,7 +360,7 @@ def get_msg_start_time(username): def get_msg_end_time(username): sql = ''' - select createTime from message + select strftime('%Y-%m-%d %H:%M:%S',createTime/1000,'unixepoch','localtime') from message where talker = ? order by msgId desc limit 1 @@ -365,6 +384,18 @@ def get_msg_by_days(username, year='2022'): 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) @@ -377,6 +408,252 @@ def get_msg_by_month(username, year='2022'): 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, + } + + +from pyecharts import options as opts +from pyecharts.charts import Bar, Line, Timeline, Grid +import pandas as pd +import xmltodict + + +def sport(username): + sports = 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: + continue + df = pd.DataFrame({'ranks': ranks, 'score': steps, 'date': date}, index=date) + months = pd.date_range(date[0], date[-1], freq='M') + tl = Timeline(init_opts=opts.InitOpts(width="440px", height="245px")) + 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="400px", height="235px")) + .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, + # 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) + ) + .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="400px", height="235px")) + .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) + ) + ) + bar.overlap(line) + grid = Grid() + grid.add(bar, opts.GridOpts(pos_left="5%", pos_right="20%"), is_control_axis_index=True) + grid.render("grid_multi_yaxis.html") + quit() + # tl.add(bar, "{}".format(months[i].strftime("%Y-%m"))) + # tl.render("./sports.html") + + return { + username: { + 'ranks': ranks, + 'score': steps, + 'date': date, + } + } + + +def radar_hour(username): + msg_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() + .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="最小值"), + ] + ), + markline_opts=opts.MarkLineOpts( + data=[opts.MarkLineItem(type_="average", name="平均值")] + ), + ) + .render("temperature_change_line_chart.html") + ) + + +def chat_start_endTime(username): + start_time = get_msg_start_time(username) + end_time = 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:] + print(year, month, day, hour, minute, second) + + if __name__ == '__main__': # rconversation = get_rconversation() # for i in rconversation: @@ -385,14 +662,23 @@ if __name__ == '__main__': # for contact in contacts: # print(contact) # [(177325,)] (73546,) (103770,) - print(search_send_message(1, 1)) - print(send_nums('wxid_vqave8lcp49r22')) - print(recv_nums('wxid_vqave8lcp49r22')) - # for t in get_text('wxid_vqave8lcp49r22'): - # print(t) - print(msg_type_num('wxid_vqave8lcp49r22')) - st = get_msg_start_time('wxid_vqave8lcp49r22') - print(st, timestamp2str(st)) - st = get_msg_end_time('wxid_vqave8lcp49r22') - print(st, timestamp2str(st)) - print(get_msg_by_month('wxid_8piw6sb4hvfm22', year='2022')) + # print(search_send_message(1, 1)) + # print(send_nums('wxid_vqave8lcp49r22')) + # print(recv_nums('wxid_vqave8lcp49r22')) + # # for t in get_text('wxid_vqave8lcp49r22'): + # # print(t) + # print(msg_type_num('wxid_vqave8lcp49r22')) + # st = get_msg_start_time('wxid_vqave8lcp49r22') + # print(st, timestamp2str(st)) + # st = get_msg_end_time('wxid_vqave8lcp49r22') + # print(st, timestamp2str(st)) + # print(get_msg_by_month('wxid_8piw6sb4hvfm22', year='2022')) + # print(len(get_sport())) + # result = sport('wxid_8piw6sb4hvfm22') + # print(get_imgPath('THUMBNAIL_DIRPATH://th_92f32326df645b3e1aecef9b6266a3b8')) + # result = get_msg_by_hour('wxid_8piw6sb4hvfm22') + # print(result) + # radar_hour('wxid_8piw6sb4hvfm22') + # print(result) + print(get_msg_start_time('wxid_8piw6sb4hvfm22'), get_msg_end_time('wxid_8piw6sb4hvfm22')) + chat_start_endTime('wxid_8piw6sb4hvfm22') diff --git a/app/DataBase/output.py b/app/DataBase/output.py index 882f7c4..dbead37 100644 --- a/app/DataBase/output.py +++ b/app/DataBase/output.py @@ -1,13 +1,15 @@ import os import re import time + import docx import xmltodict +from PyQt5.QtCore import * from docx import shared from docx.enum.table import WD_ALIGN_VERTICAL from docx.enum.text import WD_COLOR_INDEX, WD_PARAGRAPH_ALIGNMENT from docxcompose.composer import Composer -from PyQt5.QtCore import * + from . import data @@ -79,7 +81,7 @@ class Output(QThread): if self.i == self.total_num: QThread.sleep(1) conRemark = data.get_conRemark(self.ta_username) - self.progressSignal.emit(self.total_num-1) + self.progressSignal.emit(self.total_num - 1) self.merge_docx(conRemark, self.n) print('ok') self.progressSignal.emit(self.total_num) @@ -103,7 +105,7 @@ class Output(QThread): p = l len_data = messages[q:p] # self.to_docx(len_data, i, conRemark) - self.Child[i] = ChildThread(self.Me, self.ta_username, len_data, conRemark,i) + self.Child[i] = ChildThread(self.Me, self.ta_username, len_data, conRemark, i) self.Child[i].progressSignal.connect(self.progress) self.Child[i].start() @@ -116,7 +118,7 @@ class ChildThread(QThread): rangeSignal = pyqtSignal(int) i = 1 - def __init__(self, Me, ta_u, message, conRemark,num, parent=None): + def __init__(self, Me, ta_u, message, conRemark, num, parent=None): super().__init__(parent) self.Me = Me self.sec = 2 # 默认1000秒 @@ -301,16 +303,20 @@ class ChildThread(QThread): :param status: :return: ''' - 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) + 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 = '糟糕!出错了。' p = doc.add_paragraph() run = p.add_run(template) p.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER diff --git a/app/Ui/chat/chat.py b/app/Ui/chat/chat.py index 7312ce8..3ee31d3 100644 --- a/app/Ui/chat/chat.py +++ b/app/Ui/chat/chat.py @@ -12,9 +12,10 @@ import time import xmltodict from PIL import Image -from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * +from PyQt5.QtWidgets import * + from .chatUi import * from ...DataBase import data from ...ImageBox.ui import MainDemo @@ -225,16 +226,21 @@ class ChatController(QWidget, Ui_Dialog): # self.message.moveCursor(self.message.textCursor().End) def pat_a_pat(self, content): - 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) + 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 = ''' @@ -258,6 +264,8 @@ class ChatController(QWidget, Ui_Dialog): def show_emoji(self, isSend, imagePath, content): imgPath = data.get_emoji(imagePath) + if not imgPath: + return False image = Image.open(imgPath) imagePixmap = image.size # 宽高像素 # 设置最大宽度 @@ -281,12 +289,13 @@ class ChatController(QWidget, Ui_Dialog): def show_img(self, isSend, imgPath, content): 'THUMBNAIL_DIRPATH://th_29cd0f0ca87652943be9ede365aabeaa' - imgPath = imgPath.split('th_')[1] - imgPath = f'./app/data/image2/{imgPath[0:2]}/{imgPath[2:4]}/th_{imgPath}' + # imgPath = imgPath.split('th_')[1] + imgPath = data.get_imgPath(imgPath) + imgPath = f'./app/data/image2/{imgPath[0:2]}/{imgPath[2:4]}/{imgPath}' html = ''' - ''' % (imgPath, imgPath) diff --git a/app/Ui/contact/analysis/analysis.py b/app/Ui/contact/analysis/analysis.py index 3909d18..ea9d3da 100644 --- a/app/Ui/contact/analysis/analysis.py +++ b/app/Ui/contact/analysis/analysis.py @@ -1,9 +1,10 @@ import sys -from PyQt5.QtWebEngineWidgets import QWebEngineView -from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * +from PyQt5.QtWebEngineWidgets import QWebEngineView +from PyQt5.QtWidgets import * + from . import charts @@ -14,7 +15,8 @@ class AnalysisController(QWidget): self.setWindowTitle('数据分析') self.setWindowIcon(QIcon('./app/data/icon.png')) # self.setWindowFlag(Qt.FramelessWindowHint) - self.setStyleSheet('''QWidget{background-color:rgb(255, 255, 255);}''') + # self.setStyleSheet('''QWidget{background-color:rgb(255, 255, 255);}''') + # self.setBackground() self.resize(400, 300) self.center() self.setAttribute(Qt.WA_AttributeCount) @@ -40,16 +42,14 @@ class AnalysisController(QWidget): def m_movie(self): movie = QMovie("./app/data/bg.gif") - self.label.setMovie(movie) - movie.start() def initUI(self): self.label.setVisible(False) main_box = QHBoxLayout(self) self.browser1 = QWebEngineView() - self.browser1.load(QUrl('http://www.baidu.com')) + self.browser1.load(QUrl('file:///data/聊天统计/title.html')) # self.browser1 = QFrame(self) # self.browser1.setFrameShape(QFrame.StyledPanel) # self.layoutWidget = QtWidgets.QWidget(self.browser1) @@ -67,13 +67,13 @@ class AnalysisController(QWidget): self.browser2 = QWebEngineView() self.browser2.load(QUrl('file:///data/聊天统计/wordcloud.html')) self.browser3 = QWebEngineView() - self.browser3.load(QUrl('http://www.baidu.com')) + self.browser3.load(QUrl('file:///data/聊天统计/time.html')) self.browser4 = QWebEngineView() self.browser4.load(QUrl('http://www.baidu.com')) self.browser5 = QWebEngineView() - self.browser5.load(QUrl('http://www.baidu.com')) + self.browser5.load(QUrl('file:///data/聊天统计/chat_session.html')) self.browser6 = QWebEngineView() - self.browser6.load(QUrl('http://www.baidu.com')) + self.browser6.load(QUrl('file:///data/聊天统计/sports.html')) self.browser7 = QWebEngineView() self.browser7.load(QUrl('file:///data/聊天统计/month_num.html')) self.browser8 = QWebEngineView() @@ -95,7 +95,7 @@ class AnalysisController(QWidget): splitter1.addWidget(self.browser1) splitter1.addWidget(splitter2) - splitter1.setSizes([1, 5]) + splitter1.setSizes([1, 8]) splitter2.addWidget(splitter6) splitter2.addWidget(splitter3) @@ -107,10 +107,10 @@ class AnalysisController(QWidget): splitter4.addWidget(splitter5) splitter4.addWidget(self.browser2) - splitter4.setSizes([1, 3]) + splitter4.setSizes([1, 5]) splitter5.addWidget(self.browser3) - splitter5.addWidget(self.browser4) + # splitter5.addWidget(self.browser4) splitter6.addWidget(self.browser5) splitter6.addWidget(splitter7) @@ -144,16 +144,20 @@ class LoadData(QThread): """ okSignal = pyqtSignal(int) - def __init__(self,ta_u, parent=None): + 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) diff --git a/app/Ui/contact/analysis/charts.py b/app/Ui/contact/analysis/charts.py index 3740761..48ca2cf 100644 --- a/app/Ui/contact/analysis/charts.py +++ b/app/Ui/contact/analysis/charts.py @@ -1,9 +1,15 @@ import os + import jieba +import pandas as pd +import xmltodict from pyecharts import options as opts -from pyecharts.charts import Pie, WordCloud, Calendar, Bar +from pyecharts.charts import Pie, WordCloud, Calendar, Bar, Line, Timeline, Grid + from ....DataBase import data +# from app.DataBase import data + data.mkdir(os.path.abspath('.') + '/data/聊天统计') Type = { @@ -34,7 +40,7 @@ def send_recv_rate(username): total_num = send_num + recv_num print(send_num, recv_num) c = ( - Pie(init_opts=opts.InitOpts(width="460px", height="240px")) + Pie(init_opts=opts.InitOpts(width="463px", height="243px")) .add( "", [ @@ -43,7 +49,7 @@ def send_recv_rate(username): center=["40%", "50%"], ) .set_global_opts( - title_opts=opts.TitleOpts(title=f"信息发送接收",subtitle=f"总计:{total_num}条消息", pos_bottom="0%"), + 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( @@ -104,7 +110,7 @@ def message_word_cloud(username): text_data = text_data[:100] # print(text_data) ( - WordCloud(init_opts=opts.InitOpts(width="900px", height="550px")) + WordCloud(init_opts=opts.InitOpts(width="900px", height="700px")) .add(series_name="聊天文字", data_pair=text_data, word_size_range=[20, 100]) .set_global_opts( title_opts=opts.TitleOpts( @@ -112,17 +118,18 @@ def message_word_cloud(username): 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") ) def calendar_chart(username): - msg_data = data.get_msg_by_days(username) + msg_data = data.get_msg_by_days(username, year='2022') 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="460px", height="255px")) + Calendar(init_opts=opts.InitOpts(width="460px", height="270px")) .add( "", msg_data, @@ -139,6 +146,7 @@ def calendar_chart(username): pos_bottom="0px", pos_left="0px", ), + legend_opts=opts.LegendOpts(is_show=False) ) .render("./data/聊天统计/calendar.html") ) @@ -152,10 +160,9 @@ def month_num(username): 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="440px", height="245px")) + Bar(init_opts=opts.InitOpts(width="440px", height="265px")) .add_xaxis(x_axis) .add_yaxis("消息数量", y_data) - # .add_yaxis("商家B", Faker.values()) .set_global_opts( title_opts=opts.TitleOpts(title="逐月聊天统计", subtitle=None), datazoom_opts=opts.DataZoomOpts(), @@ -165,5 +172,339 @@ def month_num(username): ) +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="460px", height="270px")) + .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") + ) + + +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: + continue + df = pd.DataFrame({'ranks': ranks, 'score': steps, 'date': date}, index=date) + months = pd.date_range(date[0], date[-1], freq='M') + tl = Timeline(init_opts=opts.InitOpts(width="440px", height="265px")) + 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="440px", height="265px")) + .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) + ) + .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="440px", height="265px")) + .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) + ) + .set_series_opts( + label_opts=opts.LabelOpts( + is_show=False + ) + ) + ) + bar.overlap(line) + grid = Grid() + grid.add(bar, opts.GridOpts(pos_left="7%", 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, + } + } + + +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 = ''' + + + + 聊天时间 + + + + +
+

+ 一次聊天发生 + %s-%s %s:%s:%s +

+
+
+ 距今已有 + 626 天 + 6 时 + 26 分 + 26 秒 +
+
+
+ + + + + ''' % (year, month + '-' + day, hour, minute, second, start_time) + print(year, month, day, hour, minute, second) + with open('./data/聊天统计/time.html', 'w', encoding='utf-8') as f: + f.write(html) + + +def title(username): + conRemark = data.get_conRemark(username) + avatar = data.get_avator(username) + html = ''' + + + + 聊天时间 + + + + +
+
- - + + +
+ + + + +
+ + + + +
+ Avatar +
+
+ + + + +
+ %s +
+
+
+ + + + +
+ + + + ''' % (avatar, conRemark) + print('头像地址', avatar) + with open('./data/聊天统计/title.html', 'w', encoding='utf-8') as f: + f.write(html) + + if __name__ == '__main__': - send_recv_rate('wxid_wt2vsktnu4z022') + # send_recv_rate('wxid_wt2vsktnu4z022') + sport('wxid_wt2vsktnu4z022') diff --git a/app/Ui/decrypt/decrypt.py b/app/Ui/decrypt/decrypt.py index d6c12a0..d6a791e 100644 --- a/app/Ui/decrypt/decrypt.py +++ b/app/Ui/decrypt/decrypt.py @@ -10,13 +10,14 @@ import hashlib import os import time +import xml.etree.ElementTree as ET +from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * -from PyQt5.QtCore import * + from . import decryptUi from ...DataBase import data -import xml.etree.ElementTree as ET class DecryptControl(QWidget, decryptUi.Ui_Dialog): @@ -103,7 +104,7 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog): print("enter clicked") # 中间可以添加处理逻辑 self.DecryptSignal.emit('ok') - self.close() + # self.close() def progressBar_view(self, value): """ @@ -120,7 +121,7 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog): def btnExitClicked(self): print("Exit clicked") - self.close() + # self.close() class DecryptThread(QThread): diff --git a/app/Ui/mainview.py b/app/Ui/mainview.py index 5cb2672..951d761 100644 --- a/app/Ui/mainview.py +++ b/app/Ui/mainview.py @@ -8,13 +8,14 @@ @comment : 主窗口 """ -from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * -from .mainviewUi import * +from PyQt5.QtWidgets import * + from app.DataBase import data from .chat import chat from .contact import contact +from .mainviewUi import * class MainWinController(QMainWindow, Ui_Dialog): @@ -31,9 +32,11 @@ class MainWinController(QMainWindow, Ui_Dialog): self.chatView.setVisible(False) self.contactView = contact.ContactController(self.Me, parent=self.frame_main) self.contactView.setVisible(False) + # self.myinfoView = userinfo.MyinfoController(self.Me, parent=self.frame_main) + # self.myinfoView.setVisible(False) 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_myinfo.clicked.connect(self.myInfo) self.btn_about.clicked.connect(self.about) self.now_btn = self.btn_chat self.btn_about.setContextMenuPolicy(Qt.CustomContextMenu) @@ -105,6 +108,7 @@ class MainWinController(QMainWindow, Ui_Dialog): 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 + self.setviewVisible(self.myinfoView) def about(self): """ diff --git a/app/Ui/mainviewUi.py b/app/Ui/mainviewUi.py index 1a24102..17a84be 100644 --- a/app/Ui/mainviewUi.py +++ b/app/Ui/mainviewUi.py @@ -47,18 +47,6 @@ class Ui_Dialog(object): "QPushButton:hover{background-color: rgb(209,209,209);}") self.btn_contact.setObjectName("btn_contact") self.verticalLayout_2.addWidget(self.btn_contact) - self.btn_addC = QtWidgets.QPushButton(self.verticalLayoutWidget) - self.btn_addC.setMinimumSize(QtCore.QSize(0, 80)) - self.btn_addC.setStyleSheet("QPushButton {background-color: rgb(240,240,240);}\n" -"QPushButton:hover{background-color: rgb(209,209,209);}") - self.btn_addC.setObjectName("btn_addC") - self.verticalLayout_2.addWidget(self.btn_addC) - self.btn_add_group = QtWidgets.QPushButton(self.verticalLayoutWidget) - self.btn_add_group.setMinimumSize(QtCore.QSize(0, 80)) - self.btn_add_group.setStyleSheet("QPushButton {background-color: rgb(240,240,240);}\n" -"QPushButton:hover{background-color: rgb(209,209,209);}") - self.btn_add_group.setObjectName("btn_add_group") - self.verticalLayout_2.addWidget(self.btn_add_group) self.btn_myinfo = QtWidgets.QPushButton(self.verticalLayoutWidget) self.btn_myinfo.setMinimumSize(QtCore.QSize(100, 80)) self.btn_myinfo.setStyleSheet("QPushButton {background-color: rgb(240,240,240);}\n" @@ -73,7 +61,6 @@ class Ui_Dialog(object): self.verticalLayout_2.addWidget(self.btn_about) self.verticalLayout_2.setStretch(0, 1) self.verticalLayout_2.setStretch(2, 1) - self.verticalLayout_2.setStretch(4, 1) self.myavatar = QtWidgets.QLabel(self.frame_info) self.myavatar.setGeometry(QtCore.QRect(30, 50, 100, 100)) self.myavatar.setObjectName("myavatar") @@ -92,8 +79,6 @@ class Ui_Dialog(object): Dialog.setWindowTitle(_translate("Dialog", "Dialog")) self.btn_chat.setText(_translate("Dialog", "聊天")) self.btn_contact.setText(_translate("Dialog", "联系人")) - self.btn_addC.setText(_translate("Dialog", "添加联系人")) - self.btn_add_group.setText(_translate("Dialog", "群聊")) self.btn_myinfo.setText(_translate("Dialog", "我的")) self.btn_about.setText(_translate("Dialog", "关于")) self.myavatar.setText(_translate("Dialog", "avatar")) diff --git a/app/Ui/mainviewUi.ui b/app/Ui/mainviewUi.ui index 90406dd..64f4302 100644 --- a/app/Ui/mainviewUi.ui +++ b/app/Ui/mainviewUi.ui @@ -1,216 +1,186 @@ - Dialog - - - - 0 - 0 - 1280 - 720 - - - - ArrowCursor - - - Dialog - - - false - - - - - 160 - 0 - 1120 - 720 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - 0 - 0 - 161 - 721 - - - - background-color:rgb(240,240,240) - - - QFrame::StyledPanel - - - QFrame::Sunken - - - - - 20 - 190 - 111 - 501 - - - - - 0 - - - - - - 0 - 80 - - - - QPushButton {background-color: rgb(240,240,240);} -QPushButton:hover{background-color: rgb(209,209,209);} - - - 聊天 - - - - - - - - 0 - 80 - - - - QPushButton {background-color: rgb(240,240,240);} -QPushButton:hover{background-color: rgb(209,209,209);} - - - 联系人 - - - - - - - - 0 - 80 - - - - QPushButton {background-color: rgb(240,240,240);} -QPushButton:hover{background-color: rgb(209,209,209);} - - - 添加联系人 - - - - - - - - 0 - 80 - - - - QPushButton {background-color: rgb(240,240,240);} -QPushButton:hover{background-color: rgb(209,209,209);} - - - 群聊 - - - - - - - - 100 - 80 - - - - QPushButton {background-color: rgb(240,240,240);} -QPushButton:hover{background-color: rgb(209,209,209);} - - - 我的 - - - - - - - - 100 - 80 - - - - QPushButton {background-color: rgb(240,240,240);} -QPushButton:hover{background-color: rgb(209,209,209);} - - - 关于 - - - - - - - - - 30 - 50 - 100 - 100 - - - - avatar - - - - - - 0 - 0 - 71 - 28 - - - - 退出登录 - - - - - - 80 - 0 - 71 - 28 - - - - 注销账户 - - - - - - + Dialog + + + + 0 + 0 + 1280 + 720 + + + + ArrowCursor + + + Dialog + + + false + + + + + 160 + 0 + 1120 + 720 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + 0 + 0 + 161 + 721 + + + + background-color:rgb(240,240,240) + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + + 20 + 190 + 111 + 501 + + + + + 0 + + + + + + 0 + 80 + + + + QPushButton {background-color: rgb(240,240,240);} + QPushButton:hover{background-color: rgb(209,209,209);} + + + + 聊天 + + + + + + + + 0 + 80 + + + + QPushButton {background-color: rgb(240,240,240);} + QPushButton:hover{background-color: rgb(209,209,209);} + + + + 联系人 + + + + + + + + 100 + 80 + + + + QPushButton {background-color: rgb(240,240,240);} + QPushButton:hover{background-color: rgb(209,209,209);} + + + + 我的 + + + + + + + + 100 + 80 + + + + QPushButton {background-color: rgb(240,240,240);} + QPushButton:hover{background-color: rgb(209,209,209);} + + + + 关于 + + + + + + + + + 30 + 50 + 100 + 100 + + + + avatar + + + + + + 0 + 0 + 71 + 28 + + + + 退出登录 + + + + + + 80 + 0 + 71 + 28 + + + + 注销账户 + + + + + + diff --git a/app/data/icon.png b/app/data/icon.png index 8e6590f309a15cda9c92da50ee2492184a95d1f7..4920ebdebde8a2c65f27382cfa5aef2e0c31bf25 100644 GIT binary patch literal 910 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 diff --git a/main.py b/main.py index 53aa065..5614723 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,7 @@ -from PyQt5.QtWidgets import * -from PyQt5.QtCore import * -from PyQt5.QtGui import * import sys + +from PyQt5.QtWidgets import * + from app.Ui import * @@ -23,9 +23,10 @@ class ViewController: 注册界面 :return: """ - self.viewDecrypt = register.registerControl() # 需要将viewlogin设为成员变量 - self.viewDecrypt.DecryptSignal.connect(self.loadDecryptView) - self.viewDecrypt.show() + pass + # self.viewDecrypt = register.registerControl() # 需要将viewlogin设为成员变量 + # self.viewDecrypt.DecryptSignal.connect(self.loadDecryptView) + # self.viewDecrypt.show() def loadMainWinView(self, username): """ @@ -46,6 +47,6 @@ class ViewController: if __name__ == '__main__': app = QApplication(sys.argv) view = ViewController() - # view.loadDecryptView() # 进入登录界面,如果viewlogin不是成员变量,则离开作用域后失效。 - view.loadMainWinView('102') + view.loadDecryptView() # 进入登录界面,如果viewlogin不是成员变量,则离开作用域后失效。 + # view.loadMainWinView('102') sys.exit(app.exec_()) diff --git a/test.html b/test.html index 72ff00f..9ed6e65 100644 --- a/test.html +++ b/test.html @@ -3,8 +3,7 @@ Title - - - -
- - - - - - - - > - - - - - - - -
- %s 13245: - - - - - ADC
- %s 13245: -
+ + + + + + + + + + + +
+ + + + + + + + + > + + + + + + + +
+ + + + + + + + + ADC
+ %s 13245: +
- - Document + + Document - - - - - - - - - - - - - - - - - - - - - - - - - - -
我是标题
英雄性别职业
亚索中单
卡莎ADC
寒冰
+ + + + + + + + + + + + + + + + + + + + + + + + + +
我是标题
英雄性别职业
亚索中单
卡莎ADC
寒冰
diff --git a/wechat.html b/wechat.html index 6d22c10..15d1ce8 100644 --- a/wechat.html +++ b/wechat.html @@ -1,168 +1,55 @@ - - - - - - - - -title + + 聊天时间 + + + + -
-
-
- 我要抢楼 - -
- -
-
- -
- - 欢迎来抢楼!欢迎来抢楼!欢迎来抢楼!欢迎来抢楼!欢迎来抢楼!欢迎来抢楼!欢迎来抢楼! -
-
-
-
- 我要抢楼我要抢楼我要抢楼。 - -
- -
-
- -
- - 欢迎来抢楼!欢迎来抢楼!欢迎来抢楼!欢迎来抢楼!欢迎来抢楼!欢迎来抢楼! -
-
-
+ +
+ 你好 +
+ + \ No newline at end of file