remotes/origin/PR-39
ArturBaybulatov 9 years ago
parent b25676d215
commit fcdf640221
  1. 596
      assets/index.js
  2. 20
      projects/migrations/0036_auto_20160917_2135.py
  3. 3
      projects/models.py
  4. 22
      projects/templates/customer_project_create.html
  5. 32
      projects/templates/customer_project_edit.html

@ -9,6 +9,7 @@ var STUB_IMAGE_URL = '/static/img/profile.jpg'
// Plugins init --------------------------------------------
$('.datepicker').datepicker()
$('[data-tooltip]').tooltip({
@ -25,102 +26,101 @@ $('[data-tooltip]').tooltip({
// Specialization select -----------------------------------
var specSelectOptions = {
language: 'ru',
//minimumInputLength: 1, // Commented out to immediately load remote data
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,
}
},
;(function() {
var specSelectOptions = {
language: 'ru',
//minimumInputLength: 1, // Commented out to immediately load remote data
placeholder: 'Выберите специализацию', // Required by `allowClear`
allowClear: true,
results: function(data, page) {
return {
results: _.map(function(item) {
return {
id: item.id,
text: item.name,
origItem: item,
}
}, data.results),
more: (page * API_PAGE_SIZE) < data.count,
}
ajax: {
url: null,
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: item.name,
origItem: item,
}
}, data.results),
more: (page * API_PAGE_SIZE) < data.count,
}
},
},
},
initSelection: function(element, callback) {
var id = $(element).val()
if (id !== '') {
$.ajax({url: '/api/specializations/' + id + '/', method: 'GET', dataType: 'json'})
.then(function(data) {callback(data)})
}
}
}
$('.-spec-select-container').each(function(i, container) {
var $container = $(container)
var $specSelects = $(container).find('.-spec-select')
var $chosenSpecId = $container.find('.-chosen-spec-id').first()
var $specSelect1 = $container.find('.-spec-select-level-1').first()
var $specSelect2 = $container.find('.-spec-select-level-2').first()
var $specSelect3 = $container.find('.-spec-select-level-3').first()
var $specSelect4 = $container.find('.-spec-select-level-4').first()
var specSelects = [$specSelect1, $specSelect2, $specSelect3, $specSelect4]
$('.-spec-select-container').each(function(i, container) {
var $container = $(container)
var $specSelects = $container.find('.-spec-select')
var $chosenSpecId = $container.find('.-chosen-spec-id').first()
var $specSelect1 = $container.find('.-spec-select-level-1').first()
var $specSelect2 = $container.find('.-spec-select-level-2').first()
var $specSelect3 = $container.find('.-spec-select-level-3').first()
var $specSelect4 = $container.find('.-spec-select-level-4').first()
var specSelects = [$specSelect1, $specSelect2, $specSelect3, $specSelect4]
reinitSpecializationsByWorkType($specSelects, null)
var chosenSpecId = $chosenSpecId.val()
if (chosenSpecId)
updateSpecializationWidgets(chosenSpecId, $container, $chosenSpecId, specSelects)
$specSelects.on('change', function($evt) {
var specId = $evt.added ? $evt.added.id : null
updateSpecializationWidgets(specId, $container, $chosenSpecId, specSelects)
})
})
$specSelects.select2(specSelectOptions)
function reinitSpecializationsByWorkType($specSelects, workTypeId) {
$.get('/api/specializations/?parent__name=_root')
.then(function(res) {
var rootSpecs = res.results
var rootSpec = workTypeId == null ? rootSpecs[0] : ({1: rootSpecs[0], 2: rootSpecs[1], 3: rootSpecs[2]})[workTypeId]
$specSelects.select2(_.merge(specSelectOptions, {
ajax: {url: format('/api/specializations/?lft__gte=%s&rght__lte=%s', rootSpec.lft, rootSpec.rght)},
}))
})
}
var chosenSpecId = $chosenSpecId.val()
if (chosenSpecId)
updateSpecializationWidgets(chosenSpecId, $container, $chosenSpecId, specSelects)
function updateSpecializationWidgets(specId, $container, $chosenSpecId, specSelects) {
return getSpecializationTree(specId).then(function(specs) {
var specLevel1 = specs.specLevel1
var specLevel2 = specs.specLevel2
var specLevel3 = specs.specLevel3
var specLevel4 = specs.specLevel4
specSelects[0].select2('data', specLevel1 ? {id: specLevel1.id, text: specLevel1.name, origItem: specLevel1} : null)
specSelects[1].select2('data', specLevel2 ? {id: specLevel2.id, text: specLevel2.name, origItem: specLevel2} : null)
specSelects[2].select2('data', specLevel3 ? {id: specLevel3.id, text: specLevel3.name, origItem: specLevel3} : null)
specSelects[3].select2('data', specLevel4 ? {id: specLevel4.id, text: specLevel4.name, origItem: specLevel4} : null)
$chosenSpecId.val(specId)
})
}
$specSelects.on('change', function($evt) {
var specId = $evt.added ? $evt.added.id : null
updateSpecializationWidgets(specId, $container, $chosenSpecId, specSelects)
})
})
function updateSpecializationWidgets(specId, $container, $chosenSpecId, specSelects) {
return getSpecializationTree(specId).then(function(specs) {
var specLevel1 = specs.specLevel1
var specLevel2 = specs.specLevel2
var specLevel3 = specs.specLevel3
var specLevel4 = specs.specLevel4
specSelects[0].select2('data', specLevel1 ? {id: specLevel1.id, text: specLevel1.name, origItem: specLevel1} : null)
specSelects[1].select2('data', specLevel2 ? {id: specLevel2.id, text: specLevel2.name, origItem: specLevel2} : null)
specSelects[2].select2('data', specLevel3 ? {id: specLevel3.id, text: specLevel3.name, origItem: specLevel3} : null)
specSelects[3].select2('data', specLevel4 ? {id: specLevel4.id, text: specLevel4.name, origItem: specLevel4} : null)
$chosenSpecId.val(specId)
})
}
window.reinitSpecializationsByWorkType = reinitSpecializationsByWorkType
}())
@ -134,67 +134,77 @@ function updateSpecializationWidgets(specId, $container, $chosenSpecId, specSele
// Specialization select (simple) -------------------------------
var simpleSpecSelectsOptions = {
language: 'ru',
placeholder: 'Выберите специализацию', // Required by `allowClear`
allowClear: true,
}
var $simpleSpecContainer = $('#simpleSpecContainer')
var $emptySimpleSpecWidget = $simpleSpecContainer.find('.-simple-spec-widget').first()
$simpleSpecContainer.find('.-chosen-simple-spec-id').each(function(i, el) {
var $el = $(el)
var specId = Number($el.val())
;(function() {
var simpleSpecSelectsOptions = {
language: 'ru',
placeholder: 'Выберите специализацию', // Required by `allowClear`
allowClear: true,
//initSelection: function(element, callback) {
// var id = $(element).val()
//
// if (id !== '') {
// $.ajax({url: '/api/specializations/' + id + '/', method: 'GET', dataType: 'json'})
// .then(function(data) {callback(data)})
// }
//}
}
if (specId)
initSimpleSpecSelect2($el.closest('.-simple-spec-widget').find('.-simple-spec-select').first(), specId)
})
$('#addSpec').on('click', function($evt) {
var $newSimpleSpecWidget = $emptySimpleSpecWidget.clone()
$simpleSpecContainer.append($newSimpleSpecWidget)
var $newSimpleSpecSelect = $newSimpleSpecWidget.find('.-simple-spec-select').first()
var $simpleSpecContainer = $('#simpleSpecContainer')
var $emptySimpleSpecWidget = $simpleSpecContainer.find('.-simple-spec-widget').first()
initSimpleSpecSelect2($newSimpleSpecSelect).then(function() {
$newSimpleSpecWidget.css('display', 'block')
$simpleSpecContainer.find('.-chosen-simple-spec-id').each(function(i, el) {
var $el = $(el)
var specId = Number($el.val())
if (specId)
initSimpleSpecSelect2($el.closest('.-simple-spec-widget').find('.-simple-spec-select').first(), specId)
})
})
$simpleSpecContainer.on('change', '.-simple-spec-select', function($evt) {
if ($evt.added)
$(this).parent().children('.-chosen-simple-spec-id').first().val($evt.added.id)
})
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 {
$('#addSpec').on('click', function($evt) {
var $newSimpleSpecWidget = $emptySimpleSpecWidget.clone()
$simpleSpecContainer.append($newSimpleSpecWidget)
var $newSimpleSpecSelect = $newSimpleSpecWidget.find('.-simple-spec-select').first()
initSimpleSpecSelect2($newSimpleSpecSelect).then(function() {
$newSimpleSpecWidget.css('display', 'block')
})
})
$simpleSpecContainer.on('change', '.-simple-spec-select', function($evt) {
if ($evt.added)
$(this).parent().children('.-chosen-simple-spec-id').first().val($evt.added.id)
})
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('data', {
id: spec.id,
text: _.repeat(spec.level-1, '---') + spec.name,
origItem: spec,
}
}, specs),
}))
if (specId) {
var spec = _.find({id: specId}, specs)
$select.select2('data', {
id: spec.id,
text: _.repeat(spec.level-1, '---') + spec.name,
origItem: spec,
})
}
})
}
})
}
})
}
}())
@ -208,46 +218,49 @@ function initSimpleSpecSelect2($select, specId) {
// Team invitation contractor select -------------------------------
var contractorSelectOptions = {
language: 'ru',
placeholder: 'Выберите пользователя', // Required by `allowClear`
allowClear: true,
ajax: {
url: '/api/users/',
dataType: 'json',
quietMillis: 250,
cache: true,
data: function(term, page) {
return {
username__icontains: term,
page: page,
is_contractor: 'true',
}
},
;(function() {
var contractorSelectOptions = {
language: 'ru',
placeholder: 'Выберите пользователя', // Required by `allowClear`
allowClear: true,
results: function(data, page) {
return {
results: _.map(function(item) {
return {
id: item.id,
text: format('%s (%s)', item.username, item.get_full_name),
origItem: item,
}
}, data.results),
more: (page * API_PAGE_SIZE) < data.count,
}
ajax: {
url: '/api/users/',
dataType: 'json',
quietMillis: 250,
cache: true,
data: function(term, page) {
return {
username__icontains: term,
page: page,
is_contractor: 'true',
}
},
results: function(data, page) {
return {
results: _.map(function(item) {
return {
id: item.id,
text: format('%s (%s)', item.username, item.get_full_name),
origItem: item,
}
}, data.results),
more: (page * API_PAGE_SIZE) < data.count,
}
},
},
},
}
function initContractorSelect($select, excludeIds) {
contractorSelectOptions.ajax.url = format('%s?id__in!=%s', contractorSelectOptions.ajax.url, excludeIds.join(','))
return $select.select2(contractorSelectOptions)
}
}
function initContractorSelect($select, excludeIds) {
contractorSelectOptions.ajax.url = format('%s?id__in!=%s', contractorSelectOptions.ajax.url, excludeIds.join(','))
return $select.select2(contractorSelectOptions)
}
window.initContractorSelect = initContractorSelect
}())
@ -303,92 +316,93 @@ function initContractorSelect($select, excludeIds) {
// Location select ----------------------------------------------
var $locationSelects = $('.-location-select')
var locationSelectOptions = {
language: 'ru',
placeholder: 'Выберите местоположение', // Required by `allowClear`
allowClear: true,
}
var $countrySelect = $('.-location-select-country')
var $regionSelect = $('.-location-select-region')
var $citySelect = $('.-location-select-city')
// Initialize:
getLocationTree(null).then(function(locs) {
$countrySelect.select2(_.merge(locationSelectOptions, {data: locs.countries}))
$regionSelect.select2(_.merge(locationSelectOptions, {data: locs.regions}))
$citySelect.select2(_.merge(locationSelectOptions, {data: locs.cities}))
;(function() {
var $locationSelects = $('.-location-select')
var chosenLocId = $('#chosenLocationId').val()
var locationSelectOptions = {
language: 'ru',
placeholder: 'Выберите местоположение', // Required by `allowClear`
allowClear: true,
}
if (chosenLocId)
updateLocationWidgets(chosenLocId)
})
$locationSelects.on('change', function($evt) {
updateLocationWidgets($evt.added ? $evt.added.id : null)
})
function updateLocationWidgets(locId) {
return getLocationTree(locId).then(function(locs) {
$countrySelect.select2({data: locs.countries})
$regionSelect.select2({data: locs.regions})
$citySelect.select2({data: locs.cities})
var loc = locs.location
var $countrySelect = $('.-location-select-country')
var $regionSelect = $('.-location-select-region')
var $citySelect = $('.-location-select-city')
// Initialize:
getLocationTree(null).then(function(locs) {
$countrySelect.select2(_.merge(locationSelectOptions, {data: locs.countries}))
$regionSelect.select2(_.merge(locationSelectOptions, {data: locs.regions}))
$citySelect.select2(_.merge(locationSelectOptions, {data: locs.cities}))
if (loc && loc.level === 1) {
$countrySelect.select2('val', locs.country.id)
} else if (loc && loc.level === 2) {
$regionSelect.select2('val', locs.region.id)
$countrySelect.select2('val', locs.country.id)
} else if (loc && loc.level === 3) {
$citySelect.select2('val', locs.city.id)
$regionSelect.select2('val', locs.region.id)
$countrySelect.select2('val', locs.country.id)
}
var chosenLocId = $('#chosenLocationId').val()
if (loc)
$('#chosenLocationId').val(loc.id)
if (chosenLocId)
updateLocationWidgets(chosenLocId)
})
}
$('#realtyId').on('change', function($evt) {
var realtyId = Number($(this).val())
if (realtyId) {
loadRealtyDetails(realtyId).then(function(res) {
$('#realtyName').val(res.name)
$('#realtyBuildingClassificationId').val(res.building_classification.id).change()
$('#realtyConstructionTypeId').val(res.construction_type.id).change()
updateLocationWidgets(res.location.id)
$locationSelects.on('change', function($evt) {
updateLocationWidgets($evt.added ? $evt.added.id : null)
})
function updateLocationWidgets(locId) {
return getLocationTree(locId).then(function(locs) {
$countrySelect.select2({data: locs.countries})
$regionSelect.select2({data: locs.regions})
$citySelect.select2({data: locs.cities})
var loc = locs.location
if (loc && loc.level === 1) {
$countrySelect.select2('val', locs.country.id)
} else if (loc && loc.level === 2) {
$regionSelect.select2('val', locs.region.id)
$countrySelect.select2('val', locs.country.id)
} else if (loc && loc.level === 3) {
$citySelect.select2('val', locs.city.id)
$regionSelect.select2('val', locs.region.id)
$countrySelect.select2('val', locs.country.id)
}
if (loc)
$('#chosenLocationId').val(loc.id)
})
} else {
$('#realtyName').val('')
$('#realtyBuildingClassificationId').val('').change()
$('#realtyConstructionTypeId').val('').change()
updateLocationWidgets(null)
}
})
function loadRealtyDetails(realtyId) {
return $.ajax({
url: '/api/realties/' + realtyId + '/',
method: 'GET',
dataType: 'json',
$('#realtyId').on('change', function($evt) {
var realtyId = Number($(this).val())
if (realtyId) {
loadRealtyDetails(realtyId).then(function(res) {
$('#realtyName').val(res.name)
$('#realtyBuildingClassificationId').val(res.building_classification.id).change()
$('#realtyConstructionTypeId').val(res.construction_type.id).change()
updateLocationWidgets(res.location.id)
})
} else {
$('#realtyName').val('')
$('#realtyBuildingClassificationId').val('').change()
$('#realtyConstructionTypeId').val('').change()
updateLocationWidgets(null)
}
})
.then(function(res) {return res})
}
function loadRealtyDetails(realtyId) {
return $.ajax({
url: '/api/realties/' + realtyId + '/',
method: 'GET',
dataType: 'json',
})
.then(function(res) {return res})
}
}())
@ -404,43 +418,43 @@ function loadRealtyDetails(realtyId) {
// TODO: Add file number and overall size limit support
var $fileUploadContainer = $('#fileUploadContainer')
$('#fileUploadAddBtn').on('click', function($evt) {
$fileUploadContainer.find('.file-upload-widget').last().find('.file-upload-input').click()
})
$fileUploadContainer.on('change', '.file-upload-input', function($evt) {
var $fileInput = $(this)
var $fileUploadWidget = $fileInput.closest('.file-upload-widget')
var filePath = $fileInput.val().replace(/\\/g, '/')
var fileName = path.basename(filePath)
//var fileExt = path.extname(filePath)
var fileSize = $fileInput.get(0).files && humanFileSize($fileInput.get(0).files[0].size)
;(function() {
var $fileUploadContainer = $('#fileUploadContainer')
if (fileName) {
$fileUploadWidget.find('.file-upload-label').text(fileName + ' ' + fileSize)
var $newFileUploadWidget = $fileUploadWidget.clone()
$newFileUploadWidget.find('.file-upload-label').text('')
$fileUploadContainer.find('ul').first().append($newFileUploadWidget)
$('#fileUploadAddBtn').on('click', function($evt) {
$fileUploadContainer.find('.file-upload-widget').last().find('.file-upload-input').click()
})
$fileUploadContainer.on('change', '.file-upload-input', function($evt) {
var $fileInput = $(this)
var $fileUploadWidget = $fileInput.closest('.file-upload-widget')
var filePath = $fileInput.val().replace(/\\/g, '/')
var fileName = path.basename(filePath)
//var fileExt = path.extname(filePath)
var fileSize = $fileInput.get(0).files && humanFileSize($fileInput.get(0).files[0].size)
$fileUploadWidget.css('display', 'block')
}
})
$fileUploadContainer.on('click', '.file-upload-remove-btn', function($evt) {
var $btn = $(this)
$btn.closest('.file-upload-widget').remove()
})
$fileUploadContainer.on('click', '.existing-file-remove-btn', function($evt) {
var $btn = $(this)
$btn.closest('.existing-file-widget').remove()
})
if (fileName) {
$fileUploadWidget.find('.file-upload-label').text(fileName + ' ' + fileSize)
var $newFileUploadWidget = $fileUploadWidget.clone()
$newFileUploadWidget.find('.file-upload-label').text('')
$fileUploadContainer.find('ul').first().append($newFileUploadWidget)
$fileUploadWidget.css('display', 'block')
}
})
$fileUploadContainer.on('click', '.file-upload-remove-btn', function($evt) {
var $btn = $(this)
$btn.closest('.file-upload-widget').remove()
})
$fileUploadContainer.on('click', '.existing-file-remove-btn', function($evt) {
var $btn = $(this)
$btn.closest('.existing-file-widget').remove()
})
}())

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-09-17 18:35
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('projects', '0035_auto_20160916_2003'),
]
operations = [
migrations.AlterField(
model_name='project',
name='work_type',
field=models.IntegerField(choices=[(1, 'Проектирование'), (2, 'Проверка документации (экспертиза)'), (3, 'Устранение замечаний в проекте (корректировка проектных решений)')], default=1),
),
]

@ -73,7 +73,8 @@ class Realty(models.Model):
class Project(models.Model, HitCountMixin):
WORK_TYPES = (
(1, 'Проектирование'),
(2, 'Техническое сопровождение')
(2, 'Проверка документации'),
(3, 'Устранение замечаний в проекте'),
)
DEAL_TYPES = (

@ -59,7 +59,7 @@
</div>
<p class="type-work">Тип работы <span data-tooltip data-placement="{% tooltip_placement pk=6 %}" title="{% tooltip pk=6 %}" class="-green-glyphicon glyphicon glyphicon-question-sign"></span> <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.work_type.errors.as_text }}</span></p>
<div class="mail-block type-work-inset">
<div class="mail-block type-work-inset -project-work-type-selection-container">
{% for id, text in form.work_type.field.choices %}
<div class="inset-mb">
<label>
@ -334,7 +334,7 @@
// Scroll to first form validation error ------------------------------
// Scroll to first form validation error ---------------------------
;(function() {
@ -343,5 +343,23 @@
if (hash)
window.location.hash = hash
}())
// Load specialization choices by work type ---------------------------
;(function() {
var $radiosContainer = $('.-project-work-type-selection-container').first()
var $radios = $radiosContainer.find('input[type=radio][name={{ form.work_type.html_name }}]')
var $specSelectContainer = $('.-spec-select-container').first()
var $specSelects = $specSelectContainer.find('.-spec-select')
$radios.on('change', function($evt) {
var $that = $(this)
var workTypeId = $that.val()
reinitSpecializationsByWorkType($specSelects, workTypeId)
})
}())
</script>
{% endblock %}

@ -69,7 +69,7 @@
</div>
<p class="type-work">Тип работы <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.work_type.errors.as_text }}</span></p>
<div class="mail-block type-work-inset">
<div class="mail-block type-work-inset -project-work-type-selection-container">
{% for id, text in form.work_type.field.choices %}
<div class="inset-mb">
<label>
@ -175,7 +175,7 @@
</p>
<p class="des-afer">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Porro vel suscipit eaque quidem voluptate aperiam enim aut libero, excepturi architecto maxime, placeat maiores, odio itaque, ex consectetur dignissimos dicta officia
{% tooltip pk=10 as tooltip10 %}{{ tooltip10|linebreaksbr }}
</p>
</div>
@ -195,7 +195,7 @@
</p>
<p class="des-afer">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Porro vel suscipit eaque quidem voluptate aperiam enim aut libero, excepturi architecto maxime, placeat maiores, odio itaque, ex consectetur dignissimos dicta officia
{% tooltip pk=11 as tooltip11 %}{{ tooltip11|linebreaksbr }}
</p>
</div>
</div>
@ -318,18 +318,18 @@
;(function() {
var $workTypeSuggestionModal = $('#projectWorkTypeSuggestionModal')
var $form = $workTypeSuggestionModal.find('.-project-work-type-suggestion-form').first()
var $modal = $('#projectWorkTypeSuggestionModal')
var $form = $modal.find('.-project-work-type-suggestion-form').first()
var workTypeSuggestionUrl = '/projects/suggest-work-type/'
$workTypeSuggestionModal.find('.-action-button').first().on('click', function($evt) {
$modal.find('.-action-button').first().on('click', function($evt) {
$.post(workTypeSuggestionUrl, $form.serialize())
.then(function(res) {
if (res.status === 'success') {
console.log('Success')
$form.trigger('reset')
$('.-error').text('')
$workTypeSuggestionModal.modal('hide')
$modal.modal('hide')
$.jGrowl('Предложение успешно отправлено')
} else if (res.status === 'error') {
console.log('Error')
@ -360,5 +360,23 @@
if (hash)
window.location.hash = hash
}())
// Load specialization choices by work type ---------------------------
;(function() {
var $radiosContainer = $('.-project-work-type-selection-container').first()
var $radios = $radiosContainer.find('input[type=radio][name={{ form.work_type.html_name }}]')
var $specSelectContainer = $('.-spec-select-container').first()
var $specSelects = $specSelectContainer.find('.-spec-select')
$radios.on('change', function($evt) {
var $that = $(this)
var workTypeId = $that.val()
reinitSpecializationsByWorkType($specSelects, workTypeId)
})
}())
</script>
{% endblock %}

Loading…
Cancel
Save