From e4846f39da75b930a0ef443aedf5cc75bef9fa36 Mon Sep 17 00:00:00 2001 From: Mukhtar Date: Mon, 19 Sep 2016 17:13:58 +0300 Subject: [PATCH] #ARC-16 Fixes chat --- assets/css/extra.css | 51 +++++++++++++++++++ assets/js/chat.js | 47 +---------------- assets/js/chat_customer.js | 51 +++++++++++++++++-- chat/chat.py | 14 +++-- chat/serializers.py | 2 +- chat/templates/chat_contractor.html | 11 ++-- chat/templates/chat_customer.html | 10 ++-- chat/views.py | 2 + .../migrations/0037_auto_20160919_1126.py | 20 ++++++++ ratings/migrations/0002_historyrating_type.py | 20 ++++++++ ratings/models.py | 10 ++++ users/models.py | 3 +- users/templatetags/user_tags.py | 7 +++ 13 files changed, 185 insertions(+), 63 deletions(-) create mode 100644 projects/migrations/0037_auto_20160919_1126.py create mode 100644 ratings/migrations/0002_historyrating_type.py diff --git a/assets/css/extra.css b/assets/css/extra.css index c01a8ac..1e5a2b2 100644 --- a/assets/css/extra.css +++ b/assets/css/extra.css @@ -189,3 +189,54 @@ font-style: italic; } + +.trashedOrderBlock { + width: 100%; + float: left; + margin-bottom: -1px; + padding: 15px; + background-color: #F7F7F7; + border-top: 1px solid #72767C; + border-bottom: 1px solid #72767C; + position: relative; + cursor: pointer; + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; +} + +.trashedOrderBlock:hover { + background-color: white; + border-top: 1px solid black; + border-bottom: 1px solid black; + -webkit-transform: scale(1.03); + -moz- transform: scale(1.03); + transform: scale(1.03); + box-shadow: 0 0 10px rgba(0,0,0,0.7); + z-index: 999; +} + + +.count-tab{ + margin-left: 10px; + width: 35px; + height: 35px; + border-radius: 100%; + line-height: 35px; + text-align: center; + font-size: 14px; + font-family: 'Arial-MT-Regular', sans-serif; + position: absolute; + top: 14px; + cursor: pointer; + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; + background-color: #ebebeb; +} + +li a:active .count-tab, li a:hover .count-tab{ + background-color: #FF0027; + color: white; +} + diff --git a/assets/js/chat.js b/assets/js/chat.js index 3bb7d75..2f09eb5 100644 --- a/assets/js/chat.js +++ b/assets/js/chat.js @@ -64,7 +64,7 @@ var SocketHandler = function () { } else if (message.answer_type == 'approve_stages') { var resOrderId = message.order_id; $.jGrowl(message.msg, { - life: 4000 + life: 15000 }); setTimeout(function () { $("#orderBlock" + resOrderId).trigger('click'); @@ -185,51 +185,6 @@ function dialog (message, yesCallback, notCallback) { } - - $(".messageBlock").on('click','.trashedOrderBlock',function(){ - $("#chat-order-add").css("display", "none"); - $('.order-block, .trashedOrderBlock').each(function () { - $(this).removeClass('orAct'); - }); - $(this).addClass('orAct'); - var inbox = document.getElementById('message-chat-order-space'); - var docList = document.getElementById('documentOrderSpace'); - inbox.innerHTML = ''; - docList.innerHTML = ''; - var orderId = $(this).attr('data-id'); - location.hash = '#order' + orderId; - - $.ajax({ - url: '/api/message', - type: 'GET', - data: {csrfmiddlewaretoken: csrftoken, 'order': orderId, 'team__isnull': 'true'}, - dataType: 'json', - success: function (json) { - $.each(json.results, function (i, v) { - var senderName = 'Вы'; - var className = 'youChat'; - - if (v.sender.id !== userId) { - senderName = v.sender.username; - className = ''; - } - - inbox.innerHTML += '
' + - '

' + senderName + '

' + v.created + '
' + - '

' + v.text + '

'; - - }); - var height = inbox.scrollHeight; - inbox.scrollTop = height; - } - }); - - $("#order-stages").html(""); - $("#completeWork").hide(); - $("#add-form-order-note").hide(); - - }); - // Информация о заказе $(".messageBlock").on('click','.full-order-info', function (e) { e.preventDefault(); diff --git a/assets/js/chat_customer.js b/assets/js/chat_customer.js index 97779b4..b0c1be4 100644 --- a/assets/js/chat_customer.js +++ b/assets/js/chat_customer.js @@ -137,7 +137,7 @@ $(function () { '

Этап

' + '

' + '

' + - '

' + + '

' + '' + '' + '

' + @@ -366,6 +366,7 @@ $(function () { "msg": "Этапы для заказа " + currentOrderId + " изменены", } }); + $.jGrowl("Этапы для заказа изменены и отправлены исполнителю", { life: 15000}); }); @@ -390,7 +391,7 @@ $(function () { '' + '

' + '

' + - '
'; + ''; lastFormStage.after(addFormTemplate); } @@ -408,7 +409,7 @@ $(function () { } }); - + // Нажимаем на кнопку архивные сообщения $("#trashed-button").on('click',function(e){ e.preventDefault(); var state = $(this).attr('data-show'); @@ -452,6 +453,50 @@ $(function () { }); + // Нажимаем на заказ в архмвных заказах + $(".messageBlock").on('click','.trashedOrderBlock',function(){ + $("#chat-order-add").css("display", "none"); + $('.order-block, .trashedOrderBlock').each(function () { + $(this).removeClass('orAct'); + }); + $(this).addClass('orAct'); + var inbox = document.getElementById('message-chat-order-space'); + var docList = document.getElementById('documentOrderSpace'); + inbox.innerHTML = ''; + docList.innerHTML = ''; + var orderId = $(this).attr('data-id'); + location.hash = '#order' + orderId; + + $.ajax({ + url: '/api/message', + type: 'GET', + data: {csrfmiddlewaretoken: csrftoken, 'order': orderId, 'team__isnull': 'true'}, + dataType: 'json', + success: function (json) { + $.each(json.results, function (i, v) { + var senderName = 'Вы'; + var className = 'youChat'; + + if (v.sender.id !== userId) { + senderName = v.sender.username; + className = ''; + } + + inbox.innerHTML += '
' + + '

' + senderName + '

' + v.created + '
' + + '

' + v.text + '

'; + + }); + var height = inbox.scrollHeight; + inbox.scrollTop = height; + } + }); + + $("#order-stages").html(""); + $("#completeWork").hide(); + $("#add-form-order-note").hide(); + $("#reserveSpace").hide(); + }); // Для заказов все вытащить $('.order-block').on('click', function () { diff --git a/chat/chat.py b/chat/chat.py index 3d6ab48..57786f5 100644 --- a/chat/chat.py +++ b/chat/chat.py @@ -24,12 +24,13 @@ class ChatHandler(websocket.WebSocketHandler): waiters = set() def open(self, *args, **kwargs): - self.user_id = kwargs.get('user_id',1) + self.user_id = kwargs.get('user_id', 1) self.waiters.add((self.user_id, self)) # @gen.coroutine def on_message(self, message): parsed = escape.json_decode(message) + if 'dummy' in parsed: return @@ -50,9 +51,10 @@ class ChatHandler(websocket.WebSocketHandler): # order_id = data['data'].get('order_id') # message = data['data'].get('msg', 'Этапы обновлены') # answer_type = data['format_type'] - # waiters = tuple(w for c, w in self.waiters if c == recipent_id or c == sender_id) + # waiters = tuple(w for c, w in self.waiters if c == recipent_id) # for waiter in waiters: - # waiter.write_message({'msg': message, 'order_id': order_id, 'answer_type': answer_type}) + # print(waiter) + # # waiter.write_message({'msg': message, 'order_id': order_id, 'answer_type': answer_type}) @gen.coroutine def add_message(self, message_data): @@ -127,7 +129,11 @@ class ChatHandler(websocket.WebSocketHandler): if docs_links: message += '

' + docs_links; - waiters = tuple(w for c, w in self.waiters if c == recipent_id or c == sender_id) + if message_type: + waiters = tuple(w for c, w in self.waiters if c == recipent_id) + else: + waiters = tuple(w for c, w in self.waiters if c == recipent_id or c == sender_id) + for waiter in waiters: waiter.write_message({'msg': message, 'msg_time': msg_time, diff --git a/chat/serializers.py b/chat/serializers.py index 31c153c..5b9b59f 100644 --- a/chat/serializers.py +++ b/chat/serializers.py @@ -63,7 +63,7 @@ class MessageSerializer(ModelSerializer): out = obj.text documents = obj.documents.all() if len(documents)>0: - documents_str = '
'.join(['Входящий файл:
' + doc.file.name + '' for doc in documents]) + documents_str = '
'.join(['Приложенный файл:
' + doc.file.name + '' for doc in documents]) out += '

' + documents_str return out diff --git a/chat/templates/chat_contractor.html b/chat/templates/chat_contractor.html index 095e7fd..c4fdb07 100644 --- a/chat/templates/chat_contractor.html +++ b/chat/templates/chat_contractor.html @@ -1,6 +1,7 @@ {% extends 'partials/base.html' %} {% load staticfiles %} {% load thumbnail %} +{% load user_tags %} {% block content %} {% include 'partials/header.html' %}
@@ -16,15 +17,15 @@ @@ -56,8 +57,8 @@

Контакты - - 0 + + {% get_new_count_for_contact contact request.user %} Удалить контакт diff --git a/chat/templates/chat_customer.html b/chat/templates/chat_customer.html index 629f840..c8728f3 100644 --- a/chat/templates/chat_customer.html +++ b/chat/templates/chat_customer.html @@ -1,6 +1,7 @@ {% extends 'partials/base.html' %} {% load staticfiles %} {% load thumbnail %} +{% load user_tags %} {% block content %} {% include 'partials/header.html' %}
@@ -14,10 +15,11 @@ @@ -52,7 +54,9 @@ Контакты - 0 + + {% get_new_count_for_contact contact request.user %} + Удалить контакт diff --git a/chat/views.py b/chat/views.py index 4ccaf25..97bdb24 100644 --- a/chat/views.py +++ b/chat/views.py @@ -53,12 +53,14 @@ class ChatUserView(LoginRequiredMixin, View): users_ids.append(b) if user_id: users_ids.append(int(user_id)) + print(users_ids) contacts_users = User.objects.filter(pk__in=users_ids) chat_messages = Message.objects.filter(Q(sender=request.user.pk) | Q(recipent=request.user.pk)) orders = request.user.customer_projects.select_related('order').filter(state='active').exclude(order__contractor__isnull=True, order__team__isnull=True) transaction = Transaction.objects.get_or_create(customer=request.user, type='reservation', complete=False) self.template_name = 'chat_customer.html' + return render(request, self.template_name, {'contacts_users': contacts_users, 'chat_messages': chat_messages, 'orders': orders, diff --git a/projects/migrations/0037_auto_20160919_1126.py b/projects/migrations/0037_auto_20160919_1126.py new file mode 100644 index 0000000..0e1c166 --- /dev/null +++ b/projects/migrations/0037_auto_20160919_1126.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-09-19 08:26 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0036_auto_20160917_2135'), + ] + + operations = [ + migrations.AlterField( + model_name='project', + name='work_type', + field=models.IntegerField(choices=[(1, 'Проектирование'), (2, 'Проверка документации'), (3, 'Устранение замечаний в проекте')], default=1), + ), + ] diff --git a/ratings/migrations/0002_historyrating_type.py b/ratings/migrations/0002_historyrating_type.py new file mode 100644 index 0000000..99caa6c --- /dev/null +++ b/ratings/migrations/0002_historyrating_type.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-09-19 08:26 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ratings', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='historyrating', + name='type', + field=models.CharField(choices=[('OCCUPANCY_PROFILE', 'occupancy_profile'), ('SECURE_DEAL', 'secure_deal'), ('REVIEW', 'review'), ('MONEY_SPENT', 'money_spent'), ('PUBLICATION_PROJECT', 'publication_project'), ('VISIT_SITE', 'visit_site'), ('CHOICE_CONTRACTOR', 'choice_contractor')], default='review', max_length=50), + ), + ] diff --git a/ratings/models.py b/ratings/models.py index a231776..a9613a2 100644 --- a/ratings/models.py +++ b/ratings/models.py @@ -5,11 +5,21 @@ from specializations.models import Specialization class HistoryRating(models.Model): + TYPES_HISTORY_RATING = ( + ('OCCUPANCY_PROFILE', 'occupancy_profile'), + ('SECURE_DEAL', 'secure_deal'), + ('REVIEW', 'review'), + ('MONEY_SPENT', 'money_spent'), + ('PUBLICATION_PROJECT', 'publication_project'), + ('VISIT_SITE', 'visit_site'), + ('CHOICE_CONTRACTOR', 'choice_contractor'), + ) user = models.ForeignKey(User, related_name='history_ratings', null=True, blank=True) team = models.ForeignKey(Team, related_name='history_ratings', null=True, blank=True) rating = models.IntegerField(default=0) created = models.DateTimeField(default=timezone.now) description = models.TextField(blank=True) + type = models.CharField(max_length=50, choices=TYPES_HISTORY_RATING, default='review') def __str__(self): return '{0}'.format(self.rating) diff --git a/users/models.py b/users/models.py index e21612e..9dc2437 100644 --- a/users/models.py +++ b/users/models.py @@ -171,7 +171,8 @@ class User(AbstractBaseUser, PermissionsMixin): return self.email def get_full_name(self): - return self.first_name + ' ' + self.last_name + full_name = self.first_name + ' ' + self.last_name + return full_name or self.username def get_profile_image(self): return self.avatar diff --git a/users/templatetags/user_tags.py b/users/templatetags/user_tags.py index 6fb5513..048f621 100644 --- a/users/templatetags/user_tags.py +++ b/users/templatetags/user_tags.py @@ -60,3 +60,10 @@ def count_new_message_orders(context, user): def get_new_count_message(team_pk,user=None): count = NewMessage.objects.filter(user=user, message__team=team_pk, message__order__isnull=True).count() return count + +@register.simple_tag +def get_new_count_for_contact(contact, current_user): + count = current_user.new_messages.filter(message__sender=contact).count() + return count + +