diff --git a/.idea/MQTT.iml b/.idea/MQTT.iml index 8f27b1c..054e406 100644 --- a/.idea/MQTT.iml +++ b/.idea/MQTT.iml @@ -1,15 +1,10 @@ -<<<<<<< HEAD - - -======= - ->>>>>>> 2a86a8c5265eb866f144ab4c69c24b7e6c510b47 + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 9de2865..b89f1da 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,7 +1,4 @@ - - - + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index a2b8651..35eb1dd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,6 +2,5 @@ - \ No newline at end of file diff --git a/main/__pycache__/mysql.cpython-310.pyc b/main/__pycache__/mysql.cpython-310.pyc index a53ba04..5675076 100644 Binary files a/main/__pycache__/mysql.cpython-310.pyc and b/main/__pycache__/mysql.cpython-310.pyc differ diff --git a/main/__pycache__/mysql.cpython-311.pyc b/main/__pycache__/mysql.cpython-311.pyc index f9bbdcb..b66d6da 100644 Binary files a/main/__pycache__/mysql.cpython-311.pyc and b/main/__pycache__/mysql.cpython-311.pyc differ diff --git a/main/client/Client.py b/main/client/Client.py index 9d6f607..d06561f 100644 --- a/main/client/Client.py +++ b/main/client/Client.py @@ -62,6 +62,7 @@ def clientStart(self):#启动进程,使用threading(python自带进程管理 class Register(Client): def __init__(self,userName,userPwd): super().__init__(userName,userPwd) + self.flag=False #标志注册是否成功 self.clientStart() self.publishRegister() @@ -84,6 +85,7 @@ def on_message(self,client, userdata, msg):#接受数据 if code==0: print(message) if code==1: + self.flag=True #成功了更新 print(message) return data @@ -99,6 +101,7 @@ def publishRegister(self): class Login(Client): def __init__(self,userName,userPwd): super().__init__(userName,userPwd) + self.flag=False self.clientStart() self.publishLogin() @@ -120,6 +123,7 @@ def on_message(self,client, userdata, msg):#接受数据 if code==0: #表示登入失败 print(message) if code==1: #表示登入成功 + self.flag=True print(message) return data @@ -154,7 +158,7 @@ def on_message(self, client, userdata, msg): # 接受数据 messages = eval(msg.payload.decode('utf-8')) # 读取数据 - self.messages=messages #存到类中 + self.messages=messages #返回一个字典的列表,['id':id,'senderID':senderID,'message':message]存到类中 print(messages) @@ -301,7 +305,7 @@ def reset_password(self, answer, new_password): #################################################################### def main(): - + SendMessage("1234","1234") diff --git a/main/config/__pycache__/config.cpython-310.pyc b/main/config/__pycache__/config.cpython-310.pyc index 32b391d..4168235 100644 Binary files a/main/config/__pycache__/config.cpython-310.pyc and b/main/config/__pycache__/config.cpython-310.pyc differ diff --git a/main/config/__pycache__/config.cpython-311.pyc b/main/config/__pycache__/config.cpython-311.pyc index 9f89627..ad60920 100644 Binary files a/main/config/__pycache__/config.cpython-311.pyc and b/main/config/__pycache__/config.cpython-311.pyc differ diff --git a/main/mysql.py b/main/mysql.py index c85963c..3bead31 100644 --- a/main/mysql.py +++ b/main/mysql.py @@ -33,6 +33,7 @@ class ChatModel(BaseModel): message = TextField() senderId=BigIntegerField() time = DateTimeField(default=datetime.datetime.now) + senderName=CharField(max_length=64) class Meta: db_table = 'chat' @@ -49,7 +50,7 @@ class CreateTable: @staticmethod def create(): db.connect() - db.create_tables([UserModel, ChatModel,LikeModel]) + db.create_tables([UserModel, ChatModel,LikeModel,SecurityQuestionModel]) @@ -121,7 +122,8 @@ def getAllManage(): 'id': chat.id, 'message': chat.message, 'senderId': chat.senderId, - 'time': chat.time + 'time': chat.time, + 'senderName':chat.senderName } chat_list.append(chat_data) return chat_list @@ -130,9 +132,9 @@ def getAllManage(): return None @staticmethod - def AddChat(message,senderId): + def AddChat(message,senderId,senderName): try: - ChatModel.insert(message=message,senderId=senderId).execute() + ChatModel.insert(message=message,senderId=senderId,senderName=senderName).execute() return True except Exception as error: print(error) @@ -243,3 +245,4 @@ def reset_password(user_name, new_password): print(f"发生错误: {error}") return False +CreateTable.create() \ No newline at end of file diff --git a/main/server/Server.py b/main/server/Server.py index 23bbe0b..6a05722 100644 --- a/main/server/Server.py +++ b/main/server/Server.py @@ -146,45 +146,89 @@ def __init__(self): super().__init__() self.serverStart() - def on_connect(self, client, userdata, flags, rc): if rc == 0: print("Connected successfully") client.subscribe('like') - client.subscribe('login') # 订阅 login 主题 else: print("Failed to connect, return code %d\n", rc) + def on_message(self, client, userdata, msg): + data = eval(msg.payload.decode('utf-8')) + messageId = data.get('message_id') + returnTopic = data.get('returnTopic') + print("Publishing to topic:", returnTopic) + self.like_message(messageId, returnTopic) + def like_message(self, messageId, returnTopic): + like_count = LikeManage.like_message(messageId) + if like_count is not None: + data = {'code': 1, 'like_count': like_count} + self.client.publish(returnTopic, str(data).encode(), 1) + else: + data = {'code': 0, 'message': '点赞失败'} + self.client.publish(returnTopic, str(data).encode(), 1) + + + + +class SecurityServer(Server): + def __init__(self): + super().__init__() + self.serverStart() + + def on_connect(self, client, userdata, flags, rc): + if rc == 0: + print("连接成功") + client.subscribe('set_security_question') + client.subscribe('request_security_question',) + client.subscribe('verify_security_answer') + else: + print("连接失败,返回码 %d\n", rc) def on_message(self, client, userdata, msg): - # 规定传入数据均为dict的形式 - if msg.topic == 'like': - data = eval(msg.payload.decode('utf-8')) - messageId = data.get('message_id') - returnTopic = data.get('return_topic') - - if not messageId: - print("Invalid message format") - return - - - # 更新点赞数量 - new_count = LikeManage.like_message(messageId) - - if new_count is None: - print(f"Failed to update like count for message ID: {messageId}") - return - - print(f'处理并新的点赞计数成功') - # 此处可以输出最高点赞的消息ID - try: - top_message_id = LikeModel.select().order_by(LikeModel.count.desc()).get() - if top_message_id: - print(f'Top liked message ID: {top_message_id}') - else: - print('No top liked message found.') - except Exception as e: - print(f"Error retrieving top liked message: {e}") + data = eval(msg.payload.decode('utf-8')) + if msg.topic == 'set_security_question': + user_name = data.get('userName') + question = data.get('question') + answer = data.get('answer') + returnTopic = data.get('returnTopic') + success = SecurityQuestionManage.set_security_question(user_name, question, answer) + if success == True: + code = 1 + else: + code = 0 + data = { + 'action': 'set_question', + 'code': code + } + client.publish(returnTopic, str(data).encode(), 1) + + elif msg.topic == 'request_security_question': + user_name = data.get('userName') + returnTopic = data.get('returnTopic') + + user = UserModel.get(UserModel.name == user_name) + security_question = SecurityQuestionModel.get(SecurityQuestionModel.user_id == user.id) + data = { + 'action': 'request_question', + 'question': security_question.question + } + client.publish(returnTopic, str(data).encode(), 1) + + elif msg.topic == 'verify_security_answer': + user_name = data.get('userName') + answer = data.get('answer') + newPassword = data.get('new_password') + returnTopic = data.get('returnTopic') + success = SecurityQuestionManage.verify_security_answer(user_name, answer, newPassword) + if success: code = 1 + else: code = 0 + data = { + 'action': 'verify_security_answer', + 'code': code + } + client.publish(returnTopic, str(data).encode(), 1) + ################################################################################### #jia yikun class ChatSave(Server): @@ -206,6 +250,7 @@ def on_message(self, client, userdata, msg): data = eval(msg.payload.decode('utf-8')) message = data.get('message') userName = data.get('userName') + print(data) returnTopic = data.get('returnTopic') user=UserManage.chackName(userName) if user == None: @@ -213,8 +258,7 @@ def on_message(self, client, userdata, msg): self.client.publish(returnTopic, str(data).encode(), 1) else: print('new_message ',user.id,':', message) - chat = ChatManage() - if chat.AddChat(message, user.id): + if ChatManage.AddChat(message, user.id,userName): data = {'code': 1, 'message': "消息发送成功"} self.client.publish(returnTopic, str(data).encode(), 1) else: @@ -241,8 +285,6 @@ def on_message(self, client, userdata, msg): returnTopic = data.get('returnTopic') chat = ChatManage() payload = str(chat.getAllManage()) - print('历史消息为:') - print(payload) return self.client.publish(returnTopic, payload=payload, qos=2, retain=False) @@ -254,6 +296,6 @@ def main(): b=Login() #进程2,处理登入 c=Like() #进程3,处理点赞 d=ChatAll() #进程4,处理所有消息 - e=ChatSave() #进程5,处理消息报存 + e=ChatSave() #进程5,处理消息保存 main() \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8ddcfba --- /dev/null +++ b/requirements.txt @@ -0,0 +1,75 @@ +appnope==0.1.4 +asgiref==3.7.2 +asttokens==2.4.1 +attrs==23.2.0 +backcall @ file:///home/ktietz/src/ci/backcall_1611930011877/work +beautifulsoup4==4.12.3 +bleach==6.1.0 +Brotli @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_38mvgltu8c/croots/recipe/brotli-split_1659616064542/work +certifi==2023.11.17 +charset-normalizer==3.3.2 +colorama @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_100_k35lkb/croot/colorama_1672386539781/work +decorator @ file:///opt/conda/conda-bld/decorator_1643638310831/work +defusedxml @ file:///tmp/build/80754af9/defusedxml_1615228127516/work +Django==4.2 +django-cors-headers==4.3.1 +django-filter==24.2 +djangorestframework==3.14.0 +djangorestframework-simplejwt==5.3.1 +docopt @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_5alx0ctp1q/croots/recipe/docopt_1663662430075/work +et-xmlfile==1.1.0 +executing==2.0.1 +fastjsonschema==2.19.1 +gunicorn==22.0.0 +idna==3.6 +ipython==8.12.3 +jedi==0.19.1 +Jinja2==3.1.3 +jsonschema==4.21.1 +jsonschema-specifications==2023.12.1 +jupyter_client==8.6.1 +jupyter_core==5.7.2 +jupyterlab_pygments==0.3.0 +Markdown==3.6 +MarkupSafe==2.1.5 +matplotlib-inline @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_f6fdc0hldi/croots/recipe/matplotlib-inline_1662014472341/work +mistune==3.0.2 +mysqlclient==2.2.4 +nbclient==0.10.0 +nbconvert==7.16.2 +nbformat==5.10.3 +openpyxl==3.1.2 +packaging==24.0 +paho-mqtt==2.1.0 +pandocfilters==1.5.1 +parso @ file:///opt/conda/conda-bld/parso_1641458642106/work +pexpect==4.9.0 +pickleshare @ file:///tmp/build/80754af9/pickleshare_1606932040724/work +pipreqs==0.5.0 +platformdirs==4.2.0 +prompt-toolkit @ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_c63v4kqjzr/croot/prompt-toolkit_1704404354115/work +ptyprocess==0.7.0 +pure-eval==0.2.2 +Pygments==2.17.2 +PyJWT==2.8.0 +PyMySQL==1.1.0 +PySocks @ file:///Users/ktietz/ci_310/pysocks_1643961536721/work +python-dateutil==2.9.0.post0 +pytz==2024.1 +pyzmq @ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_43pxpbos3z/croot/pyzmq_1705605108344/work +referencing==0.33.0 +requests @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_b3tnputioh/croot/requests_1707355573919/work +rpds-py==0.18.0 +six @ file:///tmp/build/80754af9/six_1644875935023/work +soupsieve @ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_9798xzs_03/croot/soupsieve_1696347567192/work +sqlparse @ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_16ptvrhamb/croot/sqlparse_1690901943673/work +stack-data==0.6.3 +tinycss2 @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_fcw5_i306t/croot/tinycss2_1668168825117/work +tornado==6.4 +traitlets==5.14.2 +typing_extensions==4.9.0 +tzdata==2023.4 +urllib3 @ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_aff2m3lasf/croot/urllib3_1707770561896/work +wcwidth==0.2.13 +webencodings==0.5.1 +yarg==0.1.9 diff --git a/su/myproject/mqtt/__pycache__/__init__.cpython-310.pyc b/su/myproject/mqtt/__pycache__/__init__.cpython-310.pyc index 96dfd2f..5f1c584 100644 Binary files a/su/myproject/mqtt/__pycache__/__init__.cpython-310.pyc and b/su/myproject/mqtt/__pycache__/__init__.cpython-310.pyc differ diff --git a/su/myproject/mqtt/__pycache__/forms.cpython-310.pyc b/su/myproject/mqtt/__pycache__/forms.cpython-310.pyc index da19793..4b8882b 100644 Binary files a/su/myproject/mqtt/__pycache__/forms.cpython-310.pyc and b/su/myproject/mqtt/__pycache__/forms.cpython-310.pyc differ diff --git a/su/myproject/mqtt/__pycache__/views.cpython-310.pyc b/su/myproject/mqtt/__pycache__/views.cpython-310.pyc index c9b8cc2..f92c3c8 100644 Binary files a/su/myproject/mqtt/__pycache__/views.cpython-310.pyc and b/su/myproject/mqtt/__pycache__/views.cpython-310.pyc differ diff --git a/su/myproject/mqtt/client/Client.py b/su/myproject/mqtt/client/Client.py index 25527e3..50f590a 100644 --- a/su/myproject/mqtt/client/Client.py +++ b/su/myproject/mqtt/client/Client.py @@ -12,6 +12,7 @@ import time from abc import abstractmethod + class Client:#基类 def __init__(self, userName=None,userPwd=None): self.userName = userName @@ -61,7 +62,7 @@ def clientStart(self):#启动进程,使用threading(python自带进程管理 class Register(Client): def __init__(self,userName,userPwd): super().__init__(userName,userPwd) - self.flag=False #确定是否注册成功 + self.flag=False #标志注册是否成功 self.clientStart() self.publishRegister() @@ -84,7 +85,7 @@ def on_message(self,client, userdata, msg):#接受数据 if code==0: print(message) if code==1: - self.flag=True + self.flag=True #成功了更新 print(message) return data @@ -100,13 +101,10 @@ def publishRegister(self): class Login(Client): def __init__(self,userName,userPwd): super().__init__(userName,userPwd) - self.flag = False # + self.flag=False self.clientStart() self.publishLogin() - - - def on_connect(self, client, userdata, flags, rc):#链接 if rc == 0: print("Connected successfully") @@ -138,6 +136,82 @@ def publishLogin(self): # client.loop() print('发布信息 ', publish_topic['login_topic'], ' 成功') +###################################### +#xiao +class GetMessage(Client): + def __init__(self, userName): + super().__init__(userName=userName) + self.messages=[] + self.clientStart() + self.publishGetAllMessage() + + def on_connect(self, client, userdata, flags, rc): # 链接 + if rc == 0: + print("Connected successfully") + returnLogin = self.userName + "chatall" + client.subscribe(returnLogin) # 订阅 chatall 主题 + else: + print("Failed to connect, return code %d\n", rc) + + def on_message(self, client, userdata, msg): # 接受数据 + # 规定传入数据均为dict的形式 + + messages = eval(msg.payload.decode('utf-8')) + # 读取数据 + self.messages=messages #返回一个字典的列表,['id':id,'senderID':senderID,'message':message]存到类中 + + + def publishGetAllMessage(self): + returnTopic = self.userName + "chatall" + # 数据发送特定格式 + data = {'userName': self.userName, 'returnTopic': returnTopic} + # qos1 + self.client.publish("chatall", str(data).encode(), 1) + # client.loop() + print('发布信息 ', "chatall", ' 成功') + +###################################### +#jia yikun +class SendMessage(Client): + def __init__(self, userName, msg): + super().__init__(userName=userName) + self.message=msg + self.clientStart() + self.publishSendMessage() + + def on_connect(self, client, userdata, flags, rc): # 链接 + if rc == 0: + print("Connected successfully") + returnLogin = self.userName + "chatsend" + client.subscribe(returnLogin) # 订阅 chatall 主题 + else: + print("Failed to connect, return code %d\n", rc) + + def on_message(self, client, userdata, msg): # 接受数据 + # 规定传入数据均为dict的形式 + + data = eval(msg.payload.decode('utf-8')) + # 读取数据 + code = data.get('code') + message = data.get('message') + if code == 0: # 表示发送消息失败 + print(message) + if code == 1: # 表示发送消息成功 + print(message) + return data + + + + def publishSendMessage(self): + returnTopic = self.userName + "chatsend" + # 数据发送特定格式 + data = {'userName': self.userName,'message':self.message, 'returnTopic': returnTopic} + # qos1 + self.client.publish("chatsend", str(data).encode(), 1) + # client.loop() + print('发布信息 ', "chatsend", ' 成功') + + ###################################### #tao yu @@ -231,8 +305,8 @@ def reset_password(self, answer, new_password): #################################################################### def main(): pass - #Register("hhhhh","123456") - #Login("hhhhhh","123456") + + main() diff --git a/su/myproject/mqtt/client/__init__.py b/su/myproject/mqtt/client/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/su/myproject/mqtt/client/__pycache__/Client.cpython-310.pyc b/su/myproject/mqtt/client/__pycache__/Client.cpython-310.pyc index 2ccfd78..b36e243 100644 Binary files a/su/myproject/mqtt/client/__pycache__/Client.cpython-310.pyc and b/su/myproject/mqtt/client/__pycache__/Client.cpython-310.pyc differ diff --git a/su/myproject/mqtt/client/__pycache__/__init__.cpython-310.pyc b/su/myproject/mqtt/client/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index f94781a..0000000 Binary files a/su/myproject/mqtt/client/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/su/myproject/mqtt/config/__pycache__/config.cpython-310.pyc b/su/myproject/mqtt/config/__pycache__/config.cpython-310.pyc index 1c09d9f..6cc5559 100644 Binary files a/su/myproject/mqtt/config/__pycache__/config.cpython-310.pyc and b/su/myproject/mqtt/config/__pycache__/config.cpython-310.pyc differ diff --git a/su/myproject/mqtt/views.py b/su/myproject/mqtt/views.py index 31db68b..d2f3c51 100644 --- a/su/myproject/mqtt/views.py +++ b/su/myproject/mqtt/views.py @@ -1,13 +1,19 @@ import time - +from django.http import JsonResponse from django.shortcuts import render, redirect from django.contrib import messages from .forms import UserForm -from .client.Client import Login, Register +from .client.Client import * +import json -def chat(request): - # 示例的chat视图函数 - return render(request, 'chat.html') + +class User: + def __init__(self): + self.flag=False + self.userName='' + +u=User() +#login/register def login(request): if request.method == 'POST': @@ -19,9 +25,11 @@ def login(request): print(username) print(password) l = Login(username, password) - time.sleep(0.8) #等mqtt验证完成 大约要0.2s以上,还有程序运行时间,测试可得时间需要0.8秒 + time.sleep(1.2) #等mqtt验证完成 大约要0.2s以上,还有程序运行时间,测试可得时间需要0.8秒 if l.flag: # 登录成功 + u.flag=True #表示登入成功 + u.userName=username return redirect('chat') # 进入'chat'的路由 else: # 登录失败 @@ -44,7 +52,7 @@ def register(request): print(password) if password == confirm_password: r = Register(username, password) - time.sleep(0.8) + time.sleep(1.2) if r.flag: # 注册成功 messages.error(request, '注册成功') @@ -62,3 +70,39 @@ def register(request): return render(request, 'login.html', {'form': form}) +#chat +def chat(request): + username = u.userName # 从session中获取username + if username: + messages.info(request, f"欢迎回来 {username} (●’◡’●)") + return render(request, 'chat.html') + + + + +def getchats(request): + g=GetMessage(u.userName) + time.sleep(2) + comments = g.messages + if comments: + for comment in comments: + comment['time'] = comment['time'].strftime('%Y-%m-%d %H:%M:%S') + return JsonResponse(comments, safe=False) + else: + print("没有评论") + +def sendchat(request): + if request.method == 'POST': + if u.flag==False: + return JsonResponse({'status': 'failed', 'message': '未登入,无法评论,请先登入'}) + data = json.loads(request.body) + message = data.get('message') + print(message) + userName=u.userName + print("u.userName:"+u.userName) + SendMessage(userName,message) + time.sleep(2) + return JsonResponse({'status': 'success','message': '发送成功'}) + return JsonResponse({'status': 'failed'}) + + diff --git a/su/myproject/myproject/__pycache__/__init__.cpython-310.pyc b/su/myproject/myproject/__pycache__/__init__.cpython-310.pyc index 7dbe625..de16f68 100644 Binary files a/su/myproject/myproject/__pycache__/__init__.cpython-310.pyc and b/su/myproject/myproject/__pycache__/__init__.cpython-310.pyc differ diff --git a/su/myproject/myproject/__pycache__/settings.cpython-310.pyc b/su/myproject/myproject/__pycache__/settings.cpython-310.pyc index 82adc65..c024f5a 100644 Binary files a/su/myproject/myproject/__pycache__/settings.cpython-310.pyc and b/su/myproject/myproject/__pycache__/settings.cpython-310.pyc differ diff --git a/su/myproject/myproject/__pycache__/urls.cpython-310.pyc b/su/myproject/myproject/__pycache__/urls.cpython-310.pyc index 98e52f1..47af138 100644 Binary files a/su/myproject/myproject/__pycache__/urls.cpython-310.pyc and b/su/myproject/myproject/__pycache__/urls.cpython-310.pyc differ diff --git a/su/myproject/myproject/__pycache__/wsgi.cpython-310.pyc b/su/myproject/myproject/__pycache__/wsgi.cpython-310.pyc index ed0c612..ffb7475 100644 Binary files a/su/myproject/myproject/__pycache__/wsgi.cpython-310.pyc and b/su/myproject/myproject/__pycache__/wsgi.cpython-310.pyc differ diff --git a/su/myproject/myproject/urls.py b/su/myproject/myproject/urls.py index 75bb1f8..73c3dc6 100644 --- a/su/myproject/myproject/urls.py +++ b/su/myproject/myproject/urls.py @@ -22,5 +22,7 @@ path('admin/', admin.site.urls), path('login/', views.login, name='login'), path('register/', views.register, name='register'), + path('getchats/', views.getchats, name='getchats'), + path('sendchat/', views.sendchat, name='sendchat'), ] diff --git a/su/myproject/templates/chat.html b/su/myproject/templates/chat.html index aeb30f1..c780c79 100644 --- a/su/myproject/templates/chat.html +++ b/su/myproject/templates/chat.html @@ -1,134 +1,198 @@ + Title + + + -
+
+ + - - - - - 热门问答 - - - 诊疗前沿 - 科普专区 - 专家评价 - - 我的关注 - 我的收藏 - -
- - - - -
- -

hahahaha

-
-
- -
+ + + 热门问答 + + + 诊疗前沿 + 科普专区 + 专家评价 + + 我的关注 + 我的收藏 + + +
+ {% if messages %} +
    + {% for message in messages %} +
  • {{ message }}
  • + {% endfor %} +
+ {% endif %} +
+ +
+ + + + {% verbatim %} +
+

聊天 {{ commentCount }}

+
+ +
+ 评 论
- - -
- -
-
- - - -
- Logo -
-
- Logo +
+
+
+ Avatar +
+ +
+
{{ comment.senderName}}
+
{{ comment.message }}
+
+ {{ comment.time }} + + 评论 + +
+
+
-
- Logo -
- - - +
+
+

暂无评论

+
+
+ {% endverbatim %} + + + + + + -
+ +
- - - - - + }); + + + \ No newline at end of file