diff --git a/assets/css/extra.css b/assets/css/extra.css index 1e5a2b2..d94427c 100644 --- a/assets/css/extra.css +++ b/assets/css/extra.css @@ -240,3 +240,6 @@ li a:active .count-tab, li a:hover .count-tab{ color: white; } +.select2-drop { + width: 400px !important; +} diff --git a/assets/css/main.css b/assets/css/main.css index 62ed7f3..76c87ce 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -1987,7 +1987,7 @@ input[type="checkbox"]:checked + span { font-family: 'pfbeausanspro-reg', sans-serif; position: relative; text-align: left; - padding: 22px 21px 22px 21px; + padding: 22px 61px 22px 21px; } .profileTabs2 ul .active a:after { @@ -3534,7 +3534,7 @@ input[type="checkbox"]:checked + span { text-decoration: underline; position: relative; float: left; - margin: 11px 0 0 30px; + margin: 18px 0 0 30px; font-style: italic; } @@ -3545,7 +3545,7 @@ input[type="checkbox"]:checked + span { text-decoration: underline; position: relative; float: left; - margin: 51px 0 0 -45%; + margin: 61px 0 0 -45%; font-style: italic; display: none; } @@ -3593,9 +3593,9 @@ input[type="checkbox"]:checked + span { .messd:hover { z-index: 999; background-color: white; - -webkit-transform: scale(1.02); - -moz-transform: scale(1.02); - transform: scale(1.02); + -webkit-transform: scale(1.06); + -moz-transform: scale(1.06); + transform: scale(1.06); box-shadow: 0 0 10px rgba(0,0,0,0.7); } diff --git a/assets/index.js b/assets/index.js index 864dd3a..1176f78 100644 --- a/assets/index.js +++ b/assets/index.js @@ -51,7 +51,6 @@ $('[data-tooltip]').tooltip({ results: _.map(function(item) { return { id: item.id, - //text: item.name, text: _.repeat(item.level-1, '---') + item.name, origItem: item, } @@ -146,6 +145,34 @@ $('[data-tooltip]').tooltip({ placeholder: 'Выберите специализацию', // Required by `allowClear` allowClear: true, + ajax: { + url: '/api/specializations/', + dataType: 'json', + quietMillis: 250, + cache: true, + + data: function(term, page) { + return { + name__icontains: term, + page: page, + } + }, + + results: function(data, page) { + return { + results: _.map(function(item) { + return { + id: item.id, + text: _.repeat(item.level-1, '---') + item.name, + origItem: item, + } + }, data.results), + + more: (page * API_PAGE_SIZE) < data.count, + } + }, + }, + //initSelection: function(element, callback) { // var id = $(element).val() // @@ -185,30 +212,20 @@ $('[data-tooltip]').tooltip({ function initSimpleSpecSelect2($select, specId) { - return $.ajax({url: '/api/specializations/', method: 'GET', dataType: 'json'}) - .then(function(res) { - var specs = res.results - - $select.select2(_.merge(simpleSpecSelectsOptions, { - data: _.map(function(spec) { - return { - id: spec.id, - text: _.repeat(spec.level-1, '---') + spec.name, - origItem: spec, - } - }, specs), - })) - - if (specId) { - var spec = _.find({id: specId}, specs) - + $select.select2(simpleSpecSelectsOptions) + + if (specId) { + return $.get(format('/api/specializations/%s/', specId)) + .then(function(spec) { $select.select2('data', { id: spec.id, text: _.repeat(spec.level-1, '---') + spec.name, origItem: spec, }) - } - }) + }) + } else { + return $.when() + } } }()) diff --git a/projects/forms.py b/projects/forms.py index afe8b56..43f77c5 100644 --- a/projects/forms.py +++ b/projects/forms.py @@ -178,10 +178,10 @@ class PortfolioForm(forms.ModelForm): class Meta: model = Portfolio fields = '__all__' - + widgets = { - 'construction_type': forms.Select(attrs={'class': 'selectpicker'}), 'building_classification': forms.Select(attrs={'class': 'selectpicker'}), + 'construction_type': forms.Select(attrs={'class': 'selectpicker'}), 'currency': forms.Select(attrs={'class': 'selectpicker'}), 'term_type': forms.Select(attrs={'class': 'selectpicker'}), } @@ -216,6 +216,7 @@ class PortfolioEditForm(forms.ModelForm): 'name', 'term', 'term_type', + 'work_type', 'worksell', ) @@ -224,6 +225,7 @@ class PortfolioEditForm(forms.ModelForm): 'building_classification': forms.Select(attrs={'class': 'selectpicker'}), 'currency': forms.Select(attrs={'class': 'selectpicker'}), 'term_type': forms.Select(attrs={'class': 'selectpicker'}), + 'work_type': forms.Select(attrs={'class': 'selectpicker -project-work-type-select-field'}), } def __init__(self, *args, **kwargs): diff --git a/projects/migrations/0041_auto_20160920_1628.py b/projects/migrations/0041_auto_20160920_1628.py new file mode 100644 index 0000000..6677abb --- /dev/null +++ b/projects/migrations/0041_auto_20160920_1628.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-09-20 13:28 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0040_merge'), + ] + + operations = [ + migrations.AlterField( + model_name='project', + name='work_type', + field=models.IntegerField(choices=[(1, 'Проектирование'), (2, 'Проверка документации')], default=1), + ), + ] diff --git a/projects/migrations/0042_portfolio_work_type.py b/projects/migrations/0042_portfolio_work_type.py new file mode 100644 index 0000000..5401967 --- /dev/null +++ b/projects/migrations/0042_portfolio_work_type.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-09-20 15:37 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0041_auto_20160920_1628'), + ] + + operations = [ + migrations.AddField( + model_name='portfolio', + name='work_type', + field=models.IntegerField(choices=[(1, 'Проектирование'), (2, 'Проверка документации')], default=1), + ), + ] diff --git a/projects/models.py b/projects/models.py index 14fbe1b..a0c493c 100644 --- a/projects/models.py +++ b/projects/models.py @@ -330,6 +330,7 @@ class Portfolio(models.Model): term = models.IntegerField(default=0, null=True, blank=True) term_type = models.CharField(max_length=20, choices=TERM_TYPES, default='hour', null=True, blank=True) user = models.ForeignKey(User, related_name='portfolios', null=True, blank=True) + work_type = models.IntegerField(default=1, choices=Project.WORK_TYPES) worksell = models.BooleanField(default=False) def __str__(self): diff --git a/projects/templates/contractor_portfolio_edit.html b/projects/templates/contractor_portfolio_edit.html index 7654c26..521f57e 100644 --- a/projects/templates/contractor_portfolio_edit.html +++ b/projects/templates/contractor_portfolio_edit.html @@ -39,6 +39,16 @@ +
+

Тип работы {{ form.work_type.errors.as_text }}

+
+ +
+
+ {{ form.work_type }} +
+
+

Специализации

@@ -160,3 +170,39 @@ {% endblock %} + + +{% block js_block %} + +{% endblock %} diff --git a/projects/templates/project_detail.html b/projects/templates/project_detail.html index f761d86..13e19ce 100644 --- a/projects/templates/project_detail.html +++ b/projects/templates/project_detail.html @@ -345,14 +345,14 @@
{% if message.is_sender_customer %}

- {% firstof project.customer.get_full_name.strip project.customer.username %} | seen?: {{ message.seen_by_contractor }} + {% firstof project.customer.get_full_name.strip project.customer.username %}

{% else %}

{% if answer.author|class_name == 'User' %} - {% firstof answer.author.get_full_name.strip answer.author.username %} | seen?: {{ message.seen_by_contractor }} + {% firstof answer.author.get_full_name.strip answer.author.username %} {% elif answer.author|class_name == 'Team' %} - {% firstof answer.author.name.strip answer.author.owner.username %} | seen?: {{ message.seen_by_contractor }} + {% firstof answer.author.name.strip answer.author.owner.username %} {% endif %}

{% endif %} @@ -538,7 +538,7 @@ {% elif request.user.is_customer and project in request.user.customer_projects.all %} -
+

Исполнители

@@ -651,7 +651,7 @@

{% if answer.term_type == 'project' %} Срок: За проект - {% else %} + {% elif answer.term and answer.term_type %} Срок: {% morph answer.term TERM_TYPE_MORPHS|get:answer.term_type %} {% endif %}

@@ -718,14 +718,14 @@
{% if message.is_sender_customer %}

- {% firstof project.customer.get_full_name.strip project.customer.username %} | seen?: {{ message.seen_by_customer }} + {% firstof project.customer.get_full_name.strip project.customer.username %}

{% else %}

{% if answer.author|class_name == 'User' %} - {% firstof answer.author.get_full_name.strip answer.author.username %} | seen?: {{ message.seen_by_customer }} + {% firstof answer.author.get_full_name.strip answer.author.username %} {% elif answer.author|class_name == 'Team' %} - {% firstof answer.author.name.strip answer.author.owner.username %} | seen?: {{ message.seen_by_customer }} + {% firstof answer.author.name.strip answer.author.owner.username %} {% endif %}

{% endif %} @@ -1171,5 +1171,15 @@ window.toggleProjectAnswerForm = toggleProjectAnswerForm }()) + + + + // Scroll to answers ------------------------------------- + + setTimeout(function() { + if (_.includes(window.location.hash, ['#new-answers','#candidate-answers','#rejected-answers'])) { + $(window).scrollTop($('.-answers-scroll-to').first().offset().top) + } + }, 100) {% endblock %} diff --git a/projects/views.py b/projects/views.py index fb1b1d2..295ef32 100644 --- a/projects/views.py +++ b/projects/views.py @@ -111,7 +111,18 @@ class ProjectDetailWithAnswerView(BaseMixin, View): if request.POST.get('answer_as_team') == 'on': answer_as_team = True - + + + # Check for duplicate answers: + + if answer_as_team and util.has_related(request.user, 'team'): + if project.answers.filter(object_id=request.user.team.pk, content_type__model='team').exists(): + raise PermissionDenied('Повторный отклик') + else: + if project.answers.filter(object_id=request.user.pk, content_type__model='user').exists(): + raise PermissionDenied('Повторный отклик') + + if answer_as_team: form = self.form_class(request.POST, request=request, answer_as_team=True, project=project) else: diff --git a/users/templates/contractor_profile.html b/users/templates/contractor_profile.html index 4d961c9..b5519e8 100644 --- a/users/templates/contractor_profile.html +++ b/users/templates/contractor_profile.html @@ -635,7 +635,7 @@ var portfUrl = new URI('/api/portfolios/') var workSellUrl = new URI('/api/work-sells/') - var pageSize = {% if TESTING %}99999{% else %}9{% endif %} + var pageSize = {% if TESTING %}99{% else %}9{% endif %} function loadMorePortfolios() { var query = portfUrl.query(true) @@ -817,8 +817,72 @@ + // Load portfolio specialization choices by work type --------------------------- + ;(function() { + var $specSelectContainer = $('.-spec-select-container.-for-portfolios').first() + var $specSelects = $specSelectContainer.find('.-spec-select') + + var $chosenSpecId = $specSelectContainer.find('.-chosen-spec-id').first() + + var $specSelect1 = $specSelectContainer.find('.-spec-select-level-1').first() + var $specSelect2 = $specSelectContainer.find('.-spec-select-level-2').first() + var $specSelect3 = $specSelectContainer.find('.-spec-select-level-3').first() + var $specSelect4 = $specSelectContainer.find('.-spec-select-level-4').first() + var specSelects = [$specSelect1, $specSelect2, $specSelect3, $specSelect4] + + var $workTypeSelect = $('.-project-work-type-select-field').first() + + var workTypeId = Number($workTypeSelect.find('option:selected').first().val()) || 1 + reinitSpecializationsByWorkType($specSelects, workTypeId) + + var chosenSpecId = $chosenSpecId.val() + + if (chosenSpecId) + updateSpecializationWidgets(chosenSpecId, $specSelectContainer, $chosenSpecId, specSelects) + + $workTypeSelect.on('change', function($evt) { + var $that = $(this) + var workTypeId = Number($that.val()) + reinitSpecializationsByWorkType($specSelects, workTypeId) + }) + }()) + + + + // Load "work_sell" specialization choices by work type --------------------------- + + + ;(function() { + var $specSelectContainer = $('.-spec-select-container.-for-work-sell').first() + var $specSelects = $specSelectContainer.find('.-spec-select') + + var $chosenSpecId = $specSelectContainer.find('.-chosen-spec-id').first() + + var $specSelect1 = $specSelectContainer.find('.-spec-select-level-1').first() + var $specSelect2 = $specSelectContainer.find('.-spec-select-level-2').first() + var $specSelect3 = $specSelectContainer.find('.-spec-select-level-3').first() + var $specSelect4 = $specSelectContainer.find('.-spec-select-level-4').first() + var specSelects = [$specSelect1, $specSelect2, $specSelect3, $specSelect4] + + var $workTypeSelect = $('.-project-work-type-select-field').first() + + var workTypeId = Number($workTypeSelect.find('option:selected').first().val()) || 1 + reinitSpecializationsByWorkType($specSelects, workTypeId) + + var chosenSpecId = $chosenSpecId.val() + + if (chosenSpecId) + updateSpecializationWidgets(chosenSpecId, $specSelectContainer, $chosenSpecId, specSelects) + + $workTypeSelect.on('change', function($evt) { + var $that = $(this) + var workTypeId = Number($that.val()) + reinitSpecializationsByWorkType($specSelects, workTypeId) + }) + }()) + diff --git a/users/templates/portfolio_create_form.html b/users/templates/portfolio_create_form.html index e9ed537..9615da4 100644 --- a/users/templates/portfolio_create_form.html +++ b/users/templates/portfolio_create_form.html @@ -18,12 +18,21 @@
+ +
+

Тип работы

+
+
+
+ {{ portfolio_form.work_type }} +
+

Специализации

-
+
diff --git a/users/templates/worksell_create_form.html b/users/templates/worksell_create_form.html index 99276c0..9d072b3 100644 --- a/users/templates/worksell_create_form.html +++ b/users/templates/worksell_create_form.html @@ -14,12 +14,21 @@

Подробно опишите задание {{ worksell_form.description.errors.as_text }}

+ +
+

Тип работы

+
+
+
+ {{ worksell_form.work_type }} +
+

Специализации

-
+
diff --git a/work_sell/forms.py b/work_sell/forms.py index 5d81052..ae67fa3 100644 --- a/work_sell/forms.py +++ b/work_sell/forms.py @@ -45,13 +45,15 @@ class WorkSellForm(forms.ModelForm): 'name', 'term', 'term_type', + 'work_type', ) widgets = { - 'construction_type': forms.Select(attrs={'class': 'selectpicker'}), 'building_classification': forms.Select(attrs={'class': 'selectpicker'}), + 'construction_type': forms.Select(attrs={'class': 'selectpicker'}), 'currency': forms.Select(attrs={'class': 'selectpicker'}), 'term_type': forms.Select(attrs={'class': 'selectpicker'}), + 'work_type': forms.Select(attrs={'class': 'selectpicker -project-work-type-select-field'}), } def __init__(self, *args, **kwargs): diff --git a/work_sell/migrations/0016_worksell_work_type.py b/work_sell/migrations/0016_worksell_work_type.py new file mode 100644 index 0000000..c7aaa5b --- /dev/null +++ b/work_sell/migrations/0016_worksell_work_type.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-09-20 13:28 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('work_sell', '0015_auto_20160915_2056'), + ] + + operations = [ + migrations.AddField( + model_name='worksell', + name='work_type', + field=models.IntegerField(choices=[(1, 'Проектирование'), (2, 'Проверка документации')], default=1), + ), + ] diff --git a/work_sell/models.py b/work_sell/models.py index bcddff8..e94db8e 100644 --- a/work_sell/models.py +++ b/work_sell/models.py @@ -4,7 +4,7 @@ from mptt.models import TreeForeignKey from sorl.thumbnail import ImageField from users.models import User, Team -from projects.models import BuildingClassfication, ConstructionType, TERM_TYPES, CURRENCIES +from projects.models import BuildingClassfication, ConstructionType, TERM_TYPES, CURRENCIES, Project from specializations.models import Specialization @@ -24,6 +24,7 @@ class WorkSell(models.Model): team = models.ForeignKey(Team, related_name='work_sells', null=True, blank=True) term = models.IntegerField(default=0, null=True, blank=True) term_type = models.CharField(max_length=20, choices=TERM_TYPES, default='hour', null=True, blank=True) + work_type = models.IntegerField(default=1, choices=Project.WORK_TYPES) def __str__(self): return self.name diff --git a/work_sell/templates/worksell_edit.html b/work_sell/templates/worksell_edit.html index 6875596..f66510e 100644 --- a/work_sell/templates/worksell_edit.html +++ b/work_sell/templates/worksell_edit.html @@ -38,7 +38,17 @@
-
+
+

Тип работы {{ form.work_type.errors.as_text }}

+
+ +
+
+ {{ form.work_type }} +
+
+ +

Специализации {{ form.specialization.errors.as_text }}

@@ -161,3 +171,39 @@
{% endblock %} + + +{% block js_block %} + +{% endblock %}