|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
@ -0,0 +1,79 @@ |
||||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {}; |
||||
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) { |
||||
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) |
||||
/******/ return installedModules[moduleId].exports; |
||||
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = { |
||||
/******/ exports: {}, |
||||
/******/ id: moduleId, |
||||
/******/ loaded: false |
||||
/******/ }; |
||||
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); |
||||
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.loaded = true; |
||||
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports; |
||||
/******/ } |
||||
|
||||
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules; |
||||
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules; |
||||
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = ""; |
||||
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(0); |
||||
/******/ }) |
||||
/************************************************************************/ |
||||
/******/ ({ |
||||
|
||||
/***/ 0: |
||||
/***/ function(module, exports, __webpack_require__) { |
||||
|
||||
'use strict'; |
||||
|
||||
var _utils_debug = __webpack_require__(44); |
||||
|
||||
// DEBUG
|
||||
window.print = {}; |
||||
window.print.ws_print = _utils_debug.ws_print; |
||||
|
||||
/***/ }, |
||||
|
||||
/***/ 44: |
||||
/***/ function(module, exports) { |
||||
|
||||
'use strict'; |
||||
|
||||
Object.defineProperty(exports, "__esModule", { |
||||
value: true |
||||
}); |
||||
function ws_print() { |
||||
for (var _len = arguments.length, messages = Array(_len), _key = 0; _key < _len; _key++) { |
||||
messages[_key] = arguments[_key]; |
||||
} |
||||
|
||||
var message = messages.join(' '); |
||||
console.log('%c WS: ' + message, 'background: white; color: blue'); |
||||
} |
||||
|
||||
exports.ws_print = ws_print; |
||||
|
||||
/***/ } |
||||
|
||||
/******/ }); |
||||
@ -0,0 +1,445 @@ |
||||
import {getCookie} from '../utils' |
||||
import {onClickCardWithCount} from './messageCounters' |
||||
import {loadTemplate} from './loaders' |
||||
|
||||
function dialog(message, yesCallback, notCallback) { |
||||
$("#dialog_delete .modal-title").html(message); |
||||
$("#dialog_delete").modal('show'); |
||||
$("#btnYes").click(function (e) { |
||||
e.preventDefault(); |
||||
yesCallback(); |
||||
$("#dialog_delete").modal('hide'); |
||||
}); |
||||
$("#btnNot").click(function (e) { |
||||
e.preventDefault(); |
||||
notCallback(); |
||||
$("#dialog_delete").modal('hide'); |
||||
}); |
||||
} |
||||
|
||||
function bindOrders() { |
||||
$('.order-block').on('click', function (event) { |
||||
event.preventDefault(); |
||||
let $this = $(this); |
||||
onClickCardWithCount($this); |
||||
$('.order-block').each(function (i, v) { |
||||
$(v).removeClass('orAct'); |
||||
}); |
||||
$this.addClass('orAct'); |
||||
let orderId = $this.data('id'); |
||||
let projectId = $this.data('project-id'); |
||||
let recipentId = $this.data('recipent-id'); |
||||
let orderName = $this.data('order-name'); |
||||
var secureOrder = $(this).data('secure-deal'); |
||||
secureOrder = Boolean(secureOrder); |
||||
window.location.hash = `order${orderId}`; |
||||
|
||||
$("#chat-order-add #orderId").val(orderId); |
||||
$("#add-form-order-note #orderNote").val(orderId); |
||||
$("#orderArbitrationId").val(orderId); |
||||
$("#projectReviewId").val(projectId); |
||||
$("#reserve-button").attr('data-order-id', orderId); |
||||
|
||||
$("#chat-order-add #recipentId").val(recipentId); |
||||
window.chatController.create(orderId, projectId, recipentId, orderName, secureOrder); |
||||
}); |
||||
$('.order-block .dimovChat').on('click', function (event) { |
||||
event.preventDefault(); |
||||
event.stopPropagation(); |
||||
// console.log('click on tr');
|
||||
}); |
||||
} |
||||
|
||||
function bindTeams() { |
||||
$('.team-block').on('click', function () { |
||||
onClickCardWithCount($(this)); |
||||
$('.team-order-block, .team-block').each(function () { |
||||
$(this).removeClass('orAct'); |
||||
}); |
||||
$(this).addClass('orAct'); |
||||
|
||||
var teamIds = ''; |
||||
$.each($(this).find('.team-chat-user'), function (i, v) { |
||||
teamIds += $(this).attr('data-id') + ";"; |
||||
}); |
||||
$("#team-chat-form #teamIds").val(teamIds); |
||||
|
||||
var inbox = document.getElementById('message-chat-team-space'); |
||||
inbox.innerHTML = ''; |
||||
|
||||
var docList = document.getElementById('documentTeamSpace'); |
||||
docList.innerHTML = ''; |
||||
|
||||
var teamId = $(this).attr('data-team-id'); |
||||
location.hash = '#myteam' + teamId; |
||||
|
||||
// var newCount = parseInt($("#count-tab-team").text());
|
||||
// var currNewCount = parseInt($(".team-count-" + teamId).text());
|
||||
// var resCount = newCount - currNewCount;
|
||||
// $("#count-tab-team").text(resCount);
|
||||
$(".team-count-" + teamId).text(0) |
||||
|
||||
$("#team-chat-form #teamId").val(teamId); |
||||
$("#add-form-team-note #teamNote").val(teamId); |
||||
$("#team-chat-form #recipentTeamId").val(""); |
||||
$("#team-chat-form #orderTeamId").val(""); |
||||
$("#add-form-team-note #orderNote").val(""); |
||||
|
||||
$.ajax({ |
||||
url: '/api/message', |
||||
type: 'GET', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: {'team': teamId, 'order__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 += '<div class="col-lg-12 insetCommChat ' + className + '"><div class="topCommChat">' + |
||||
'<p class="nameCommChat">' + senderName + '</p> <span>' + v.created + '</span></div>' + |
||||
'<p class="textCommChat">' + v.text + '</p></div>'; |
||||
}); |
||||
var height = inbox.scrollHeight; |
||||
inbox.scrollTop = height; |
||||
} |
||||
}); |
||||
|
||||
$.ajax({ |
||||
url: '/api/documents', |
||||
type: 'GET', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: { |
||||
'team': teamId, |
||||
'is_delete': false, |
||||
'is_send': true, |
||||
}, |
||||
dataType: 'json', |
||||
success: function (json) { |
||||
$.each(json.results, function (i, v) { |
||||
docList.innerHTML += '<li style="word-break: break-all;"><a class="file-link" href="/chat/download/' + v.file + '">' + v.file + '</a><div class="remove-document" data-id="' + v.id + '" style="right:-10px;"></div></li>'; |
||||
}); |
||||
}, |
||||
error: function (e) { |
||||
console.log(e); |
||||
} |
||||
}); |
||||
|
||||
$.ajax({ |
||||
url: '/api/note/', |
||||
type: 'GET', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: {'team': teamId}, |
||||
dataType: 'json', |
||||
success: function (json) { |
||||
// console.log(json.results);
|
||||
var noteHtmlInbox = ''; |
||||
var note_tmpl = loadTemplate('note_tmpl'); |
||||
$.each(json.results, function (i, v) { |
||||
noteHtmlInbox += note_tmpl({text: v.text}); |
||||
|
||||
}); |
||||
$(".team-notes-block").html(noteHtmlInbox); |
||||
} |
||||
}); |
||||
|
||||
}); |
||||
} |
||||
|
||||
function bindArbitrationSend() { |
||||
// TODO: Test it
|
||||
$('#order-arbitration-add').on('click', function (e) { |
||||
e.preventDefault(); |
||||
e.stopPropagation(); |
||||
var formData = $("#arbitration-add-form").serialize(); |
||||
$.ajax({ |
||||
url: '/projects/arbitration/create/', |
||||
type: 'POST', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: formData, |
||||
dataType: 'json', |
||||
success: function (json) { |
||||
// console.log(json);
|
||||
$("#arbitration-add").modal('hide'); |
||||
$.jGrowl("Обращение в арбитраж добавлено", { |
||||
life: 4000 |
||||
}); |
||||
}, |
||||
error: function (e) { |
||||
console.log('error'); |
||||
console.log(e); |
||||
} |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
function bindOnTabs() { |
||||
/** |
||||
* Биндит обработчики на Закладки |
||||
*/ |
||||
$('a[data-toggle="tab"]').unbind().on('show.bs.tab', function (e) { |
||||
// console.log("TAB!");
|
||||
var activeTab = $(this).attr('href').substring(1); |
||||
var liveHash = URI(location.href).hash(); |
||||
|
||||
switch (activeTab) { |
||||
case 'tab1': |
||||
setTimeout(function () { |
||||
if (liveHash.indexOf("#user") != -1) { |
||||
var userHashId = liveHash.replace("#user", ""); |
||||
$("#userBlock" + userHashId).trigger('click'); |
||||
} else { |
||||
$(".user-block").first().trigger('click'); |
||||
} |
||||
}, 100); |
||||
break; |
||||
|
||||
case 'tab2': |
||||
// console.log("tab2");
|
||||
setTimeout(function () { |
||||
if (liveHash.indexOf("#order") != -1) { |
||||
var ordHashId = liveHash.replace("#order", ""); |
||||
$("#orderBlock" + ordHashId).trigger('click'); |
||||
} else { |
||||
$(".order-block").first().trigger('click'); |
||||
} |
||||
}, 100); |
||||
break; |
||||
|
||||
case 'tab3': |
||||
setTimeout(function () { |
||||
// console.log("on active TAB team");
|
||||
if (liveHash.indexOf("#teamorder") != -1) { |
||||
var teamHashId = liveHash.replace("#teamorder", ""); |
||||
$("#teamOrderBlock" + teamHashId).trigger('click'); |
||||
} else if (liveHash.indexOf("#myteam") != -1) { |
||||
var teamHashId = liveHash.replace("#myteam", ""); |
||||
$("#teamMyBlock" + teamHashId).trigger('click'); |
||||
} else { |
||||
var firstTeamBlock = $(".team-block").first(); |
||||
var firstTeamOrder = $(".team-order-block").first(); |
||||
if (firstTeamOrder.length == 1) { |
||||
firstTeamOrder.trigger('click'); |
||||
} else if (firstTeamBlock.length == 1) { |
||||
firstTeamBlock.trigger('click'); |
||||
} |
||||
} |
||||
}, 100); |
||||
|
||||
} |
||||
|
||||
}); |
||||
} |
||||
|
||||
function bindUserContacts() { |
||||
$(".conMess").click('on', function (e) { |
||||
e.preventDefault(); |
||||
e.stopPropagation(); |
||||
|
||||
var userId = $(this).attr('data-id'); |
||||
$.ajax({ |
||||
url: '/api/users/' + userId + '/', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
dataType: 'json', |
||||
success: function (data) { |
||||
var outTable = ''; |
||||
if (data.username) { |
||||
outTable += '<tr><td>Ник</td><td>' + data.username + '</td>'; |
||||
} |
||||
|
||||
if (data.fio) { |
||||
outTable += '<tr><td>Ф.И.О</td><td>' + data.fio + '</td>'; |
||||
} |
||||
if (data.skype) { |
||||
outTable += '<tr><td>Skype</td><td>' + data.skype + '</td>'; |
||||
} |
||||
|
||||
if (data.website) { |
||||
outTable += '<tr><td>Сайт</td><td>' + data.website + '</td>'; |
||||
} |
||||
|
||||
if (data.phone) { |
||||
outTable += '<tr><td>Телефон</td><td>' + data.phone + '</td>'; |
||||
} |
||||
|
||||
$("#contact-info table").html(outTable); |
||||
$("#contact-info").modal('show'); |
||||
// console.log(data);
|
||||
}, |
||||
error: function (e, jqxhr) { |
||||
console.log(e); |
||||
} |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
function bindGetUserMessages() { |
||||
$('.user-block').on('click', function () { |
||||
onClickCardWithCount($(this)); |
||||
// var newCount = parseInt($("#count-tab-contact").text());
|
||||
var contactId = $(this).attr('data-id'); |
||||
location.hash = '#user' + contactId; |
||||
$("#contact-chat-form #recipentContactId").val(contactId); |
||||
$("#add-form-contractor-note #recipentNoteContractor").val(contactId); |
||||
|
||||
$('.user-block').each(function () { |
||||
$(this).removeClass('mesAct'); |
||||
}); |
||||
|
||||
$(this).addClass('mesAct'); |
||||
var inbox = document.getElementById('message-chat-space'); |
||||
var sumSenderRecipent = parseInt(userId) + parseInt(contactId); |
||||
|
||||
$("#message-chat-space").removeClass().addClass("contact-space" + sumSenderRecipent); |
||||
// var currNewCount = parseInt($(".contact-count-" + sumSenderRecipent).text());
|
||||
// var resCount = newCount - currNewCount;
|
||||
// $("#count-tab-contact").text(resCount);
|
||||
$(".contact-count-" + sumSenderRecipent).text(0); |
||||
var docList = document.getElementById('documentSpace'); |
||||
inbox.innerHTML = ''; |
||||
docList.innerHTML = ''; |
||||
|
||||
$.ajax({ |
||||
url: '/api/message', |
||||
type: 'GET', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: { |
||||
'operand': 'in', |
||||
'sender_id': userId, |
||||
'recipent_id': contactId |
||||
}, |
||||
dataType: 'json', |
||||
success: function (json) { |
||||
$.each(json.results, function (i, v) { |
||||
var senderName = 'Вы'; |
||||
var className = 'youChat'; |
||||
if (v.sender.id == contactId) { |
||||
senderName = v.sender.username; |
||||
className = ''; |
||||
} |
||||
inbox.innerHTML += '<div class="col-lg-12 insetCommChat ' + className + '"><div class="topCommChat">' + |
||||
'<p class="nameCommChat">' + senderName + '</p> <span>' + v.created + '</span></div>' + |
||||
'<p class="textCommChat">' + v.text + '</p></div>'; |
||||
}); |
||||
var height = inbox.scrollHeight; |
||||
inbox.scrollTop = height; |
||||
} |
||||
}); |
||||
|
||||
$.ajax({ |
||||
url: '/api/documents', |
||||
type: 'GET', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: { |
||||
'operand': 'in', |
||||
'sender_id': userId, |
||||
'recipent_id': contactId, |
||||
'is_delete': false, |
||||
'is_send': true, |
||||
}, |
||||
dataType: 'json', |
||||
|
||||
success: function (json) { |
||||
// console.log(json);
|
||||
|
||||
$.each(json.results, function (i, v) { |
||||
docList.innerHTML += '<li style="word-break: break-all;"><a class="file-link" href="/chat/download/' + v.file + '">' + v.file + '</a><div class="remove-document" data-id="' + v.id + '" style="right:-10px;"></div></li>'; |
||||
}); |
||||
}, |
||||
error: function (e) { |
||||
console.log(e); |
||||
} |
||||
}); |
||||
|
||||
$.ajax({ |
||||
url: '/api/note/', |
||||
type: 'GET', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: { |
||||
'operand': 'in', |
||||
'sender_id': userId, |
||||
'recipent_id': contactId |
||||
}, |
||||
dataType: 'json', |
||||
success: function (json) { |
||||
// console.log(json.results);
|
||||
var noteHtmlInbox = ''; |
||||
var note_tmpl = loadTemplate('note_tmpl'); |
||||
$.each(json.results, function (i, v) { |
||||
noteHtmlInbox += note_tmpl({text: v.text}); |
||||
}); |
||||
$(".contractor-notes-block").html(noteHtmlInbox); |
||||
} |
||||
}); |
||||
|
||||
}); |
||||
} |
||||
|
||||
function bindDeleteContact() { |
||||
$('.deleteMess').on('click', function (e) { |
||||
e.preventDefault(); |
||||
e.stopPropagation(); |
||||
|
||||
var senderId = userId; |
||||
var recipentId = $(this).attr('data-recipent-id'); |
||||
var _this = $(this); |
||||
|
||||
dialog("Вы действительно хотите удалить сообщения этого пользователя?", |
||||
function () { |
||||
$.ajax({ |
||||
url: '/chat/messages_delete/', |
||||
type: 'POST', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: {'sender_id': senderId, 'recipent_id': recipentId}, |
||||
dataType: 'json', |
||||
success: function (json) { |
||||
|
||||
if (json.status == 'ok') { |
||||
_this.parent().remove(); |
||||
$("#message-chat-space").html(""); |
||||
} |
||||
|
||||
}, |
||||
error: function (e) { |
||||
console.log('error'); |
||||
console.log(e); |
||||
} |
||||
}); |
||||
}.bind(null, senderId, recipentId, _this), |
||||
function () { |
||||
}); |
||||
|
||||
|
||||
}); |
||||
} |
||||
|
||||
export { |
||||
bindOrders, |
||||
bindArbitrationSend, |
||||
bindOnTabs, |
||||
bindUserContacts, |
||||
bindGetUserMessages, |
||||
bindTeams, |
||||
bindDeleteContact, |
||||
} |
||||
@ -0,0 +1 @@ |
||||
import {StagesController} from './StagesContractorController'
import {MessagesController} from './MessagesControllers'
import {DocumentsController} from './DocumentsControllers'
class ChatPageController {
constructor() {
let self = this;
console.log("NEW CONTRACTOR ChatPageController");
this.statesController = undefined;
this.messagesController = undefined;
this.documentsController = undefined;
// TODO: не забыть!
// $('.order-block').on('click', function (event) {
// console.log("CLICK!!!");
// event.preventDefault();
// let $this = $(this);
// $('.order-block').each(function (i, v) {
// $(v).removeClass('orAct');
// });
// $this.addClass('orAct');
// let orderId = $this.data('id');
// let projectId = $this.data('project-id');
// let recipentId = $this.data('recipent-id');
// let orderName = $this.data('order-name');
// // console.log('orderId = ', orderId);
// new StagesController(orderId, projectId, recipentId, orderName);
// new MessagesController(orderId);
// window.location.hash = `order${orderId}`;
//
// $("#chat-order-add #orderId").val(orderId);
// $("#add-form-order-note #orderNote").val(orderId);
// $("#orderArbitrationId").val(orderId);
// $("#projectReviewId").val(projectId);
// // console.log("recipentId = ", recipentId);
// $("#chat-order-add #recipentId").val(recipentId);
// $("#targetCustomerId").val(recipentId);
// $("#add-form-order-note #recipentNote").val(recipentId);
//
// });
// $('.order-block .dimovChat').on('click', function (event) {
// event.preventDefault();
// event.stopPropagation();
// // TODO: доделать сворачивание/разворачивание блока
// // console.log('click on tr');
// });
}
create(orderId, projectId, recipentId, orderName, secureOrder) {
this.statesController = new StagesController(orderId, projectId, recipentId, orderName, secureOrder);
this.messagesController = new MessagesController(orderId);
this.documentsController = new DocumentsController(orderId);
}
// refresh()
}
export {ChatPageController} |
||||
@ -0,0 +1 @@ |
||||
import {StagesController} from './StagesCustomerController'
import {MessagesController} from './MessagesControllers'
import {recalculateMessages} from './messageCounters'
class ChatPageController {
constructor() {
let self = this;
// console.log("NEW Chat CUSTOMER PageController");
this.statesController = undefined;
this.messagesController = undefined;
// TODO: не забыть!
// recalculateMessages();
}
create(orderId, projectId, recipentId, orderName, secureOrder) {
this.statesController = new StagesController(orderId, projectId, recipentId, orderName, secureOrder);
this.messagesController = new MessagesController(orderId);
}
}
export {ChatPageController} |
||||
@ -0,0 +1,67 @@ |
||||
import {getCookie} from '../utils' |
||||
import {loadTemplate} from './loaders' |
||||
|
||||
class DocumentsController { |
||||
constructor(orderId) { |
||||
console.log('Create MessagesController'); |
||||
const self = this; |
||||
this.orderId = orderId; |
||||
this.$container = $('#documentOrderSpace'); |
||||
this.$container.html(""); |
||||
|
||||
this.messageTemplate = loadTemplate('document_attach_file_tmpl'); |
||||
this.dataPromise = this.getMessagesData(); |
||||
this.dataPromise.then( |
||||
self._onLoadData.bind(self) |
||||
) |
||||
} |
||||
|
||||
getMessagesData() { |
||||
const self = this; |
||||
return Promise.resolve( |
||||
$.ajax({ |
||||
url: '/api/documents', |
||||
type: 'GET', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: { |
||||
'order': self.orderId, |
||||
'is_delete': false, |
||||
'is_send': true, |
||||
}, |
||||
dataType: 'json', |
||||
// success: function (json) {
|
||||
//
|
||||
// },
|
||||
error: function (e) { |
||||
console.log(e); |
||||
} |
||||
})); |
||||
} |
||||
|
||||
addDocument(json) { |
||||
|
||||
} |
||||
|
||||
_onLoadData(json) { |
||||
const self = this; |
||||
// console.log('mesages json = ', json);
|
||||
// console.log('$inbox = ', this.$inbox);
|
||||
// console.log("messages render start");
|
||||
this.$container.html(""); |
||||
$.each(json.results, function (i, v) { |
||||
let document = $(self.messageTemplate( |
||||
{ |
||||
href: `/chat/download/' + ${v.file}`, |
||||
text: v.file, |
||||
document_id: v.id |
||||
})); |
||||
self.$container.append(document); |
||||
}); |
||||
// console.log("messages render complete");
|
||||
// self.$inbox.scrollTop(self.$inbox.prop("scrollHeight"));
|
||||
} |
||||
} |
||||
|
||||
export {DocumentsController} |
||||
@ -0,0 +1,61 @@ |
||||
import {getCookie} from '../utils' |
||||
import {loadTemplate} from './loaders' |
||||
|
||||
class MessagesController { |
||||
constructor(orderId) { |
||||
console.log('Create MessagesController'); |
||||
const self = this; |
||||
this.orderId = orderId; |
||||
this.$inbox = $('#message-chat-order-space'); |
||||
this.$inbox.html(""); |
||||
this.messageTemplate = loadTemplate('message_tmpl'); |
||||
this.dataPromise = this.getMessagesData(); |
||||
this.dataPromise.then( |
||||
self._onLoadData.bind(self) |
||||
) |
||||
} |
||||
|
||||
getMessagesData() { |
||||
const self = this; |
||||
return Promise.resolve($.ajax({ |
||||
url: '/api/message', |
||||
type: 'GET', |
||||
data: {'order': self.orderId, 'team__isnull': 'true'}, |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
dataType: 'json', |
||||
success: function (json) { |
||||
console.log('Success Messages') |
||||
} |
||||
})); |
||||
} |
||||
|
||||
_onLoadData(json) { |
||||
const self = this; |
||||
// console.log('mesages json = ', json);
|
||||
// console.log('$inbox = ', this.$inbox);
|
||||
// console.log("messages render start");
|
||||
self.$inbox.html(""); |
||||
$.each(json.results, function (i, v) { |
||||
var senderName = 'Вы'; |
||||
var className = 'youChat'; |
||||
|
||||
if (v.sender.id !== userId) { |
||||
senderName = v.sender.username; |
||||
className = ''; |
||||
} |
||||
if (v.is_system) { |
||||
senderName = 'Системное'; |
||||
className = 'systemChat' |
||||
} |
||||
let message = $(self.messageTemplate({className: className, senderName: senderName, message: v})); |
||||
self.$inbox.append(message); |
||||
|
||||
}); |
||||
// console.log("messages render complete");
|
||||
self.$inbox.scrollTop(self.$inbox.prop("scrollHeight")); |
||||
} |
||||
} |
||||
|
||||
export {MessagesController} |
||||
@ -0,0 +1,340 @@ |
||||
import {loadTemplate} from './loaders' |
||||
// new-stages-form
|
||||
// update-stages-form
|
||||
// remove-stages-form
|
||||
|
||||
class StageForm { |
||||
constructor($container, {orderId, stage_num, stage_status, type = 'new', formNamePostfix = '-stages-form', template_name, data = {}}, |
||||
kwargs = { |
||||
stage_num: stage_num, |
||||
stage_status: stage_status, |
||||
form_name: (type + formNamePostfix), |
||||
orderId: orderId, |
||||
stage: data |
||||
},) |
||||
// kwargs - auto generate from name_attributes
|
||||
{ |
||||
// console.log('Stage form template_name = ', template_name);
|
||||
this.orderId = orderId; |
||||
this._type = type; |
||||
this.$container = $container; |
||||
this.self_tmpl = loadTemplate(template_name); |
||||
this.data = data; |
||||
this.$form = undefined; |
||||
this.stageId = (type != 'new') ? data.id : undefined; |
||||
this.create(kwargs); |
||||
} |
||||
|
||||
create(kwargs) { |
||||
/** |
||||
* Добавление шаблона-формы Этапа на страницу |
||||
*/ |
||||
let el = $(this.self_tmpl(kwargs)); |
||||
this.$container.append(el); |
||||
this.$form = el.find('form'); |
||||
// console.log("form --> ", this.$form);
|
||||
if (this.$form.length) this.$form.find('input[name=cost]').mask('000000000'); |
||||
} |
||||
|
||||
remove() { |
||||
/** |
||||
* Удаление, при уменьшении кол-ва этапов |
||||
* return true - удаляем из [] stages |
||||
*/ |
||||
if (this.type == 'new') { |
||||
this.$form.parent().remove(); |
||||
return true; |
||||
} |
||||
this.type = 'remove'; |
||||
// this.$form.removeClass('update-stages-form').addClass('remove-stages-form');
|
||||
return false |
||||
} |
||||
|
||||
restore() { |
||||
/** |
||||
* Восстановление, при увеличении кол-ва этапов |
||||
*/ |
||||
if (this.type == 'new') throw new Error("Попытка восстановить элемент с type='new'"); |
||||
this.type = 'update'; |
||||
// this.$form.removeClass('remove-stages-form').addClass('update-stages-form');
|
||||
} |
||||
|
||||
set type(newType) { |
||||
this.$form.removeClass(`${this._type}-stages-form`).addClass(`${newType}-stages-form`); |
||||
if (newType == 'remove') this.hide(); |
||||
if (newType == 'update') this.show(); |
||||
this._type = newType |
||||
} |
||||
|
||||
get type() { |
||||
return this._type |
||||
} |
||||
|
||||
disable() { |
||||
this.$form.find('input').attr('readonly', true); |
||||
} |
||||
|
||||
enable() { |
||||
this.$form.find('input').attr('readonly', false); |
||||
} |
||||
|
||||
hide() { |
||||
this.$form.parent().hide(); |
||||
} |
||||
|
||||
show() { |
||||
this.$form.parent().show() |
||||
} |
||||
|
||||
is_valid() { |
||||
let self = this; |
||||
let mesage = 'Это поле обязательно'; |
||||
let valid = true; |
||||
//Очищаем старые ошибки
|
||||
this.$form.find('.error').html(""); |
||||
// Отображаем новые
|
||||
this.$form.find(":input:not([type=hidden])").each(function (i, v) { |
||||
if (!$(v).val()) { |
||||
self.$form.find(`.error-${$(v).attr("name")}`).html(mesage).css('color', 'red'); |
||||
valid = false |
||||
} |
||||
}); |
||||
return valid |
||||
} |
||||
|
||||
sendAjax_approve() { |
||||
/** |
||||
* Отправка Этапа "на согласование" |
||||
*/ |
||||
let self = this; |
||||
// console.log("Send AJAX Approve");
|
||||
if (this.type == 'new') { |
||||
// console.log('new stages approve');
|
||||
return Promise.resolve($.ajax({ |
||||
// async: false,
|
||||
url: '/api/stages/', |
||||
type: 'POST', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: this.$form.serialize(), |
||||
dataType: 'json', |
||||
}) |
||||
.done(function (json) { |
||||
self.type = 'update'; |
||||
self.disable(); |
||||
self.$form.find('.error').html(""); |
||||
// console.log("json -->", json);
|
||||
self.stageId = json.id; |
||||
// console.log(json);
|
||||
}) |
||||
.fail(function (xhr, errorMsg, error) { |
||||
console.log("ERROR, xhr", xhr); |
||||
$.each(xhr.responseJSON, function (i, v) { |
||||
self.$form.find('.error-' + i).html(v).css('color', 'red'); |
||||
// console.log(self.$form);
|
||||
// console.log(v);
|
||||
// console.log(i);
|
||||
}); |
||||
})); |
||||
} else if (this.type == 'update') { |
||||
this.$form.find('input[name=status]').val('send_approve'); |
||||
return Promise.resolve($.ajax({ |
||||
url: `/api/stages/${this.stageId}/`, |
||||
type: 'PUT', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: this.$form.serialize(), |
||||
dataType: 'json', |
||||
}) |
||||
.done(function (json) { |
||||
self.$form.find('.error').html(""); |
||||
self.disable(); |
||||
}) |
||||
.fail(function (xhr, errorMsg, error) { |
||||
$.each(xhr.responseJSON, function (i, v) { |
||||
self.$form.find('.error-' + i).html(v).css('color', 'red'); |
||||
console.log(v); |
||||
console.log(i); |
||||
}); |
||||
})); |
||||
} else if (this.type == 'remove') { |
||||
return Promise.resolve($.ajax({ |
||||
url: `/api/stages/${this.stageId}/`, |
||||
type: 'DELETE', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
dataType: 'json', |
||||
}) |
||||
.done(function (json) { |
||||
}) |
||||
.fail(function (xhr, errorMsg, error) { |
||||
console.log("delete fail, json -->", xhr); |
||||
})); |
||||
} |
||||
} |
||||
|
||||
sendAjax_accept(secureOrder) { |
||||
/** |
||||
* "Согласовать" Этапы (Исполнителем) |
||||
*/ |
||||
// console.log("secureOrder = ", secureOrder);
|
||||
// console.log("set new status =", secureOrder ? 'agreed': 'in_process');
|
||||
return Promise.resolve($.ajax({ |
||||
url: '/api/stages/' + this.stageId + '/', |
||||
type: 'PATCH', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
//TODO: слать только изменения
|
||||
data: { |
||||
status: secureOrder ? 'agreed': 'in_process', |
||||
}, |
||||
dataType: 'json', |
||||
})) |
||||
} |
||||
|
||||
sendAjax_change() { |
||||
/** |
||||
* Отправка Этапа "Внести изменения" |
||||
*/ |
||||
let self = this; |
||||
// this.$form.find('input[name=status]').val('not_agreed');
|
||||
// console.log("ajax Change form -->", this.$form);
|
||||
return Promise.resolve($.ajax({ |
||||
url: '/api/stages/' + this.stageId + '/', |
||||
type: 'PATCH', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
//TODO: слать только изменения
|
||||
data: {status: 'not_agreed'}, |
||||
dataType: 'json', |
||||
}) |
||||
.done(function (json) { |
||||
// enableStageFields(json.id);
|
||||
// $form.find('.error').html("");
|
||||
self.enable(); |
||||
}) |
||||
.fail(function (xhr) { |
||||
console.log("Ошибка, которой не должно быть json -->", xhr.responseJSON); |
||||
})); |
||||
} |
||||
|
||||
} |
||||
|
||||
class StageReserved { |
||||
constructor($container, {template_name = 'reserved_tmpl', data}, |
||||
kwargs = { |
||||
reserved_cls: '', |
||||
reserved_name: '', |
||||
stage: data |
||||
},) { |
||||
// Вывод текста резервирования в зависимости от статуса этапа
|
||||
let reserved_names = { |
||||
agreed: 'Не зарезервирована', |
||||
in_process: 'Зарезервирована', |
||||
completed: 'Зарезервирована', |
||||
closed: 'Переведена исполнителю', |
||||
}; |
||||
// Вывод текста резервирования в зависимости от статуса этапа
|
||||
let reserved_classes = { |
||||
agreed: 'unreserved', |
||||
in_process: 'reserved', |
||||
completed: 'reserved', |
||||
closed: 'closed', |
||||
}; |
||||
kwargs.reserved_cls = reserved_classes[data.status]; |
||||
kwargs.reserved_name = reserved_names[data.status]; |
||||
this.data = data; |
||||
this.self_tmpl = loadTemplate(template_name); |
||||
this.$container = $container; |
||||
this.create(kwargs); |
||||
} |
||||
|
||||
create(kwargs) { |
||||
/** |
||||
* Добавление шаблона "Резервирование" Этапа на страницу |
||||
*/ |
||||
this.$self = $(this.self_tmpl(kwargs)); |
||||
this.$container.append(this.$self); |
||||
// console.log("form --> ", this.$form);
|
||||
// this.$form.find('input[name=cost]').mask('000000000');
|
||||
} |
||||
} |
||||
|
||||
class StageInWork { |
||||
constructor($container, {template_name = 'work_in_process_tmpl', note_text = '', data}, |
||||
kwargs = {stage: data, note_text: note_text}) { |
||||
this.stageId = data.id; |
||||
this.data = data; |
||||
this.self_tmpl = loadTemplate(template_name); |
||||
this.$container = $container; |
||||
this.create(kwargs); |
||||
} |
||||
|
||||
create(kwargs) { |
||||
/** |
||||
* Добавление шаблона "Выполнение работы" Этапа на страницу |
||||
*/ |
||||
this.$self = $(this.self_tmpl(kwargs)); |
||||
this.$container.append(this.$self); |
||||
} |
||||
|
||||
hide() { |
||||
this.$self.hide(); |
||||
} |
||||
|
||||
sendAjax_complete() { |
||||
/** |
||||
* Отправка Этапа "Закрыть этап" |
||||
*/ |
||||
let self = this; |
||||
return Promise.resolve($.ajax({ |
||||
url: `/api/stages/${this.stageId}/`, |
||||
type: 'PATCH', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: {status: 'completed'}, |
||||
dataType: 'json', |
||||
}) |
||||
.done(function (json) { |
||||
// enableStageFields(json.id);
|
||||
// $form.find('.error').html("");
|
||||
// self.enable();
|
||||
}) |
||||
.fail(function (xhr) { |
||||
console.log("Ошибка, которой не должно быть json -->", xhr.responseJSON); |
||||
})); |
||||
} |
||||
|
||||
sendAjax_close() { |
||||
/** |
||||
* Отправка Этапа "Закрыть этап" |
||||
*/ |
||||
let self = this; |
||||
return Promise.resolve($.ajax({ |
||||
url: `/api/stages/${this.stageId}/`, |
||||
type: 'PATCH', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
//TODO: слать только изменения
|
||||
data: {status: 'closed'}, |
||||
dataType: 'json', |
||||
}) |
||||
.done(function (json) { |
||||
// enableStageFields(json.id);
|
||||
// $form.find('.error').html("");
|
||||
// self.enable();
|
||||
}) |
||||
.fail(function (xhr) { |
||||
console.log("Ошибка, которой не должно быть json -->", xhr.responseJSON); |
||||
})); |
||||
} |
||||
} |
||||
|
||||
export {StageForm, StageReserved, StageInWork} |
||||
@ -0,0 +1,446 @@ |
||||
import {getCookie} from '../utils' |
||||
import {loadTemplate} from './loaders' |
||||
import {StageForm, StageReserved, StageInWork} from './Stages' |
||||
|
||||
let message_format = { |
||||
"format_type": "approve_stages", |
||||
"data": { |
||||
"sender_id": "", |
||||
"recipent_id": "", |
||||
"order_id": "", |
||||
"msg": "", |
||||
"is_system": true |
||||
} |
||||
}; |
||||
|
||||
const STATUSES = { |
||||
'not_agreed': 'не согласован', |
||||
'send_approve': 'на согласовании', |
||||
'agreed': 'согласовано', |
||||
'cancel_approve': 'исполнитель отказался', |
||||
'in_process': 'в процессе', |
||||
'completed': 'завершен', |
||||
'closed': 'закрыт', |
||||
|
||||
}; |
||||
|
||||
//Contractor
|
||||
class StagesController { |
||||
constructor(orderId, projectId, recipentId, orderName, secureOrder) { |
||||
const self = this; |
||||
this.orderId = orderId; |
||||
this.projectId = projectId; |
||||
this.recipentId = recipentId; |
||||
this.orderName = orderName; |
||||
this.secureOrder = secureOrder; |
||||
// console.log("ids -->", orderId, projectId, recipentId);
|
||||
this.data = {}; //JSON
|
||||
this.stages = []; |
||||
this.stages_reserved = []; |
||||
this.stages_work = []; |
||||
this.STAGE_STATUSES = { |
||||
'not_agreed': this.buildStartStage.bind(self), |
||||
'send_approve': this.buildSendApproveStage.bind(self), |
||||
'agreed': this.buildAgreedStage.bind(self), |
||||
'in_process': this.buildProcessStage.bind(self), |
||||
'completed': this.buildProcessStage.bind(self), |
||||
'closed': this.buildProcessStage.bind(self), |
||||
}; |
||||
this.btnCompleteTmpl = loadTemplate('bntCompleteStage_tmpl'); |
||||
this.btnSendReviewTmpl = loadTemplate('btnSendReview_tmpl'); |
||||
this.$orderStagesContainer = $('#order-stages'); |
||||
this.$orderStagesContainer.html(''); |
||||
this.buttons = { |
||||
btnApprove: $('#btnApprove'), // "Согласовать"
|
||||
btnChange: $('#btnChange'), // "Отправить на внесение изменений"
|
||||
btnsToArchive: $('.js-btnToArchive'), // "Отказаться от заказа"
|
||||
btnsArbitration: $('.js-btnArbitration'),// "Обратиться в арбитраж"
|
||||
btnSendReview: $('#order-review-add') // "Оставить отзыв"
|
||||
}; |
||||
this.stages_elements = { |
||||
$approve: $('#conditions-approve'), //1. Согласование условия
|
||||
$reserve: $('#reserveSpace'), //2. Резервирование (Отобразить)
|
||||
$works: $('#completeWork') //3. Выполненная работа
|
||||
}; |
||||
this.init(); |
||||
} |
||||
|
||||
init() { |
||||
const self = this; |
||||
|
||||
this.dataPromise = this.getOrderData({orderId: this.orderId}); |
||||
this.dataPromise |
||||
.then( |
||||
self._onLoadData.bind(self) |
||||
) |
||||
.catch( |
||||
self._onLoadDataError.bind(self) |
||||
); |
||||
} |
||||
|
||||
getOrderData({orderId}) { |
||||
const self = this; |
||||
return Promise.resolve($.ajax({ |
||||
url: `/api/orders/${orderId}/`, |
||||
dataType: 'json', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
})) |
||||
} |
||||
|
||||
redraw() { |
||||
/** |
||||
* Полностью перерисовываем страницу Заказа |
||||
*/ |
||||
console.log("Redraw contractor stages"); |
||||
// $("#orderBlock" + this.orderId).trigger('click');
|
||||
this.init(); |
||||
} |
||||
|
||||
|
||||
buildStartStage() { |
||||
/** |
||||
* Стадия: "Проект Предложен"(нет этапов) |
||||
*/ |
||||
// Выделить цифру 1. красным
|
||||
// $('#conditions-approve').find('.select')
|
||||
this.stages_elements.$approve.show(); |
||||
this.stages_elements.$reserve.show(); |
||||
this.stages_elements.$works.show(); |
||||
this.$orderStagesContainer.parent().hide(); |
||||
this.buttons.btnsToArchive.first().hide(); |
||||
this.$orderStagesContainer.show(); |
||||
this.buttons.btnApprove.hide(); |
||||
this.buttons.btnChange.hide(); |
||||
this.buttons.btnsArbitration.hide(); |
||||
this.stages_elements.$approve.find('.js-help-text').show(); |
||||
this.stages_elements.$reserve.find('.stages-paid').html(""); |
||||
this.stages_elements.$works.find('.js-help-text').show(); |
||||
this.stages_elements.$works.find('#stagesWork').html(""); |
||||
if (this.secureOrder){ |
||||
this.stages_elements.$reserve.find('.js-help-text').show(); |
||||
} else { |
||||
this.stages_elements.$reserve.find('.js-help-text').hide(); |
||||
// this.stages_elements.$reserve.find('.js-help-text').html('Резервирование не предусмотрено, безопасная сделака не активна');
|
||||
} |
||||
|
||||
} // Нет Этапов / "Не согласован"
|
||||
|
||||
// buildNotAgreedStage() {
|
||||
// console.log("Stage: not_agreed");
|
||||
// // this._renderStage('stage_tmpl');
|
||||
// this.buttons.btnApprove.hide();
|
||||
// this.buttons.btnChange.hide();
|
||||
// this.buttons.btnToArchive.hide();
|
||||
// this.buttons.btnArbitration.hide();
|
||||
// } // Статус "Не согласован"
|
||||
|
||||
buildSendApproveStage() { |
||||
console.log("Stage: send_approve"); |
||||
this._renderStage('stage_approved_tmpl', true); |
||||
this.$orderStagesContainer.parent().show(); |
||||
this.buttons.btnApprove.show(); |
||||
this.buttons.btnChange.show(); |
||||
this.buttons.btnsToArchive.first().show(); |
||||
this.stages_elements.$reserve.hide(); |
||||
this.stages_elements.$works.hide(); |
||||
} // Статус "На согласовании"
|
||||
|
||||
buildAgreedStage() { |
||||
console.log('Stage: agreed'); |
||||
this.$orderStagesContainer.parent().show(); |
||||
this.buttons.btnApprove.hide(); |
||||
this.buttons.btnChange.hide(); |
||||
this.buttons.btnsToArchive.hide(); |
||||
this.buttons.btnsArbitration.first().hide(); |
||||
this.buttons.btnsArbitration.last().show(); |
||||
this._renderStage('stage_approved_tmpl', true); |
||||
this.stages_elements.$approve.find('.js-help-text').hide(); |
||||
this.stages_elements.$reserve.show(); |
||||
if (this.secureOrder){ |
||||
this._renderStageReserved('reserved_tmpl'); |
||||
this.stages_elements.$reserve.find('.js-help-text').show(); |
||||
}else{ |
||||
this.stages_elements.$reserve.find('.stages-paid').html(""); |
||||
this.stages_elements.$reserve.find('.js-help-text').hide(); |
||||
} |
||||
} // Статус "Согласован"
|
||||
|
||||
buildProcessStage() { |
||||
console.log('Stage: in_process'); |
||||
this.buildAgreedStage(); |
||||
this.stages_elements.$reserve.find('.js-help-text').hide(); |
||||
this.stages_elements.$works.show(); |
||||
if (this.secureOrder) { |
||||
this._renderStageInWork('work_in_process_tmpl'); |
||||
} else { |
||||
this.stages_elements.$reserve.find('.stages-paid').html(""); |
||||
} |
||||
} // Статус "В процессе"/"Завершен"/"Закрыт"
|
||||
|
||||
_buildPage() { |
||||
// console.log("Build PAge");
|
||||
this.stages_elements.$reserve.hide(); |
||||
this.stages_elements.$works.hide(); |
||||
if (this.data.stages.length == 0) { |
||||
this.buildStartStage() |
||||
} else { |
||||
let stageStatus = this.data.stages[0].status; |
||||
// console.log('stageStatus = ', stageStatus);
|
||||
this.STAGE_STATUSES[stageStatus](); |
||||
} |
||||
this._bindEvents(); |
||||
} |
||||
|
||||
_renderStage(template_name, disable = false) { |
||||
let i = 0; |
||||
// console.log("this.data.stages = ", this.data.stages);
|
||||
this.$orderStagesContainer.html(""); |
||||
for (let stage_data of this.data.stages) { |
||||
i++; |
||||
// console.log('stage_data = ', stage_data);
|
||||
let stage = new StageForm(this.$orderStagesContainer, |
||||
{ |
||||
orderId: this.orderId, stage_num: i, stage_status: STATUSES[stage_data.status], |
||||
type: 'update', template_name: template_name, data: stage_data |
||||
}); |
||||
if (disable) stage.disable(); |
||||
this.stages.push(stage); |
||||
|
||||
} |
||||
} |
||||
|
||||
_renderStageReserved(template_name) { |
||||
/** |
||||
* Отрисовываем блок "Резервирование" |
||||
*/ |
||||
// console.log("_renderStageReserved");
|
||||
let $container = this.stages_elements.$reserve.find('.stages-paid'); |
||||
$container.html(""); |
||||
this.stages_reserved = []; |
||||
// console.log("this.data.stages = ", this.data.stages);
|
||||
// Нет незарезервированных Этапов
|
||||
// let has_not_reserved_stages = false;
|
||||
for (let stage_data of this.data.stages) { |
||||
// if (stage_data.status == 'agreed') has_not_reserved_stages = true;
|
||||
let stage = new StageReserved($container, |
||||
{ |
||||
template_name, data: stage_data |
||||
}); |
||||
this.stages_reserved.push(stage); |
||||
} |
||||
// if (!has_not_reserved_stages) {
|
||||
// this.buttons.btnReserve.hide();
|
||||
// this.stages_elements.$reserve.find('.js-help-text').hide();
|
||||
// }
|
||||
} |
||||
|
||||
_renderStageInWork(template_name) { |
||||
/** |
||||
* Отрисовываем блок "Выволнение работы", включая "Выполненныа работа" и "Оставить отзыв" |
||||
*/ |
||||
let $container = this.stages_elements.$works.find('#stagesWork'); |
||||
$container.html(""); |
||||
let all_closed = this.data.stages.every((el)=>el.status == 'closed'); |
||||
if (all_closed) { |
||||
this.stages_elements.$works.find('.titleStepss').html('3. Выполненная работа'); |
||||
this.stages_elements.$works.find('.js-btnArbitration').hide(); |
||||
this.stages_elements.$works.find('.js-help-text').hide(); |
||||
for (let stage_data of this.data.stages) { |
||||
let stage = new StageInWork($container, |
||||
{ |
||||
template_name, data: stage_data |
||||
}); |
||||
this.stages_work.push(stage); |
||||
} |
||||
// console.log("has_user_review = ", this.data.has_user_review);
|
||||
if (!this.data.has_user_review) { |
||||
let btnReviewOpenModel = $(this.btnSendReviewTmpl()); |
||||
btnReviewOpenModel.unbind().on('click', this._onBtnReviewOpenModal.bind(this)); |
||||
// Если кнопка "Оставить отзыв" еще не добавлена - добавляем
|
||||
if (!this.stages_elements.$works.find('#send-review').length) this.stages_elements.$works.append(btnReviewOpenModel); |
||||
} else { |
||||
if (this.stages_elements.$works.find('#send-review').length) this.stages_elements.$works.find('#send-review').remove() |
||||
} |
||||
|
||||
} else { |
||||
for (let stage_data of this.data.stages) { |
||||
if (stage_data.status == 'closed' || stage_data.status == 'agreed') continue; |
||||
let note_text = (stage_data.status == 'completed') ? '...НА УТВЕРЖДЕНИИ У ЗАКАЗЧИКА' : ''; |
||||
let stage = new StageInWork($container, |
||||
{ |
||||
template_name, data: stage_data, note_text: note_text |
||||
}); |
||||
if (stage_data.status == 'in_process') { |
||||
let $btn = $(this.btnCompleteTmpl({stage: stage_data, text: 'Завершить этап'})); |
||||
$container.html(); |
||||
$container.append($btn); |
||||
$btn.on('click', this._onBtnComplete.bind(this, stage)) |
||||
} |
||||
this.stages_work.push(stage); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
_onLoadData(json) { |
||||
this.data = json; |
||||
this._buildPage(); |
||||
} |
||||
|
||||
_bindEvents() { |
||||
const self = this; |
||||
this.buttons.btnApprove.unbind().on("click", this._onBtnAccept.bind(self)); |
||||
this.buttons.btnChange.unbind().on("click", this._onBtnChange.bind(self)); |
||||
this.buttons.btnsToArchive.unbind().on("click", this._onBtnAToArchive.bind(self)); |
||||
this.buttons.btnsArbitration.unbind().on("click", this._onBtnArbitration.bind(self)); |
||||
this.buttons.btnSendReview.unbind().on("click", this._onBtnSendReview.bind(self)); |
||||
$("#reserve-stage-modal").find('#stage-num').unbind().on('change', function (event) { |
||||
// console.log("select stage cost = ", self.stages[this.value - 1].data.cost);
|
||||
$("#reserve-stage-modal").find('#stage-cost').html(self.stages[this.value - 1].data.cost); |
||||
}); |
||||
} |
||||
|
||||
// BINDS
|
||||
|
||||
_onBtnAccept(event) { |
||||
event.preventDefault(); |
||||
const self = this; |
||||
Promise.all(this.stages.map((el)=>el.sendAjax_accept(self.secureOrder))).then(()=> { |
||||
console.log('Этапы согласованы'); |
||||
self.redraw(); |
||||
|
||||
let message = message_format; |
||||
message.data.sender_id = userId; |
||||
message.data.recipent_id = self.recipentId; |
||||
message.data.order_id = self.orderId; |
||||
message.data.msg = `Условия заказа ${self.orderName} приняты`; |
||||
console.log("Send-WS Условия приняты"); |
||||
socket.send_stages_approve(message); |
||||
//TODO: раскомментировать дурацкое окно
|
||||
// $('#popupOk').modal('show');
|
||||
// })
|
||||
}); |
||||
} // "Согласовать"
|
||||
|
||||
_onBtnChange(event) { |
||||
event.preventDefault(); |
||||
const self = this; |
||||
Promise.all(this.stages.map((el)=>el.sendAjax_change())).then(()=> { |
||||
self.redraw(); |
||||
let message = message_format; |
||||
message.data.sender_id = userId; |
||||
message.data.recipent_id = self.recipentId; |
||||
message.data.order_id = self.orderId; |
||||
message.data.msg = `Заказ ${self.orderName} отправлен для внесения изменений`; |
||||
console.log("Send-WS Внести изменения"); |
||||
socket.send_stages_approve(message); |
||||
}); |
||||
|
||||
} // "Отправить на внесение изменений"
|
||||
|
||||
// TODO: test it
|
||||
_onBtnAToArchive(event) { |
||||
event.preventDefault(); |
||||
console.error("Отказаться от заказа. Не протестировано!!"); |
||||
// TODO: Не только удалять заказ, но и делать его копию со статусом "Открыто"
|
||||
$.ajax({ |
||||
// async: false,
|
||||
url: `/api/orders/${this.orderId}/`, |
||||
type: 'DELETE', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
dataType: 'json', |
||||
}) |
||||
.done(function (json) { |
||||
console.log('delete complete'); |
||||
window.location.href = window.location.href.replace(getHash(), ""); |
||||
}) |
||||
.fail(function (xhr, errorMsg, error) { |
||||
console.log("delete fail, json -->", xhr); |
||||
}); |
||||
|
||||
} // "Отказаться от заказа"
|
||||
|
||||
_onBtnComplete(stage, event) { |
||||
event.preventDefault(); |
||||
const self = this; |
||||
// let stageId = $(event.target).data('stage-id');
|
||||
// console.log('Complete stage id = ', stage.data.id);
|
||||
stage.sendAjax_complete() |
||||
.then(function (json) { |
||||
self.redraw(); |
||||
let message = message_format; |
||||
message.data.sender_id = userId; |
||||
message.data.recipent_id = self.recipentId; |
||||
message.data.order_id = self.orderId; |
||||
message.data.msg = `Этап ${json.name} закрыт`; |
||||
console.log("Send-WS Закрытие этапа"); |
||||
socket.send_stages_approve(message); |
||||
}) |
||||
.catch(function (xhr) { |
||||
console.log("При закрытии этапа произошла ошибка -->", xhr); |
||||
}) |
||||
|
||||
} // "Закрыть этап"
|
||||
|
||||
_onBtnReviewOpenModal(event) { |
||||
event.preventDefault(); |
||||
$('#review-add').modal('show'); |
||||
} // Открыть модальное окно "Оставить отзыв"
|
||||
|
||||
_onBtnSendReview(event) { |
||||
event.preventDefault(); |
||||
const self = this; |
||||
$('#projectReviewId').val(this.projectId); |
||||
$('#targetCustomerId').val(this.recipentId); |
||||
// $('#fromContractorId').val('....current user');
|
||||
var formData = $("#review-adds-form").serialize(); |
||||
// console.log('Оставить отзыв formdata -->', formData);
|
||||
$.ajax({ |
||||
url: '/api/reviews/', |
||||
type: 'POST', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: formData, |
||||
dataType: 'json', |
||||
success: function (json) { |
||||
// console.log('Отзыв успешно отправлен, json -->', json);
|
||||
// $('#review-add').modal('hide');
|
||||
// self.stages_elements.$works.find('.js-btnSendReview').hide();
|
||||
$('#review-add').modal('hide'); |
||||
self.redraw(); |
||||
|
||||
let message = message_format; |
||||
message.data.sender_id = userId; |
||||
message.data.recipent_id = self.recipentId; |
||||
message.data.order_id = self.orderId; |
||||
message.data.msg = `Отзыв на заказ ${self.orderName} оставлен`; |
||||
console.log("Send-WS Оставить отзыв"); |
||||
socket.send_stages_approve(message); |
||||
// $("a[href='#tab2']").trigger('click');
|
||||
window.location = '/chat/#order'; |
||||
location.reload(); |
||||
}, |
||||
error: function (e) { |
||||
console.log('error'); |
||||
console.log(e); |
||||
} |
||||
}); |
||||
} // "Оставить отзыв"
|
||||
|
||||
|
||||
_onBtnArbitration(event) { |
||||
event.preventDefault(); |
||||
$("#arbitration-add").modal('show'); |
||||
} // "Обратиться в арбитраж"
|
||||
|
||||
_onLoadDataError(error) { |
||||
console.log("Error loading data -->", error); |
||||
} |
||||
} |
||||
|
||||
export {StagesController} |
||||
@ -0,0 +1,545 @@ |
||||
import {getCookie} from '../utils' |
||||
import {loadTemplate} from './loaders' |
||||
import {StageForm, StageReserved, StageInWork} from './Stages' |
||||
|
||||
let message_format = { |
||||
"format_type": "approve_stages", |
||||
"data": { |
||||
"sender_id": "", |
||||
"recipent_id": "", |
||||
"order_id": "", |
||||
"msg": "", |
||||
"is_system": true |
||||
} |
||||
}; |
||||
|
||||
const STATUSES = { |
||||
'not_agreed': 'не согласован', |
||||
'send_approve': 'на согласовании', |
||||
'agreed': 'согласовано', |
||||
'cancel_approve': 'исполнитель отказался', |
||||
'in_process': 'в процессе', |
||||
'completed': 'завершен', |
||||
'closed': 'закрыт', |
||||
|
||||
}; |
||||
|
||||
|
||||
class StagesController { |
||||
constructor(orderId, projectId, recipentId, orderName, secureOrder) { |
||||
const self = this; |
||||
this.orderId = orderId; |
||||
this.orderName = orderName; |
||||
this.projectId = projectId; |
||||
this.recipentId = recipentId; |
||||
this.secureOrder = secureOrder; |
||||
this.data = {}; //JSON
|
||||
this.stages = []; |
||||
this.stages_reserved = []; |
||||
this.stages_work = []; |
||||
this.STAGE_STATUSES = { |
||||
'not_agreed': this.buildNotAgreedStage.bind(self), |
||||
'send_approve': this.buildSendApproveStage.bind(self), |
||||
'agreed': this.buildAgreedStage.bind(self), |
||||
'in_process': this.buildProcessStage.bind(self), |
||||
'completed': this.buildProcessStage.bind(self), |
||||
'closed': this.buildProcessStage.bind(self), |
||||
}; |
||||
this.btnCompleteTmpl = loadTemplate('bntCompleteStage_tmpl'); |
||||
this.btnSendReviewTmpl = loadTemplate('btnSendReview_tmpl'); |
||||
this.$orderStagesContainer = $('#order-stages'); |
||||
this.$orderStagesContainer.html(''); |
||||
this.$stagesCount = $('#countStage'); |
||||
this.$stagesCount.unbind().on("change", this._changeNumStages.bind(self)); |
||||
this.$stagesCount.parent().show(); |
||||
this.buttons = { |
||||
btnApprove: $('#btnApprove'), |
||||
btnChange: $('#btnChange'), |
||||
btnToArchive: $('#btnToArchive'), |
||||
btnReserve: $('#btnReserve'), |
||||
btnsArbitration: $('.js-btnArbitration'), |
||||
btnSendReview: $('#order-review-add') |
||||
}; |
||||
this.stages_elements = { |
||||
$approve: $('#conditions-approve'), //1. Согласование условия
|
||||
$reserve: $('#reserveSpace'), //2. Резервирование
|
||||
$works: $('#completeWork') //3. Выполненная работа
|
||||
}; |
||||
this.init(); |
||||
} |
||||
|
||||
init() { |
||||
const self = this; |
||||
|
||||
this.dataPromise = this.getOrderData({orderId: this.orderId}); |
||||
this.dataPromise |
||||
.then( |
||||
self._onLoadData.bind(self) |
||||
) |
||||
.catch( |
||||
self._onLoadDataError.bind(self) |
||||
); |
||||
} |
||||
|
||||
getOrderData({orderId}) { |
||||
const self = this; |
||||
return Promise.resolve($.ajax({ |
||||
url: `/api/orders/${orderId}/`, |
||||
dataType: 'json', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
})) |
||||
} |
||||
|
||||
redraw() { |
||||
/** |
||||
* Полностью перерисовываем страницу Заказа |
||||
*/ |
||||
console.log("Redraw customer stages"); |
||||
// $("#orderBlock" + this.orderId).trigger('click');
|
||||
this.init(); |
||||
} |
||||
|
||||
buildStartStage() { |
||||
/** |
||||
* Стадия: "Проект Предложен"(нет этапов) |
||||
*/ |
||||
// Выделить цифру 1. красным
|
||||
// $('#conditions-approve').find('.select')
|
||||
this.$orderStagesContainer.show(); |
||||
this.buttons.btnApprove.show(); |
||||
this.buttons.btnChange.hide(); |
||||
this.buttons.btnToArchive.hide(); |
||||
this.$stagesCount.removeAttr('disabled'); |
||||
this.$stagesCount.val(1); |
||||
this.$stagesCount.trigger('change'); |
||||
// this.stages_elements.$approve.find('.js-help-text').show();
|
||||
// this.stages_elements.$reserve.find('.js-help-text').show();
|
||||
// this.stages_elements.$reserve.find('.stages-paid').hide();
|
||||
// this.stages_elements.$works.find('.js-help-text').show();
|
||||
// this.stages_elements.$works.find('#stagesWork').show();
|
||||
|
||||
} // Нет Этапов
|
||||
|
||||
buildNotAgreedStage() { |
||||
console.log("Stage: not_agreed"); |
||||
this._renderStage('stage_tmpl'); |
||||
this.buttons.btnApprove.show(); |
||||
this.buttons.btnChange.hide(); |
||||
this.buttons.btnToArchive.hide(); |
||||
} // Статус "Не согласован"
|
||||
|
||||
buildSendApproveStage() { |
||||
console.log("Stage: send_approve"); |
||||
this._renderStage('stage_tmpl', true); |
||||
this.$stagesCount.attr('disabled', true); |
||||
this.stages_elements.$reserve.hide(); |
||||
this.stages_elements.$works.hide(); |
||||
this.buttons.btnApprove.hide(); |
||||
this.buttons.btnChange.show(); |
||||
this.buttons.btnToArchive.show(); |
||||
} // Статус "На согласовании"
|
||||
|
||||
buildAgreedStage() { |
||||
console.log('Stage: agreed'); |
||||
this.buttons.btnApprove.hide(); |
||||
this.buttons.btnChange.hide(); |
||||
this.buttons.btnToArchive.hide(); |
||||
this.$stagesCount.parent().hide(); |
||||
this._renderStage('stage_approved_tmpl', true); |
||||
this.stages_elements.$approve.find('.js-help-text').hide(); |
||||
this.stages_elements.$reserve.find('.js-help-text').show(); |
||||
this.stages_elements.$reserve.show(); |
||||
this.buttons.btnReserve.show(); |
||||
this.buttons.btnsArbitration.show(); |
||||
this._renderStageReserved('reserved_tmpl') |
||||
|
||||
} // Статус "Согласован"
|
||||
|
||||
buildProcessStage() { |
||||
console.log('Stage: in_process'); |
||||
this.buildAgreedStage(); |
||||
this.stages_elements.$reserve.find('.js-btnArbitration').hide(); |
||||
this.stages_elements.$works.show(); |
||||
this._renderStageInWork('work_in_process_tmpl'); |
||||
} // Статус "В процессе"/"Завершен"/"Закрыт"
|
||||
|
||||
_buildPage() { |
||||
// console.log("Build PAge");
|
||||
this.stages_elements.$reserve.hide(); |
||||
this.stages_elements.$works.hide(); |
||||
if (this.data.stages.length == 0) { |
||||
this.buildStartStage() |
||||
} else { |
||||
let stageStatus = this.data.stages[0].status; |
||||
// console.log('stageStatus = ', stageStatus);
|
||||
this.STAGE_STATUSES[stageStatus](); |
||||
} |
||||
this._bindEvents(); |
||||
} |
||||
|
||||
_renderStage(template_name, disable = false) { |
||||
let i = 0; |
||||
this.$orderStagesContainer.html(""); |
||||
for (let stage_data of this.data.stages) { |
||||
i++; |
||||
let stage = new StageForm(this.$orderStagesContainer, |
||||
{ |
||||
orderId: this.orderId, stage_num: i, stage_status: STATUSES[stage_data.status], |
||||
type: 'update', template_name: template_name, data: stage_data |
||||
}); |
||||
if (disable) stage.disable(); |
||||
this.stages.push(stage); |
||||
|
||||
} |
||||
this.$stagesCount.val(i); |
||||
} |
||||
|
||||
_renderStageReserved(template_name) { |
||||
let $container = this.stages_elements.$reserve.find('.stages-paid'); |
||||
$container.html(""); |
||||
this.stages_reserved = []; |
||||
// Нет незарезервированных Этапов
|
||||
let has_not_reserved_stages = false; |
||||
for (let stage_data of this.data.stages) { |
||||
if (stage_data.status == 'agreed') has_not_reserved_stages = true; |
||||
let stage = new StageReserved($container, |
||||
{ |
||||
template_name, data: stage_data |
||||
}); |
||||
this.stages_reserved.push(stage); |
||||
} |
||||
if (!has_not_reserved_stages) { |
||||
this.buttons.btnReserve.hide(); |
||||
this.stages_elements.$reserve.find('.js-help-text').hide(); |
||||
} |
||||
} |
||||
|
||||
_renderStageInWork(template_name) { |
||||
/** |
||||
* Отрисовываем блок "Выволнение работы", включая "Выполненныа работа" и "Оставить отзыв" |
||||
*/ |
||||
let $container = this.stages_elements.$works.find('#stagesWork'); |
||||
$container.html(""); |
||||
let all_closed = this.data.stages.every((el)=>el.status == 'closed'); |
||||
if (all_closed) { |
||||
this.stages_elements.$works.find('.titleStepss').html('3. Выполненная работа'); |
||||
this.stages_elements.$works.find('.js-btnArbitration').hide(); |
||||
this.stages_elements.$works.find('.js-help-text').hide(); |
||||
for (let stage_data of this.data.stages) { |
||||
let stage = new StageInWork($container, |
||||
{ |
||||
template_name, |
||||
data: stage_data, |
||||
note_text: 'Закройте этап или подробно опишите замечания в чате' |
||||
}); |
||||
this.stages_work.push(stage); |
||||
} |
||||
if (!this.data.has_user_review) { |
||||
let btnReviewOpenModel = $(this.btnSendReviewTmpl()); |
||||
btnReviewOpenModel.unbind().on('click', this._onBtnReviewOpenModal.bind(this)); |
||||
// Если кнопка "Оставить отзыв" еще не добавлена - добавляем
|
||||
if (!this.stages_elements.$works.find('#send-review').length) this.stages_elements.$works.append(btnReviewOpenModel); |
||||
} else { |
||||
if (this.stages_elements.$works.find('#send-review').length) this.stages_elements.$works.find('#send-review').remove() |
||||
} |
||||
|
||||
} else { |
||||
for (let stage_data of this.data.stages) { |
||||
if (stage_data.status == 'closed') continue; |
||||
let stage = new StageInWork($container, |
||||
{ |
||||
template_name, data: stage_data |
||||
}); |
||||
if (stage_data.status == 'completed') { |
||||
let $btn = $(this.btnCompleteTmpl({stage: stage_data, text: 'Закрыть этап'})); |
||||
$container.html(); |
||||
$container.append($btn); |
||||
$btn.on('click', this._onBtnClose.bind(this, stage)) |
||||
} |
||||
this.stages_work.push(stage); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
_onLoadData(json) { |
||||
this.data = json; |
||||
this._buildPage(); |
||||
} |
||||
|
||||
_changeNumStages(event) { |
||||
/** |
||||
* Изменяет кол-во этапов(stages) |
||||
*/ |
||||
let newNumStages = parseInt($(event.target).val()); |
||||
if (newNumStages < 1 || isNaN(newNumStages)) { |
||||
newNumStages = 1; |
||||
this.$stagesCount.val(newNumStages) |
||||
} |
||||
let currentNumStages = $('.js-stage-form:not(.remove-stages-form)').length; |
||||
if (currentNumStages == newNumStages) return; |
||||
if (currentNumStages > newNumStages) { |
||||
for (let stage of this.stages.slice().reverse()) { |
||||
if (stage.remove()) { |
||||
let index = this.stages.indexOf(stage); |
||||
if (index >= 0) { |
||||
this.stages.splice(index, 1); |
||||
} |
||||
} |
||||
currentNumStages--; |
||||
if (currentNumStages == newNumStages) break; |
||||
} |
||||
} else { |
||||
for (let stage of this.stages.slice()) { |
||||
if (stage.type == 'remove') { |
||||
stage.restore(); |
||||
} else continue; |
||||
currentNumStages++; |
||||
if (currentNumStages == newNumStages) break; |
||||
} |
||||
while (currentNumStages < newNumStages) { |
||||
currentNumStages++; |
||||
let stage = new StageForm(this.$orderStagesContainer, |
||||
{orderId: this.orderId, stage_num: currentNumStages, type: 'new', template_name: 'stage_tmpl'}); |
||||
this.stages.push(stage); |
||||
} |
||||
} |
||||
} //При изменении кол-ва этапов
|
||||
|
||||
_bindEvents() { |
||||
const self = this; |
||||
this.buttons.btnApprove.unbind().on("click", this._onBtnApprove.bind(self)); |
||||
this.buttons.btnChange.unbind().on("click", this._onBtnChange.bind(self)); |
||||
this.buttons.btnToArchive.unbind().on("click", this._onBtnAToArchive.bind(self)); |
||||
this.buttons.btnReserve.unbind().on("click", this._onBtnReserve.bind(self)); |
||||
this.buttons.btnsArbitration.unbind().on("click", this._onBtnArbitration.bind(self)); |
||||
this.buttons.btnSendReview.unbind().on("click", this._onBtnSendReview.bind(self)); |
||||
$('#paymentfromSite').unbind().on('click', this._onBtnPaymentFromSite.bind(self)); |
||||
$("#reserve-stage-modal").find('#stage-num').unbind().on('change', function (event) { |
||||
// console.log("select stage cost = ", self.stages[this.value - 1].data.cost);
|
||||
$("#reserve-stage-modal").find('#stage-cost').html(self.stages[this.value - 1].data.cost); |
||||
}); |
||||
} |
||||
|
||||
// BINDS
|
||||
|
||||
_onBtnApprove(event) { |
||||
event.preventDefault(); |
||||
const self = this; |
||||
if (!this.stages.every((el)=>el.is_valid())) { |
||||
console.error('Не все поля форм валидны'); |
||||
return |
||||
} |
||||
// При выполнении всех ajax запросов
|
||||
Promise.all(this.stages.map((el)=>el.sendAjax_approve())).then(()=> { |
||||
this.buttons.btnApprove.hide(); |
||||
this.buttons.btnChange.show(); |
||||
this.buttons.btnToArchive.show(); |
||||
this.$stagesCount.attr('disabled', true); |
||||
// var currentRecipentId = $(self).data('id');
|
||||
// var secureOrder = true;
|
||||
//
|
||||
let message = message_format; |
||||
message.data.sender_id = userId; |
||||
message.data.recipent_id = self.recipentId; |
||||
message.data.order_id = self.orderId; |
||||
message.data.msg = `Условия заказа ${self.orderName} отправлены на согласование`; |
||||
console.log("Send-WS Отправить на согласование"); |
||||
socket.send_stages_approve(message); |
||||
//TODO: раскомментировать дурацкое окно
|
||||
// $('#popupOk').modal('show');
|
||||
// })
|
||||
}); |
||||
} // "Отправить на согласование"
|
||||
|
||||
_onBtnChange(event) { |
||||
event.preventDefault(); |
||||
const self = this; |
||||
Promise.all(this.stages.map((el)=>el.sendAjax_change())).then(()=> { |
||||
this.buttons.btnApprove.show(); |
||||
this.buttons.btnChange.hide(); |
||||
this.buttons.btnToArchive.hide(); |
||||
this.$stagesCount.attr('disabled', false); |
||||
let message = message_format; |
||||
message.data.sender_id = userId; |
||||
message.data.recipent_id = self.recipentId; |
||||
message.data.order_id = self.orderId; |
||||
message.data.msg = `Заказ ${self.orderName} отозван для внесения изменений`; |
||||
console.log("Send-WS Внести изменения"); |
||||
socket.send_stages_approve(message); |
||||
}); |
||||
|
||||
} // "Внести изменения"
|
||||
|
||||
// TODO: test it
|
||||
_onBtnAToArchive(event) { |
||||
event.preventDefault(); |
||||
const self = this; |
||||
$.ajax({ |
||||
// async: false,
|
||||
url: `/api/orders/${this.orderId}/`, |
||||
type: 'DELETE', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
dataType: 'json', |
||||
}) |
||||
.done(function (json) { |
||||
console.log('delete complete'); |
||||
window.location.href = window.location.href.replace(getHash(), ""); |
||||
let message = message_format; |
||||
message.data.sender_id = userId; |
||||
message.data.recipent_id = self.recipentId; |
||||
message.data.order_id = self.orderId; |
||||
message.data.msg = `Заказа ${self.orderName} отправлен в архив`; |
||||
console.log("Send-WS Отправить в архив"); |
||||
socket.send_stages_approve(message); |
||||
}) |
||||
.fail(function (xhr, errorMsg, error) { |
||||
console.log("delete fail, json -->", xhr); |
||||
}); |
||||
|
||||
} // "Отказаться и отправить в архив"
|
||||
|
||||
_onBtnReserve(event) { |
||||
const self = this; |
||||
event.preventDefault(); |
||||
// Set modal-window params
|
||||
let $modal = $("#reserve-stage-modal"); |
||||
let total_cost = this.stages.map((el)=>parseInt(el.data.cost)).reduce((a, b) => a + b, 0); |
||||
// console.log('total cost = ', total_cost);
|
||||
$modal.find('#total-cost').html(total_cost); |
||||
|
||||
let $select_stageNum = $modal.find('#stage-num'); |
||||
$select_stageNum |
||||
.find('option') |
||||
.remove() |
||||
.end(); |
||||
for (let stage of this.stages) { |
||||
if (stage.data.is_paid) continue; |
||||
$select_stageNum.append(`<option>${stage.data.pos}</option>`); |
||||
} |
||||
// let $stage_cost = $modal.find('#stage-cost');
|
||||
// $stage_cost.html(self.stages[this.value - 1].data.cost);
|
||||
$modal.find('#stage-num').trigger('change'); |
||||
|
||||
$modal.modal('show'); |
||||
} // "Зарезервировать" --> Открывает модальное окно для резервирования
|
||||
|
||||
_onBtnPaymentFromSite(event) { |
||||
const self = this; |
||||
event.preventDefault(); |
||||
let $modal = $("#reserve-stage-modal"); |
||||
let sum, stages_id; |
||||
if ($modal.find('input[name=choice_way]:checked').val() == 'all_stages') { |
||||
sum = $modal.find('#total-cost').html(); |
||||
stages_id = this.stages.map((el)=>el.data.id); |
||||
} else { |
||||
sum = $modal.find('#stage-cost').html(); |
||||
let num_stage = $modal.find('#stage-num').val() - 1; |
||||
stages_id = [this.stages[num_stage].data.id]; |
||||
} |
||||
$.ajax({ |
||||
url: '/wallets/payfromscore/', |
||||
type: 'POST', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: { |
||||
sum: sum, |
||||
stages_id: stages_id.join(';'), |
||||
}, |
||||
dataType: 'json', |
||||
success: function (json) { |
||||
// console.log('success pay stage, json ', json);
|
||||
$("#reserve-stage-modal").modal('toggle'); |
||||
let message = message_format; |
||||
message.data.sender_id = userId; |
||||
message.data.recipent_id = self.recipentId; |
||||
message.data.order_id = self.orderId; |
||||
message.data.msg = `Заказчик зарезервировал сумму для этапов`; |
||||
console.log("Send-WS Оплата Этапа/Этапов"); |
||||
socket.send_stages_approve(message); |
||||
self.redraw(); |
||||
}, |
||||
error: function (xhr) { |
||||
console.log('error pay stage, json', xhr.responseJSON); |
||||
$.jGrowl(xhr.responseJSON.message_error); |
||||
} |
||||
}); |
||||
} // Оплата с сайта(Счет на Proekton)
|
||||
|
||||
_onBtnClose(stage, event) { |
||||
event.preventDefault(); |
||||
const self = this; |
||||
stage.sendAjax_close() |
||||
.then(function (json) { |
||||
console.log("Этап закрыт успешно"); |
||||
let message = message_format; |
||||
message.data.sender_id = userId; |
||||
message.data.recipent_id = self.recipentId; |
||||
message.data.order_id = self.orderId; |
||||
message.data.msg = `Заказчик закрыл этап ${json.name}`; |
||||
console.log("Send-WS Оплата Этапа/Этапов"); |
||||
socket.send_stages_approve(message); |
||||
self.redraw(); |
||||
}) |
||||
.catch(function (xhr) { |
||||
console.log("При закрытии этапа произошла ошибка -->", xhr); |
||||
}) |
||||
|
||||
} // "Закрыть этап"
|
||||
|
||||
_onBtnReviewOpenModal(event) { |
||||
event.preventDefault(); |
||||
$('#review-add').modal('show'); |
||||
} // Открыть модальное окно "Оставить отзыв"
|
||||
|
||||
_onBtnSendReview(event) { |
||||
event.preventDefault(); |
||||
const self = this; |
||||
$('#projectReviewId').val(this.projectId); |
||||
$('#targetContractorId').val(this.recipentId); |
||||
var formData = $("#review-adds-form").serialize(); |
||||
$.ajax({ |
||||
url: '/api/reviews/', |
||||
type: 'POST', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: formData, |
||||
dataType: 'json', |
||||
success: function (json) { |
||||
$('#review-add').modal('hide'); |
||||
let message = message_format; |
||||
message.data.sender_id = userId; |
||||
message.data.recipent_id = self.recipentId; |
||||
message.data.order_id = self.orderId; |
||||
message.data.msg = `Отзыв на заказ ${self.orderName} оставлен`; |
||||
console.log("Send-WS Оставить отзыв"); |
||||
socket.send_stages_approve(message); |
||||
window.location = '/chat/#order'; |
||||
location.reload(); |
||||
// $("a[href='#tab2']").trigger('click');
|
||||
}, |
||||
error: function (e) { |
||||
console.log('error'); |
||||
console.log(e); |
||||
} |
||||
}); |
||||
} // "Оставить отзыв"
|
||||
|
||||
|
||||
_onBtnArbitration(event) { |
||||
event.preventDefault(); |
||||
$("#arbitration-add").modal('show'); |
||||
} // "Обратиться в арбитраж"
|
||||
|
||||
_onLoadDataError(error) { |
||||
console.log("Error loading data -->", error); |
||||
} |
||||
} |
||||
|
||||
export {StagesController} |
||||
@ -0,0 +1,84 @@ |
||||
import {getCookie} from '../utils' |
||||
|
||||
|
||||
function bindArchiveProjects() { |
||||
// Нажимаем на кнопку архивные сообщения
|
||||
$("#trashed-button").on('click', function (e) { |
||||
e.preventDefault(); |
||||
var state = $(this).attr('data-show'); |
||||
var trashedOrderHtml = ""; |
||||
|
||||
if (state == 'true') { |
||||
$(this).attr('data-show', 'false'); |
||||
$(this).text("Скрыть архивные заказы"); |
||||
|
||||
$("#archive-space").show(); |
||||
$("#show-archive-label").show(); |
||||
|
||||
} else { |
||||
$(this).attr('data-show', 'true'); |
||||
$(this).text("Показать архивные заказы"); |
||||
$("#archive-space").hide(); |
||||
$("#show-archive-label").hide(); |
||||
} |
||||
|
||||
|
||||
}); |
||||
|
||||
// Нажимаем на заказ в архмвных заказах
|
||||
$(".messageBlock").on('click', '.trashedOrderBlock', function () { |
||||
let $this = $(this); |
||||
$("#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 = '';
|
||||
|
||||
|
||||
let orderId = $this.data('id'); |
||||
// let projectId = $this.data('project-id');
|
||||
// let recipentId = $this.data('recipent-id');
|
||||
// let orderName = $this.data('order-name');
|
||||
location.hash = '#order' + orderId; |
||||
// console.log(orderId);
|
||||
window.chatController.create(orderId); |
||||
// $.ajax({
|
||||
// url: '/api/message',
|
||||
// type: 'GET',
|
||||
// beforeSend: function (xhr) {
|
||||
// xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'))
|
||||
// },
|
||||
// data: {'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 += '<div class="col-lg-12 insetCommChat ' + className + '"><div class="topCommChat">' +
|
||||
// '<p class="nameCommChat">' + senderName + '</p><span>' + v.created + '</span></div>' +
|
||||
// '<p class="textCommChat">' + v.text + '</p></div>';
|
||||
//
|
||||
// });
|
||||
// var height = inbox.scrollHeight;
|
||||
// inbox.scrollTop = height;
|
||||
// }
|
||||
// });
|
||||
|
||||
// $("#order-stages").html("");
|
||||
// $("#completeWork").hide();
|
||||
// $("#add-form-order-note").hide();
|
||||
// $("#reserveSpace").hide();
|
||||
}); |
||||
} |
||||
|
||||
export {bindArchiveProjects} |
||||
@ -0,0 +1,145 @@ |
||||
function chatContactsInit() { |
||||
/** |
||||
* Bind на кнопку "Отправить" в Закладке "Личные контакты" |
||||
*/ |
||||
$('#contact-chat-add-message').on('click', function (e) { |
||||
e.preventDefault(); |
||||
var chatMessage = $("#chat").val(); |
||||
var recipentId = $("#recipentContactId").val(); |
||||
var senderId = $("#senderContactId").val(); |
||||
var sendLinks = $("#document-send-contact a"); |
||||
|
||||
if (chatMessage || sendLinks.length > 0) { |
||||
$("#contact-chat-form .errorEmptyMessage").hide(); |
||||
|
||||
var sendLinkIds = ""; |
||||
var documentLinks = ""; |
||||
var documentAttachFiles = ""; |
||||
|
||||
$.each(sendLinks, function (i, v) { |
||||
sendLinkIds += $(this).attr('data-id') + ';'; |
||||
documentLinks += 'Приложенный файл. скачать: <br> <a href="' + $(this).attr('href') + '">' + $(this).text() + '</a><br>'; |
||||
documentAttachFiles += '<li style="word-break: break-all;">' + |
||||
'<a class="file-link" href="' + $(this).attr('href') + '">' + $(this).text() + '</a>' + |
||||
'<div class="remove-document" data-id="' + $(this).attr('data-id') + '" style="right:-10px;"></div></li>'; |
||||
}); |
||||
// console.log("sendLinkIds = ", sendLinkIds);
|
||||
socket.send_message({ |
||||
"format_type": "add_message_contact", |
||||
"data": { |
||||
"sender_id": senderId, |
||||
"recipent_id": recipentId, |
||||
"chat_message": chatMessage, |
||||
"document_send_links": sendLinkIds, |
||||
"document_data": { |
||||
"document_links": documentLinks, |
||||
"document_attach_files": documentAttachFiles, |
||||
} |
||||
} |
||||
}); |
||||
$("#chat").val(""); |
||||
$("#document-send-contact").html(""); |
||||
} else { |
||||
$("#contact-chat-form .errorEmptyMessage").show(); |
||||
} |
||||
|
||||
}); |
||||
} |
||||
|
||||
function chatOrdersInit() { |
||||
/** |
||||
* Bind на кнопку "Отправить" в Закладке "Исполнители/Заказчики" |
||||
*/ |
||||
$('#order-chat-add-message').on('click', function (e) { |
||||
e.preventDefault(); |
||||
var chatMessage = $("#chat-order-add #chat").val(); |
||||
var recipentId = $("#chat-order-add #recipentId").val(); |
||||
var senderId = $("#chat-order-add #senderId").val(); |
||||
var orderId = $("#chat-order-add #orderId").val(); |
||||
var sendLinks = $("#document-send-order a"); |
||||
if (chatMessage || sendLinks.length > 0) { |
||||
var sendLinkIds = ""; |
||||
var documentLinks = ""; |
||||
var documentAttachFiles = ""; |
||||
$.each(sendLinks, function (i, v) { |
||||
sendLinkIds += $(this).attr('data-id') + ';'; |
||||
documentLinks += 'Приложенный файл. скачать: <br> <a href="' + $(this).attr('href') + '">' + $(this).text() + '</a><br>'; |
||||
documentAttachFiles += '<li style="word-break: break-all;">' + |
||||
'<a class="file-link" href="' + $(this).attr('href') + '">' + $(this).text() + '</a>' + |
||||
'<div class="remove-document" data-id="' + $(this).attr('data-id') + '" style="right:-10px;"></div></li>'; |
||||
}); |
||||
socket.send_message({ |
||||
"format_type": "add_message_order", |
||||
"data": { |
||||
"sender_id": senderId, |
||||
"recipent_id": recipentId, |
||||
"chat_message": chatMessage, |
||||
"order_id": orderId, |
||||
"document_send_links": sendLinkIds, |
||||
"document_data": { |
||||
"document_links": documentLinks, |
||||
"document_attach_files": documentAttachFiles, |
||||
} |
||||
} |
||||
|
||||
}); |
||||
$("#chat-order-add #chat").val(""); |
||||
$("#document-send-order").html(""); |
||||
} else { |
||||
$("#chat-order-add .errorEmptyMessage").show(); |
||||
} |
||||
|
||||
}); |
||||
} |
||||
|
||||
function chatTeamsInit() { |
||||
$("#add-team-chat-message").on('click', function (e) { |
||||
e.preventDefault(); |
||||
var chatMessage = $("#team-chat-form #chatText").val(); |
||||
// var recipentId = $("#team-chat-form #recipentTeamId").val();
|
||||
var senderId = $("#team-chat-form #senderTeamId").val(); |
||||
var teamId = $("#team-chat-form #teamId").val(); |
||||
// var orderId = $("#team-chat-form #orderTeamId").val();
|
||||
var documentSendIds = $("#documentSendIds").val(); |
||||
var teamIds = $("#team-chat-form #teamIds").val(); |
||||
var sendLinks = $("#document-send a"); |
||||
if (chatMessage || sendLinks.length > 0) { |
||||
var sendLinkIds = ""; |
||||
var documentLinks = ""; |
||||
var documentAttachFiles = ""; |
||||
$.each(sendLinks, function (i, v) { |
||||
sendLinkIds += $(this).attr('data-id') + ';'; |
||||
documentLinks += 'Приложенный файл. скачать: <br> <a href="' + $(this).attr('href') + '">' + $(this).text() + '</a><br>'; |
||||
documentAttachFiles += '<li style="word-break: break-all;">' + |
||||
'<a class="file-link" href="' + $(this).attr('href') + '">' + $(this).text() + '</a>' + |
||||
'<div class="remove-document" data-id="' + $(this).attr('data-id') + '" style="right:-10px;"></div></li>'; |
||||
|
||||
}); |
||||
socket.send_message({ |
||||
"format_type": "add_message_team", |
||||
"data": { |
||||
"sender_id": senderId, |
||||
// "recipent_id": recipentId,
|
||||
"chat_message": chatMessage, |
||||
"team_id": teamId, |
||||
"team_ids": teamIds, |
||||
// "order_id": orderId,
|
||||
"document_send_links": sendLinkIds, |
||||
"document_data": { |
||||
"document_links": documentLinks, |
||||
"document_attach_files": documentAttachFiles, |
||||
} |
||||
} |
||||
}); |
||||
|
||||
$("#team-chat-form #chatText").val(""); |
||||
$("#document-send").html(""); |
||||
$("#documentSendIds").val(""); |
||||
} else { |
||||
$("#team-chat-form .errorEmptyMessage").show(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
|
||||
export {chatContactsInit, chatOrdersInit, chatTeamsInit} |
||||
@ -0,0 +1,157 @@ |
||||
import {getCookie} from '../utils' |
||||
|
||||
function uploadDocumentsContactInit() { |
||||
$("#upload-document-contact").bind('fileuploadsubmit', function (e, data) { |
||||
data.formData = { |
||||
sender: $("#contact-chat-form #senderContactId").val(), |
||||
recipent: $("#contact-chat-form #recipentContactId").val(), |
||||
} |
||||
|
||||
}); |
||||
|
||||
$('#upload-document-contact').fileupload({ |
||||
url: '/chat/create/', |
||||
crossDomain: false, |
||||
beforeSend: function (xhr, settings) { |
||||
// console.log("Upload form data -->", this.formData);
|
||||
$('#progress .progress-bar').css( |
||||
'width', |
||||
'0%' |
||||
); |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
dataType: 'json', |
||||
done: function (e, data) { |
||||
$.each(data.result.files, function (index, file) { |
||||
var htmlImg = '<div style="float: left"><a href="/chat/download/' + file.name + '" class="send-doc" data-id="' + file.id + '">' + file.name + '</a>' + |
||||
'<div class="remove-document" data-id="' + file.id + '" style="right:-10px;float:left;position: static;"></div></div>'; |
||||
var document_send = $(htmlImg).appendTo("#document-send-contact"); |
||||
}); |
||||
}, |
||||
fail: function (e) { |
||||
console.log(e); |
||||
}, |
||||
progressall: function (e, data) { |
||||
var progress = parseInt(data.loaded / data.total * 100, 10); |
||||
$('#progress .progress-bar').css( |
||||
'width', |
||||
progress + '%' |
||||
); |
||||
} |
||||
}).prop('disabled', !$.support.fileInput) |
||||
.parent().addClass($.support.fileInput ? undefined : 'disabled'); |
||||
} |
||||
|
||||
function uploadDocumentsOrderInit() { |
||||
$("#upload-document-order").bind('fileuploadsubmit', function (e, data) { |
||||
data.formData = { |
||||
sender: $("#chat-order-add #senderId").val(), |
||||
recipent: $("#chat-order-add #recipentId").val(), |
||||
order: $("#chat-order-add #orderId").val(), |
||||
} |
||||
// console.log(data.formData);
|
||||
}); |
||||
|
||||
$('#upload-document-order').fileupload({ |
||||
url: '/chat/create/', |
||||
crossDomain: false, |
||||
beforeSend: function (xhr, settings) { |
||||
$('#progress .progress-bar').css( |
||||
'width', |
||||
'0%' |
||||
); |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
dataType: 'json', |
||||
done: function (e, data) { |
||||
$.each(data.result.files, function (index, file) { |
||||
var htmlImg = '<div style="float: left"><a href="/chat/download/' + file.name + '" class="send-doc" data-id="' + file.id + '">' + file.name + '</a>' + |
||||
'<div class="remove-document" data-id="'+ file.id+'" style="right:-10px;float:left;position: static;"></div></div>'; |
||||
var document_send = $(htmlImg).appendTo("#document-send-order"); |
||||
}); |
||||
}, |
||||
fail: function (e) { |
||||
console.log(e); |
||||
}, |
||||
progressall: function (e, data) { |
||||
var progress = parseInt(data.loaded / data.total * 100, 10); |
||||
$('#progress .progress-bar').css( |
||||
'width', |
||||
progress + '%' |
||||
); |
||||
} |
||||
}).prop('disabled', !$.support.fileInput) |
||||
.parent().addClass($.support.fileInput ? undefined : 'disabled'); |
||||
} |
||||
|
||||
function uploadDocumentsTeamInit() { |
||||
$("#upload-document-team").bind('fileuploadsubmit', function (e, data) { |
||||
data.formData = { |
||||
sender: $("#team-chat-form #senderTeamId").val(), |
||||
recipent: $("#team-chat-form #recipentTeamId").val(), |
||||
order: $("#team-chat-form #orderTeamId").val(), |
||||
team: $("#team-chat-form #teamId").val(), |
||||
}; |
||||
// console.log(data.formData);
|
||||
}); |
||||
|
||||
$('#upload-document-team').fileupload({ |
||||
url: '/chat/create/', |
||||
crossDomain: false, |
||||
beforeSend: function (xhr, settings) { |
||||
$('#progress .progress-bar').css( |
||||
'width', |
||||
'0%' |
||||
); |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')); |
||||
}, |
||||
dataType: 'json', |
||||
done: function (e, data) { |
||||
$.each(data.result.files, function (index, file) { |
||||
var currentValue = $("#documentSendIds").val(); |
||||
currentValue += file.id + ';'; |
||||
$("#documentSendIds").val(currentValue); |
||||
var htmlImg = '<div style="float: left"><a href="/chat/download/' + file.name + '" class="send-doc" data-id="' + file.id + '">' + file.name + '</a>' + |
||||
'<div class="remove-document" data-id="' + file.id + '" style="right:-10px;float:left;position: static;"></div></div>'; |
||||
var document_send = $(htmlImg).appendTo("#document-send"); |
||||
}); |
||||
}, |
||||
fail: function (e) { |
||||
console.log(e); |
||||
}, |
||||
progressall: function (e, data) { |
||||
var progress = parseInt(data.loaded / data.total * 100, 10); |
||||
$('#progress .progress-bar').css( |
||||
'width', |
||||
progress + '%' |
||||
); |
||||
} |
||||
}).prop('disabled', !$.support.fileInput) |
||||
.parent().addClass($.support.fileInput ? undefined : 'disabled'); |
||||
} |
||||
|
||||
function bindRemoveDocuments() { |
||||
$('.tab-content').on('click', '.remove-document', function (e) { |
||||
e.preventDefault(); |
||||
var dataId = $(this).attr('data-id'); |
||||
var _this = $(this); |
||||
$.ajax({ |
||||
url: '/api/documents/' + dataId + '/', |
||||
type: 'PATCH', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: {is_delete: true}, |
||||
dataType: 'json', |
||||
success: function (json) { |
||||
_this.parent().remove(); |
||||
// console.log(json);
|
||||
}, |
||||
error: function (e, jqxhr) { |
||||
console.log(jqxhr); |
||||
} |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
export {uploadDocumentsContactInit, uploadDocumentsOrderInit, uploadDocumentsTeamInit, bindRemoveDocuments} |
||||
@ -0,0 +1,9 @@ |
||||
write_message = {'msg': "", |
||||
'msg_time': ".strftime('%Y-%m-%d %H:%M:%S')", |
||||
'order_id': "", |
||||
'recipent_id': "", |
||||
'sender_id': "", |
||||
'sender_name': "", |
||||
'answer_type': "", |
||||
'docs_attach': "", |
||||
} |
||||
@ -0,0 +1,36 @@ |
||||
//1-approve_stages
|
||||
var approve_stages = { |
||||
"format_type": "approve_stages", |
||||
"data": { |
||||
"sender_id": "", |
||||
"recipent_id": "", |
||||
"order_id": "", |
||||
"msg": "Заказчик зарезервировал сумму для этапов " + json.stages, |
||||
} |
||||
}; |
||||
|
||||
//2-add_message_order
|
||||
var add_message_order = { |
||||
"format_type": "add_message_order", |
||||
"data": { |
||||
"sender_id": "", |
||||
"recipent_id": "", |
||||
"chat_message": "", |
||||
"order_id": "", |
||||
"document_send_links": "id;id;id", |
||||
"document_data": { |
||||
"document_links": 'links/document_link_tmpl.html(...copy)', |
||||
"document_attach_files": 'links/document_attach_file_tmpl.html(...copy)', |
||||
} |
||||
} |
||||
|
||||
}; |
||||
|
||||
//3-add_message_contact
|
||||
var add_message_contact = add_message_order; |
||||
|
||||
//4-add_message_team
|
||||
var add_message_team = add_message_order; |
||||
add_message_team["team_id"] = ""; |
||||
add_message_team["team_ids"] = "id;id;id"; |
||||
|
||||
@ -0,0 +1,28 @@ |
||||
import stage_tmpl from './templates/stage_tmpl.html' |
||||
import stage_approved_tmpl from './templates/stage_approved_tmpl.html' |
||||
import reserved_tmpl from './templates/reserved_tmpl.html' |
||||
import message_tmpl from './templates/message_tmpl.html' |
||||
import work_in_process_tmpl from './templates/work_in_process_tmpl.html' |
||||
import bntCompleteStage_tmpl from './templates/buttons/bntCompleteStage_tmpl.html' |
||||
import btnSendReview_tmpl from './templates/buttons/btnSendReview_tmpl.html' |
||||
import document_attach_file_tmpl from './templates/links/document_attach_file_tmpl.html' |
||||
import note_tmpl from './templates/note_tmpl.html' |
||||
|
||||
function loadTemplate(template_name) { |
||||
let templates = { |
||||
stage_tmpl: stage_tmpl, |
||||
stage_approved_tmpl: stage_approved_tmpl, |
||||
reserved_tmpl: reserved_tmpl, |
||||
message_tmpl: message_tmpl, |
||||
work_in_process_tmpl: work_in_process_tmpl, |
||||
bntCompleteStage_tmpl: bntCompleteStage_tmpl, |
||||
btnSendReview_tmpl: btnSendReview_tmpl, |
||||
document_attach_file_tmpl: document_attach_file_tmpl, |
||||
note_tmpl: note_tmpl, |
||||
}; |
||||
|
||||
if (!templates[template_name]) throw new Error(`Template ${template_name} does not exist`); |
||||
return templates[template_name] |
||||
} |
||||
|
||||
export {loadTemplate} |
||||
@ -0,0 +1,43 @@ |
||||
function recalculateTabsCounter() { |
||||
// let tabs = [$('#count-tab-contact'), $('#count-tab-order'), $('#count-tab-team')]
|
||||
let tabs = [$('#tab1'), $('#tab2'), $('#tab3')]; |
||||
let total_messages_count = 0; |
||||
for (let tab of tabs){ |
||||
let count_sum = Array.from((tab.find('.js-count').map((i, el)=>parseInt($(el).html())))).reduce((a, b) => a + b, 0); |
||||
let $tab_counter = $(`a[href="#${tab.attr('id')}"]`).find('.count-tab'); |
||||
$tab_counter.html(count_sum); |
||||
total_messages_count += count_sum; |
||||
// console.log($tab_counter, 'new value -->', count_sum);
|
||||
} |
||||
let $header_counter = $('.js-all-messages'); |
||||
$header_counter.html(total_messages_count); |
||||
} |
||||
|
||||
function countPlus(message, place) { |
||||
/** |
||||
* Увеличиваем счетчик соответствующий сообщению(message) |
||||
*/ |
||||
// console.log("MESSAGE = ", message);
|
||||
let $container; |
||||
if (message.answer_type == "add_message_contact"){ |
||||
$container = $(`.contact-count-${message.sender_id}`); |
||||
} else if (message.answer_type == "add_message_order"){ |
||||
$container = $(`#count-order-${message.order_id}`); |
||||
} else if (message.answer_type == "add_message_team") { |
||||
$container = $(`#count-team-${message.team_id}`); |
||||
} |
||||
// console.log("container = ", $container);
|
||||
$container.html(parseInt($container.html()) + 1); |
||||
recalculateTabsCounter(); |
||||
} |
||||
|
||||
function onClickCardWithCount($card){ |
||||
/** |
||||
* При нажатии на карточку со счетчиком новых сообщений |
||||
*/ |
||||
// console.log('Обнулем счетчик ', $card);
|
||||
$card.find('.js-count').html(0); |
||||
recalculateTabsCounter(); |
||||
} |
||||
|
||||
export {countPlus, onClickCardWithCount} |
||||
@ -0,0 +1,77 @@ |
||||
import {loadTemplate} from './loaders' |
||||
var note_tmpl = loadTemplate('note_tmpl'); |
||||
|
||||
function bindContractorNotes() { |
||||
$('#add-note-contractor').on('click', function (e) { |
||||
e.preventDefault(); |
||||
$.ajax({ |
||||
url: '/api/note/', |
||||
type: 'POST', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: $("#add-form-contractor-note").serialize(), |
||||
dataType: 'json', |
||||
success: function (json) { |
||||
// console.log(json);
|
||||
$("#add-form-contractor-note #chat2").val(""); |
||||
let li = note_tmpl({text: json.text}); |
||||
$(li).appendTo(".contractor-notes-block"); |
||||
}, |
||||
error: function (e) { |
||||
console.log('error'); |
||||
console.log(e); |
||||
} |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
function bindOrderNotes() { |
||||
$('#add-note-button').on('click', function (e) { |
||||
e.preventDefault(); |
||||
$.ajax({ |
||||
url: '/api/note/', |
||||
type: 'POST', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: $("#add-form-order-note").serialize(), |
||||
dataType: 'json', |
||||
success: function (json) { |
||||
// $("<li>" + json.text + "</li>").appendTo(".order-notes-block");
|
||||
let li = note_tmpl({text: json.text}); |
||||
$(li).appendTo(".order-notes-block"); |
||||
$("#add-form-order-note #chat2").val(""); |
||||
}, |
||||
error: function (e) { |
||||
console.log('error'); |
||||
console.log(e); |
||||
} |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
function bindTeamNotes() { |
||||
$('#add-team-note-button').on('click', function (e) { |
||||
e.preventDefault(); |
||||
$.ajax({ |
||||
url: '/api/note/', |
||||
type: 'POST', |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) |
||||
}, |
||||
data: $("#add-form-team-note").serialize(), |
||||
dataType: 'json', |
||||
success: function (json) { |
||||
$("<li>" + json.text + "</li>").appendTo(".team-notes-block"); |
||||
$("#add-form-team-note #chat2").val(""); |
||||
}, |
||||
error: function (e) { |
||||
console.log('error'); |
||||
console.log(e); |
||||
} |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
export {bindContractorNotes, bindOrderNotes, bindTeamNotes} |
||||
@ -0,0 +1,27 @@ |
||||
import {getCookie} from '../utils' |
||||
|
||||
function restoreTabFromHash() { |
||||
var currentHash = URI(location.href).hash(); |
||||
if (currentHash.indexOf("#order") == 0) { |
||||
$("a[href='#tab2']").trigger('click'); |
||||
// console.log("click on ", "#orderBlock" + currentHash.replace("#order", ""));
|
||||
let obj_id = currentHash.replace("#order", ""); |
||||
// console.log("obj_id = ", obj_id);
|
||||
if (obj_id) { |
||||
$("#orderBlock" + currentHash.replace("#order", "")).trigger('click'); |
||||
} else { |
||||
$('.order-block').first().trigger('click'); |
||||
} |
||||
|
||||
} else if (currentHash.indexOf("#user") == 0) { |
||||
$("a[href='#tab1']").trigger('click'); |
||||
} else if (currentHash.indexOf("#teamorder") == 0 || currentHash.indexOf("#myteam") == 0) { |
||||
$("a[href='#tab3']").trigger('click'); |
||||
} else { |
||||
$("a[href='#tab1']").trigger('click'); |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
export {restoreTabFromHash} |
||||
@ -0,0 +1,8 @@ |
||||
<!-- stage={} , text--> |
||||
<div style="margin-left: -27px; margin-right: -27px; text-align: center"> |
||||
<a href="#" |
||||
class="chat-button icon-complete_stage js-btnComplete" |
||||
style="padding-left: 60px;" |
||||
data-stage-id="${this.stage.id}"> ${this.text} ${this.stage.pos} |
||||
</a> |
||||
</div> |
||||
@ -0,0 +1,6 @@ |
||||
<div style="margin-left: -27px; margin-right: -27px; text-align: center" id="send-review"> |
||||
<a href="#" |
||||
class="chat-button icon-check js-btnSendReview" |
||||
style="padding-left: 10px; padding-right: 10px">ЗАКРЫТЬ ПРОЕКТ И ОСТАВИТЬ ОТЗЫВ |
||||
</a> |
||||
</div> |
||||
@ -0,0 +1,12 @@ |
||||
<!--href, text, document_id, --> |
||||
<li style="word-break: break-all;"> |
||||
<a class="file-link" href="${this.href} ">${this.text}</a> |
||||
<div class="remove-document" data-id="${this.document_id}" style="right:-10px;"></div> |
||||
</li> |
||||
|
||||
<!-- |
||||
<li style="word-break: break-all;"> |
||||
<a class="file-link" href="/chat/download/ v.file "> v.file </a> |
||||
<div class="remove-document" data-id=" v.id " style="right:-10px;"></div> |
||||
</li> |
||||
--> |
||||
@ -0,0 +1,7 @@ |
||||
<!-- href, text --> |
||||
<div> |
||||
Приложенный файл. скачать: <br> |
||||
<a href="$(this.href)"> |
||||
$(this.text) |
||||
</a> |
||||
</div> |
||||
@ -0,0 +1,7 @@ |
||||
<!--className senderName message={...}--> |
||||
<div class="col-lg-12 insetCommChat ${this.className}"> |
||||
<div class="topCommChat"> |
||||
<p class="nameCommChat">${this.senderName}</p><span>${this.message.created}</span> |
||||
</div> |
||||
<p class="textCommChat">${this.message.text}</p> |
||||
</div> |
||||
@ -0,0 +1,6 @@ |
||||
<div class="note-wrapper"> |
||||
<li> |
||||
${this.text} |
||||
</li> |
||||
<div class="remove-note" data-id="${this.note_id}" style="right:-10px;"></div> |
||||
</div> |
||||
@ -0,0 +1,5 @@ |
||||
<!--<li class="reserved"><span class="text">Сумма за этап 1.<br/> Зарезервирована</span></li> --> |
||||
<!--<li class="unreserved"><span class="text">Сумма за этап 2.<br/> Не зарезервирована</span></li> --> |
||||
<li class="${this.reserved_cls}"><span class="text">Сумма за этап ${this.stage.pos} |
||||
<br/>${this.reserved_name}</span> |
||||
</li> |
||||
@ -0,0 +1,29 @@ |
||||
<!-- this {stage_num: '...', stage_status: '...', stage: {...} --> |
||||
<div class="numberStepp box-sizing"> |
||||
<div class="review-type" style="width: 100%"> |
||||
<div class="alignleft"> |
||||
<span>ЭТАП ${this.stage_num}</span> |
||||
</div> |
||||
<div class="alignright"> |
||||
<span class="stage-status"> ${this.stage_status}</span> |
||||
</div> |
||||
<div style="clear: both;"></div> |
||||
</div> |
||||
|
||||
<div class="stage-data"> |
||||
${this.stage.name} |
||||
</div> |
||||
Результат этапа |
||||
<div class="stage-data"> |
||||
${this.stage.result} |
||||
</div> |
||||
Цена |
||||
<div class="stage-data"> |
||||
${this.stage.cost} ₽ |
||||
</div> |
||||
Срок |
||||
<div class="stage-data"> |
||||
до ${this.stage.term} |
||||
</div> |
||||
|
||||
</div> |
||||
@ -0,0 +1,29 @@ |
||||
<!-- this {stage_num: '...', form_name: '...', orderId: '...', stage: {...} --> |
||||
<div class="numberStepp box-sizing"> |
||||
<p>ЭТАП ${this.stage_num} </p> |
||||
<form class="${this.form_name} js-stage-form" data-stage-id="${(this.stage && this.stage.id) ? this.stage.id : ''}" |
||||
id="stage-form-${(this.stage && this.stage.id) ? this.stage.id : ''}"> |
||||
<label>Название</label> |
||||
<input class="form-control" type="text" name="name" |
||||
value="${(this.stage && this.stage.name) ? this.stage.name : ''}"> |
||||
<p class="error error-name"></p> |
||||
<label>Цена</label> |
||||
<input class="form-control" type="text" name="cost" |
||||
value="${(this.stage && this.stage.cost) ? this.stage.cost : ''}"> |
||||
<p class="error error-cost"></p> |
||||
<input class="form-control" name="pos" type="hidden" |
||||
value="${(this.stage && this.stage.pos) ? this.stage.pos : this.stage_num}"> |
||||
<p class="error error-pos"></p> |
||||
<input class="form-control orderStagesInput" type="hidden" name="order" |
||||
value="${this.orderId}"> |
||||
<input class="form-control" type="hidden" name="status" value="send_approve"> |
||||
<label>Срок</label> |
||||
<input class="term-picker form-control datepicker" type="text" name="term" |
||||
value="${(this.stage && this.stage.term) ? this.stage.term : ''}"> |
||||
<p class="error error-term"></p> |
||||
<label>Результат</label> |
||||
<input class="form-control" type="text" name="result" |
||||
value="${(this.stage && this.stage.result) ? this.stage.result : ''}"> |
||||
<p class="error error-result"></p> |
||||
</form> |
||||
</div> |
||||
@ -0,0 +1,10 @@ |
||||
<!-- this {stage: {...}, note_text--> |
||||
<div style="margin: 10px 0"> |
||||
В работе: ${this.stage.name} <br> |
||||
Результат этапа: ${this.stage.result} <br> |
||||
Срок сдачи: ${this.stage.term}<br> |
||||
<span class="select">${this.stage.cost}</span> р |
||||
<div class="note"> |
||||
${this.note_text} |
||||
</div> |
||||
</div> |
||||
@ -0,0 +1,6 @@ |
||||
function ws_print(...messages) { |
||||
let message = messages.join(' '); |
||||
console.log(`%c WS: ${message}`, 'background: white; color: blue'); |
||||
} |
||||
|
||||
export {ws_print} |
||||
@ -0,0 +1,114 @@ |
||||
import {loadTemplate} from './loaders' |
||||
import {countPlus} from './messageCounters' |
||||
|
||||
function getUserPlace() { |
||||
/** |
||||
* Определяем в какой закладке Чата пользователь |
||||
*/ |
||||
let hash = location.hash; |
||||
let tab, id; |
||||
|
||||
for (let str of ["user", "order", "myteam"]) { |
||||
if (hash.indexOf(`#${str}`) != -1) { |
||||
tab = str; |
||||
id = hash.replace(`#${str}`, ''); |
||||
} |
||||
} |
||||
return {tab, id} |
||||
} |
||||
|
||||
function checkMessageInPlace(message, place) { |
||||
/** |
||||
* Проверяем, направлено ли входящее сообщение на текущую вкладку пользователя |
||||
*/ |
||||
// message.answer_type=place.tab
|
||||
let eq = ['add_message_contact=user', 'add_message_order=order', 'add_message_team=myteam', 'approve_stages=order']; |
||||
// console.log([message.answer_type, place.tab].join('='));
|
||||
// console.log(message.order_id, '==', place.id, message.order_id == place.id);
|
||||
if ((eq.indexOf([message.answer_type, place.tab].join('=')) != -1) && |
||||
((message.order_id == place.id) || (message.recipent_id == place.id) || (message.sender_id == place.id) || (message.team_id == place.id))) { |
||||
|
||||
return true |
||||
} |
||||
return false |
||||
} |
||||
|
||||
function connect() { |
||||
wsConnect.then(function (_socket) { |
||||
socket = _socket; |
||||
// Onmessage in Chat page
|
||||
socket.addEventListener("message", function (event) { |
||||
var data = JSON.parse(event.data); |
||||
print.ws_print("new message on Chat page"); |
||||
console.log(", message =", data); |
||||
|
||||
let user_place = getUserPlace(); |
||||
// console.log("User place ", place.tab, place.id);
|
||||
|
||||
if (checkMessageInPlace(data, user_place)) { |
||||
console.log("Сообщение принято открытым чатом"); |
||||
let chat_container_selectors = { |
||||
"user": "#message-chat-space", |
||||
"order": "#message-chat-order-space", |
||||
"myteam": "#message-chat-team-space", |
||||
}; |
||||
let documents_container_seletors = { |
||||
"user": "#documentSpace", |
||||
"order": "#documentOrderSpace", |
||||
"myteam": "#documentTeamSpace", |
||||
}; |
||||
let $chat_container = $(chat_container_selectors[user_place.tab]); |
||||
let $documents_container = $(documents_container_seletors[user_place.tab]); |
||||
var classMessage = 'youChat'; |
||||
var senderName = 'Вы'; |
||||
if (data.sender_id != userId) { |
||||
senderName = data.sender_name; |
||||
classMessage = ''; |
||||
} |
||||
if (data.is_system){ |
||||
senderName = 'Системное'; |
||||
classMessage = 'systemChat' |
||||
} |
||||
|
||||
let chat_message = loadTemplate('message_tmpl')({ |
||||
className: classMessage, |
||||
senderName: senderName, |
||||
message: {created: data.msg_time, text: data.msg} |
||||
}); |
||||
$chat_container.append(chat_message); |
||||
$chat_container.scrollTop($chat_container.prop("scrollHeight")); |
||||
|
||||
$documents_container.append(data.docs_attach); |
||||
|
||||
if (data.answer_type == 'approve_stages') { |
||||
window.chatController.statesController.redraw(); |
||||
} |
||||
|
||||
} else { |
||||
console.log("Сообщение учтено счетчиком"); |
||||
countPlus(data, user_place) |
||||
} |
||||
|
||||
}); |
||||
|
||||
socket.addEventListener("close", function () { |
||||
console.error("Connection Lost"); |
||||
connect(); |
||||
}); |
||||
|
||||
socket.send_message = function (messageData) { |
||||
console.log('send message -->', messageData); |
||||
socket.send(JSON.stringify(messageData)); |
||||
}; |
||||
|
||||
socket.send_stages_approve = function (messageData) { |
||||
// TODO: Пометить сообщения как "системные"
|
||||
socket.send(JSON.stringify(messageData)); |
||||
}; |
||||
}); |
||||
wsConnect.catch(function (reason) { |
||||
console.error("Server is not available", reason) |
||||
}) |
||||
} |
||||
|
||||
export {connect} |
||||
@ -0,0 +1,63 @@ |
||||
import {ChatPageController} from './chat/ChatContractorPageController' |
||||
import { |
||||
bindOrders, |
||||
bindArbitrationSend, |
||||
bindOnTabs, |
||||
bindUserContacts, |
||||
bindGetUserMessages, |
||||
bindTeams, |
||||
bindDeleteContact |
||||
} from './chat/BINDS' |
||||
|
||||
import { |
||||
uploadDocumentsContactInit, |
||||
uploadDocumentsOrderInit, |
||||
uploadDocumentsTeamInit, |
||||
bindRemoveDocuments |
||||
} from './chat/documents' |
||||
|
||||
import {bindContractorNotes, bindOrderNotes, bindTeamNotes} from './chat/notes' |
||||
|
||||
import {restoreTabFromHash} from './chat/parts' |
||||
|
||||
import {bindArchiveProjects} from './chat/archiveProjects' |
||||
|
||||
import {chatContactsInit, chatOrdersInit, chatTeamsInit} from './chat/chats' |
||||
import {connect} from './chat/wsChatConnect' |
||||
|
||||
window.connect = connect; |
||||
window.socket = undefined; |
||||
|
||||
$(function () { |
||||
bindArbitrationSend(); |
||||
window.onhashchange = function (e) { |
||||
$('a[data-toggle="tab"][href="#' + location.hash.slice(1) + '"]').trigger("click"); |
||||
}; |
||||
window.chatController = new ChatPageController(); |
||||
bindOrders(); |
||||
bindTeams(); |
||||
bindOnTabs(); |
||||
bindUserContacts(); |
||||
bindGetUserMessages(); |
||||
bindArchiveProjects(); |
||||
bindDeleteContact(); |
||||
|
||||
// Chats
|
||||
chatContactsInit(); |
||||
chatOrdersInit(); |
||||
chatTeamsInit(); |
||||
|
||||
//Documents
|
||||
uploadDocumentsContactInit(); |
||||
uploadDocumentsOrderInit(); |
||||
uploadDocumentsTeamInit(); |
||||
bindRemoveDocuments(); |
||||
|
||||
//Notes
|
||||
bindContractorNotes(); |
||||
bindOrderNotes(); |
||||
bindTeamNotes(); |
||||
|
||||
//restore
|
||||
restoreTabFromHash(); |
||||
}); |
||||
@ -0,0 +1,47 @@ |
||||
import {ChatPageController} from './chat/ChatCustomerPageController' |
||||
import { |
||||
bindOrders, |
||||
bindArbitrationSend, |
||||
bindOnTabs, |
||||
bindUserContacts, |
||||
bindGetUserMessages, |
||||
bindDeleteContact |
||||
} from './chat/BINDS' |
||||
|
||||
import {restoreTabFromHash} from './chat/parts' |
||||
|
||||
import {chatContactsInit, chatOrdersInit} from './chat/chats' |
||||
import {connect} from './chat/wsChatConnect' |
||||
|
||||
import {bindArchiveProjects} from './chat/archiveProjects' |
||||
|
||||
window.connect = connect; |
||||
window.socket = undefined; |
||||
|
||||
$(function () { |
||||
$('body').on('focus', ".term-picker", function () { |
||||
$(this).datepicker({ |
||||
minDate: 0, |
||||
}); |
||||
}); |
||||
|
||||
bindArbitrationSend(); |
||||
window.onhashchange = function (e) { |
||||
// console.log("Change Hash!!! ", 'a[data-toggle="tab"][href="#' + location.hash.slice(1) + '"]');
|
||||
$('a[data-toggle="tab"][href="#' + location.hash.slice(1) + '"]').trigger("click"); |
||||
}; |
||||
|
||||
window.chatController = new ChatPageController(); |
||||
bindOrders(); |
||||
bindOnTabs(); |
||||
restoreTabFromHash(); |
||||
bindUserContacts(); |
||||
bindGetUserMessages(); |
||||
bindArchiveProjects(); |
||||
bindDeleteContact(); |
||||
|
||||
//Chats
|
||||
chatContactsInit(); |
||||
chatOrdersInit(); |
||||
|
||||
}); |
||||
@ -0,0 +1,5 @@ |
||||
import {ws_print} from './chat/utils_debug' |
||||
|
||||
// DEBUG
|
||||
window.print = {}; |
||||
window.print.ws_print = ws_print; |
||||
@ -0,0 +1,20 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.9.7 on 2017-01-31 13:09 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('chat', '0014_newmessage'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AddField( |
||||
model_name='message', |
||||
name='is_system', |
||||
field=models.BooleanField(default=False), |
||||
), |
||||
] |
||||
@ -0,0 +1,325 @@ |
||||
@import "base/variavles" |
||||
@import "modules/mods" |
||||
@import "base/colors" |
||||
|
||||
%icons |
||||
margin-left: 0px |
||||
display: inline-flex |
||||
align-items: center |
||||
&:before |
||||
content: '' |
||||
display: inline-block |
||||
width: 20px |
||||
height: 20px |
||||
background-size: cover |
||||
position: relative |
||||
left: -5px |
||||
|
||||
.contractor-notes-block, .team-notes-block, .order-notes-block |
||||
text-align: left |
||||
padding-left: 45px |
||||
font-family: Arial, Verdana, Helvetica, sans-serif |
||||
|
||||
ol |
||||
li |
||||
display: list-item |
||||
list-style: decimal inside |
||||
white-space: nowrap |
||||
overflow: hidden |
||||
text-overflow: ellipsis |
||||
max-width: 180px |
||||
|
||||
.note-wrapper |
||||
position: relative |
||||
|
||||
.modal-header |
||||
text-align: center |
||||
|
||||
// Системное сообщение |
||||
.systemChat |
||||
background-color: #ffe9ed |
||||
|
||||
.review-type |
||||
.alignleft |
||||
float: left |
||||
//width: 33% |
||||
text-align: left |
||||
|
||||
.aligncenter |
||||
float: left |
||||
//width: 33% |
||||
text-align: center |
||||
|
||||
.alignright |
||||
float: right |
||||
//width: 33% |
||||
text-align: right |
||||
|
||||
.chat-button |
||||
transition: all 0.3s |
||||
width: 100% |
||||
background-color: #f1f1f1 |
||||
text-transform: uppercase |
||||
color: #373737 |
||||
//display: inline-block |
||||
font-family: "pfdintextcomppro-regular", sans-serif |
||||
font-size: 18px |
||||
letter-spacing: 1px |
||||
margin-bottom: 5px |
||||
&:visited, &:link |
||||
color: #373737 |
||||
&:hover |
||||
box-shadow: 0 0 15px rgba(0, 0, 0, 0.8) |
||||
transform: scale(1.04) |
||||
//color: #7e7e7e |
||||
padding: 25px 30px |
||||
&.icon-hand |
||||
@extend %icons |
||||
&:before |
||||
width: 25px |
||||
height: 25px |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_hands_gray.png") |
||||
size: 24px 24px |
||||
repeat: no-repeat |
||||
&.icon-books |
||||
@extend %icons |
||||
&:before |
||||
width: 30px |
||||
height: 25px |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_books.png") |
||||
size: 30px 25px |
||||
repeat: no-repeat |
||||
&.icon-print |
||||
@extend %icons |
||||
&:before |
||||
width: 30px |
||||
height: 25px |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_print.png") |
||||
size: 30px 25px |
||||
repeat: no-repeat |
||||
&.icon-change |
||||
@extend %icons |
||||
&:before |
||||
width: 20px |
||||
height: 24px |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_edit.png") |
||||
size: 20px 24px |
||||
repeat: no-repeat |
||||
&.icon-credit_card |
||||
@extend %icons |
||||
&:before |
||||
width: 25px |
||||
height: 28px |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_credit_card_gray.png") |
||||
size: 25px 28px |
||||
repeat: no-repeat |
||||
&.icon-arbitration |
||||
@extend %icons |
||||
&:before |
||||
width: 25px |
||||
height: 28px |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_arbitration.png") |
||||
size: 25px 28px |
||||
repeat: no-repeat |
||||
|
||||
&.icon-complete_stage |
||||
@extend %icons |
||||
&:before |
||||
width: 25px |
||||
height: 28px |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_complete_stage.png") |
||||
size: 25px 28px |
||||
repeat: no-repeat |
||||
&.icon-check |
||||
@extend %icons |
||||
&:before |
||||
width: 25px |
||||
height: 25px |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_check.png") |
||||
size: 25px 25px |
||||
repeat: no-repeat |
||||
|
||||
a.btn.btn-send |
||||
transition: all 0.3s |
||||
padding: 5px 25px !important |
||||
background-color: white |
||||
border: 1px solid #BEBEBE |
||||
border-radius: 40px |
||||
&:hover |
||||
transform: scale(1.04) |
||||
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2) |
||||
&.icon-send |
||||
@extend %icons |
||||
&:before |
||||
width: 25px |
||||
height: 25px |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_arrow_gray.png") |
||||
size: 24px 24px |
||||
repeat: no-repeat |
||||
|
||||
.icon-protect |
||||
display: inline-block |
||||
@extend %icons |
||||
&:before |
||||
width: 18px |
||||
height: 20px |
||||
left: 0 |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_protect.png") |
||||
size: 18px 20px |
||||
repeat: no-repeat |
||||
|
||||
.icon-note |
||||
display: inline-block |
||||
@extend %icons |
||||
&:before |
||||
width: 30px |
||||
height: 20px |
||||
left: 0 |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_pen_black.png") |
||||
size: 20px 20px |
||||
repeat: no-repeat |
||||
|
||||
.stage-data |
||||
padding-left: 3px |
||||
background-color: #f1f1f1 |
||||
color: #8c8c8c |
||||
font-size: 12px |
||||
|
||||
.stage-status |
||||
font-style: italic |
||||
color: #5e5e5e |
||||
|
||||
.stages-paid |
||||
li |
||||
padding-left: 25px |
||||
margin-top: 15px |
||||
.text |
||||
padding-left: 10px |
||||
.reserved |
||||
//display: inline-block |
||||
@extend %icons |
||||
&:before |
||||
width: 25px |
||||
height: 25px |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_coins_green.png") |
||||
size: 25px 25px |
||||
repeat: no-repeat |
||||
|
||||
.unreserved |
||||
//display: inline-block |
||||
color: #FD010E |
||||
@extend %icons |
||||
&:before |
||||
width: 25px |
||||
height: 25px |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_coins_red.png") |
||||
size: 25px 25px |
||||
repeat: no-repeat |
||||
.closed |
||||
//display: inline-block |
||||
@extend %icons |
||||
&:before |
||||
width: 25px |
||||
height: 25px |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_coins_gray.png") |
||||
size: 25px 25px |
||||
repeat: no-repeat |
||||
|
||||
.border |
||||
border-top: 1px solid #CFCFCF |
||||
position: relative |
||||
height: 20px |
||||
margin-top: 10px |
||||
.bird |
||||
position: absolute |
||||
border: 30px solid transparent |
||||
border-top: 12px solid #CFCFCF |
||||
top: 0 |
||||
left: 50% |
||||
margin-left: -30px |
||||
&:before |
||||
content: '' |
||||
display: block |
||||
position: absolute |
||||
border: 30px solid transparent |
||||
border-top: 12px solid white |
||||
top: -13px |
||||
left: 50% |
||||
margin-left: -30px |
||||
|
||||
.select |
||||
color: #FD010E |
||||
|
||||
.note |
||||
color: #FD010E |
||||
padding-top: 10px |
||||
font-size: 12px |
||||
|
||||
//Team |
||||
.team-block |
||||
.team-user-list |
||||
overflow-y: auto |
||||
display: -webkit-box |
||||
line-height: 16px |
||||
max-height: 64px |
||||
hyphens: none |
||||
|
||||
.max-rows |
||||
overflow-y: hidden |
||||
display: -webkit-box |
||||
line-height: 16px |
||||
max-height: 32px |
||||
|
||||
.icon-hand |
||||
@extend %icons |
||||
&:before |
||||
width: 25px |
||||
height: 25px |
||||
background: |
||||
image: url("#{$static}/img/icons/icon_hands_gray.png") |
||||
size: 24px 24px |
||||
repeat: no-repeat |
||||
|
||||
a |
||||
cursor: crosshair |
||||
&:visited |
||||
color: #333333 |
||||
&:hover |
||||
color: black |
||||
|
||||
a.docs |
||||
&-more, &-less |
||||
color: #{map_get($component_colors, select)} |
||||
cursor: pointer |
||||
&:hover |
||||
color: darken(#FD010E, 25%) |
||||
box-shadow: none |
||||
|
||||
&-more:before |
||||
content: '...Развернуть' |
||||
&-less:before |
||||
content: '...Cвернуть' |
||||
|
||||
.remove-note |
||||
position: absolute |
||||
width: 11px |
||||
height: 11px |
||||
background: url('../img/delDoc.png') no-repeat center |
||||
background-size: cover |
||||
right: -20px !important |
||||
top: 2px |
||||
cursor: pointer |
||||
@ -0,0 +1,50 @@ |
||||
<p>Прикрепленные документы</p> |
||||
<ul id="{{ class }}"></ul> |
||||
<div style="text-align: center"> |
||||
<a class="docs-more js-more" style="display: none"></a> |
||||
</div> |
||||
<div style="margin-left: -27px; margin-right: -27px;"> |
||||
<a href="{% url 'common:create' %}" |
||||
class="chat-button icon-print" |
||||
style="padding: 25px 10px" |
||||
>Распечатать с помощью ресурса</a> |
||||
</div> |
||||
|
||||
<script> |
||||
document.addEventListener('DOMContentLoaded', function () { |
||||
var $documents_container = $('#' + '{{ class }}'); |
||||
var $more = $documents_container.parent().find('.js-more'); |
||||
{# console.log("more -->", $more);#} |
||||
$documents_container.bind('DOMSubtreeModified', function (e) { |
||||
{# console.log('Documents container change!!!');#} |
||||
var $elements = $documents_container.children('li'); |
||||
var num_elements = $elements.length; |
||||
if (num_elements > 2) { |
||||
$more.show(); |
||||
console.log("more class = ", $more.attr('class')); |
||||
if ($more.hasClass('docs-more')) { |
||||
$elements.slice(0, 2).show(); |
||||
$elements.slice(2).hide(); |
||||
} |
||||
} else { |
||||
$elements.show(); |
||||
$more.hide(); |
||||
} |
||||
}); |
||||
$more.on('click', function (e) { |
||||
e.preventDefault(); |
||||
var $elements = $documents_container.children('li'); |
||||
if ($more.hasClass('docs-more')) { |
||||
$elements.show(); |
||||
$more.removeClass('docs-more'); |
||||
$more.addClass('docs-less'); |
||||
} else { |
||||
$elements.slice(0, 2).show(); |
||||
$elements.slice(2).hide(); |
||||
$more.removeClass('docs-less'); |
||||
$more.addClass('docs-more'); |
||||
} |
||||
{# $more.toggleClass('docs-more', 'docs-less')#} |
||||
}) |
||||
}) |
||||
</script> |
||||
@ -0,0 +1,47 @@ |
||||
{% load user_tags %} |
||||
<div class="orderBlock box-sizing order-block" data-team-id=" |
||||
{% if order.team %}{{ order.team.pk }}{% else %}0{% endif %}" |
||||
data-project-id="{{ order.project.id }}" |
||||
id="orderBlock{{ order.id }}" |
||||
{% if request.user.is_contractor %} |
||||
data-recipent-id="{{ order.project.customer.pk }}" |
||||
{% else %} |
||||
{% if order.contractor %} |
||||
data-recipent-id="{{ order.contractor.pk }}" |
||||
{% else %} |
||||
data-recipent-id="{{ order.team.owner.pk }}" |
||||
{% endif %} |
||||
{% endif %} |
||||
data-id="{{ order.id }}" |
||||
data-secure-deal="{% if order.secure %}true{% else %}false{% endif %}" |
||||
data-order-name="{{ order.project.name }}"> |
||||
|
||||
<span class="dimovChat"></span> |
||||
<div class="titleOB mod-align-center"> |
||||
{{ order }} |
||||
<span class="js-count count-order" id="count-order-{{ order.id }}"> |
||||
{% get_new_count_for_order request.user order.id %} |
||||
</span> |
||||
{% if order.secure %} |
||||
<span class="icon-protect"></span> |
||||
{% endif %} |
||||
</div> |
||||
|
||||
<div class="hideOBB"> |
||||
<p class="pOB"> |
||||
{# <span style="display: none;"#} |
||||
{# class="order-count-{{ order.id }}">{% get_new_count_for_order request.user order.id %}#} |
||||
{# </span>#} |
||||
<span>Исполнитель:</span> |
||||
{% if order.contractor %} |
||||
{{ order.contractor.get_full_name }} |
||||
{% else %} |
||||
{{ order.team.name }} |
||||
{% endif %} |
||||
</p> |
||||
<a href="#" class="linkChat11 full-order-info"> |
||||
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> |
||||
Полное описание заказа |
||||
</a> |
||||
</div> |
||||
</div> |
||||
@ -0,0 +1,61 @@ |
||||
{% load user_tags %} |
||||
<div class="team-block orderBlock box-sizing" id="teamMyBlock{{ yteam.pk }}" |
||||
data-team-id="{{ yteam.pk }}"> |
||||
<span class="dimovChat"></span> |
||||
<div class="titleOB mod-align-center"> |
||||
<div class="max-rows" style="display: inline-block"> |
||||
{{ yteam }} {% if yteam.owner.pk == request.user.pk %} |
||||
[<a href="{% url 'users:team-profile' pk=yteam.pk %}">Моя группа</a>] {% endif %} |
||||
</div> |
||||
<div class="mod-align-center-inline"> |
||||
<span class="js-count count-order" id="count-team-{{ yteam.pk }}">{% get_new_count_for_team request.user yteam.id %}</span> |
||||
{% if yteam.orders.count > 0 %}<span class="icon-hand"></span> {% endif %} |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="hideOBB disTab"> |
||||
<div class="pOB"> |
||||
{# <span style="display: none;"#} |
||||
{# class="team-count-{{ yteam.id }}">#} |
||||
{# {% get_new_count_for_team request.user yteam.id %}#} |
||||
{# </span>#} |
||||
<span>Владелец группы:</span> [{{ yteam.owner.username }}] |
||||
</div> |
||||
<div class="pDB"> |
||||
<div> |
||||
<strong>Всего участников в группе</strong> <span class="select">{{ yteam.contractors.count }}</span> |
||||
</div> |
||||
<div> |
||||
{# //FIXME: Изменить Участники группы --> Сейчас на сайте#} |
||||
{# <strong>Сейчас на сайте:</strong>#} |
||||
<strong>Участники группы:</strong> |
||||
<div class="team-user-list" id="team-users-online"> |
||||
{# user-1, user-2, user-3, user-4, user-5, user-6, user-7, user-8, user-9,#} |
||||
{# user-1, user-2, user-3, user-4, user-5, user-6, user-7, user-8, user-9,#} |
||||
{# user-1, user-2, user-3, user-4, user-5, user-6, user-7, user-8, user-9,#} |
||||
{# user-1, user-2, user-3, user-4, user-5, user-6, user-7, user-8, user-9,#} |
||||
{% for tuser in yteam.contractors.all %} |
||||
<a href="{% url 'users:contractor-profile' pk=tuser.pk %}">{{ tuser.username }}</a> |
||||
{% endfor %} |
||||
</div> |
||||
</div> |
||||
<div> |
||||
<strong>Заказов от имени группы</strong> <span class="select">{{ yteam.orders.count }}</span> |
||||
</div> |
||||
</div> |
||||
|
||||
<p style="display: none;"> |
||||
{% if request.user.pk != torder.team.owner.pk %} |
||||
<span class="team-chat-user" |
||||
data-id="{{ yteam.owner.pk }}">{{ yteam.owner.username }}</span> |
||||
{% endif %} |
||||
{% for tuser in yteam.contractors.all %} |
||||
{% if request.user.pk != tuser.pk %} |
||||
<span class="team-chat-user" |
||||
data-id="{{ tuser.pk }}">{{ tuser.username }} </span> |
||||
{% endif %} |
||||
{% endfor %} |
||||
</p> |
||||
|
||||
</div> |
||||
</div> |
||||
@ -0,0 +1,156 @@ |
||||
<script> |
||||
var socket; |
||||
function getOpenOrdersList() { |
||||
$.ajax({ |
||||
url: '/api/orders?status=created', |
||||
type: 'get', |
||||
success: function (data) { |
||||
$.each(data.results, function (key, value) { |
||||
open_order_list.push(parseInt(value.id)) |
||||
}) |
||||
} |
||||
}) |
||||
} |
||||
function message_count_plus() { |
||||
console.log('Message +1'); |
||||
var all_messages = $('.js-all-messages'); |
||||
var count = parseInt(all_messages.html()) + 1; |
||||
if (count > 99) count = '99+'; |
||||
all_messages.html(count); |
||||
} |
||||
|
||||
var wsConnect; |
||||
function WSConnection() { |
||||
'use strict'; |
||||
this.socket = {}; |
||||
} |
||||
|
||||
WSConnection.prototype.connect = function (url) { |
||||
'use strict'; |
||||
return new Promise((resolve, reject) => { |
||||
var self = this; |
||||
|
||||
this.socket = new WebSocket(url); |
||||
// Пользователь на странице Чата(Переговорная) |
||||
var inChatPage = true; |
||||
|
||||
this.socket.onopen = function () { |
||||
print.ws_print('Socket open'); |
||||
resolve(this); |
||||
try { |
||||
connect(); |
||||
} catch (ReferenceError) { |
||||
print.ws_print('No additional WS connect'); |
||||
inChatPage = false; |
||||
} |
||||
}; |
||||
|
||||
this.socket.onmessage = function (event) { |
||||
print.ws_print("New message: " + JSON.parse(event.data)); |
||||
var notificationData = JSON.parse(event.data); |
||||
{# if (open_order_list.indexOf(parseInt(notificationData.order_id)) != -1) {#} |
||||
{# message_count_plus('#my_office');#} |
||||
{# }#} |
||||
{# message_count_plus('.js-all-messages');#} |
||||
var outMessage = ""; |
||||
if (notificationData.answer_type == 'add_message_contact') { |
||||
outMessage += "<a href='/chat/?user_id=" + notificationData.sender_id + "'>" + notificationData.msg + "<a>"; |
||||
} else if ((notificationData.answer_type == 'approve_stages') || (notificationData.answer_type == 'add_message_order')) { |
||||
outMessage += "<a href='/chat/#order" + notificationData.order_id + "'>" + notificationData.msg + "<a>"; |
||||
} |
||||
if (!inChatPage) message_count_plus(); |
||||
print.ws_print("Вам пришло новое сообщение!", outMessage); |
||||
if (userId != notificationData.sender_id) { |
||||
$.jGrowl("Вам пришло новое сообщение!<br />" + outMessage, {life: 15000}); |
||||
} |
||||
}; |
||||
|
||||
this.socket.add_message = function (messageData) { |
||||
print.ws_print("add Message"); |
||||
self.socket.send(JSON.stringify(messageData)) |
||||
}; |
||||
|
||||
this.socket.onerror = function (error) { |
||||
print.ws_print('Error: ' + error); |
||||
reject(error); |
||||
}; |
||||
|
||||
this.socket.onclose = function (event) { |
||||
print.ws_print("Websocket closed: " + JSON.stringify(event)); |
||||
// TODO: Сдеалть реконнект#} |
||||
setTimeout(function () { |
||||
console.log("reconnect to WS"); |
||||
wsConnect = new WSConnection().connect(url); |
||||
}, 2000); |
||||
|
||||
}; |
||||
}); |
||||
}; |
||||
|
||||
|
||||
{# var SocketHandlerMain = function (userId) {#} |
||||
{# var domain = '{{ request.META.HTTP_HOST }}';#} |
||||
{# var port = '{{ request.META.SERVER_PORT }}';#} |
||||
{# var queryString = '{{ request.get_full_path }}';#} |
||||
{##} |
||||
{# if ((queryString.indexOf('/chat') != 0) && (queryString.indexOf('/users/contractor-office/work-projects') != 0)) {#} |
||||
{# domain = domain.replace(':' + port, ':8888');#} |
||||
{# if (window.location.protocol == 'https:') {#} |
||||
{# var ws = "wss://";#} |
||||
{# } else {#} |
||||
{# var ws = "ws://";#} |
||||
{# }#} |
||||
{##} |
||||
{# var url = ws + domain + '/chat/' + userId + '/';#} |
||||
{# var sock = new WebSocket(url);#} |
||||
{# sock.onopen = function () {#} |
||||
{# print.ws_print('Socket open');#} |
||||
{# };#} |
||||
{##} |
||||
{# sock.onmessage = function (event) {#} |
||||
{# var notificationData = JSON.parse(event.data);#} |
||||
{# if (open_order_list.indexOf(parseInt(notificationData.order_id)) != -1) {#} |
||||
{# message_count_plus('#my_office');#} |
||||
{# }#} |
||||
{# message_count_plus('.js-all-messages');#} |
||||
{# var outMessage = "";#} |
||||
{# if (notificationData.answer_type == 'add_message_contact') {#} |
||||
{# outMessage += "<a href='/chat/?user_id=" + notificationData.sender_id + "'>" + notificationData.msg + "<a>";#} |
||||
{# } else if ((notificationData.answer_type == 'approve_stages') || (notificationData.answer_type == 'add_message_order')) {#} |
||||
{# outMessage += "<a href='/chat/#order" + notificationData.order_id + "'>" + notificationData.msg + "<a>";#} |
||||
{# }#} |
||||
{# print.ws_print("Вам пришло новое сообщение!", outMessage);#} |
||||
{# $.jGrowl("Вам пришло новое сообщение!<br />" + outMessage, {life: 15000});#} |
||||
{# };#} |
||||
{##} |
||||
{# this.send_message = function (messageData) {#} |
||||
{# print.ws_print("send message", messageData);#} |
||||
{# sock.send(JSON.stringify(messageData));#} |
||||
{# };#} |
||||
{# }#} |
||||
{# };#} |
||||
|
||||
var userId = '{{ request.user.pk }}'; |
||||
|
||||
if (userId) { |
||||
var domain = '{{ request.META.HTTP_HOST }}'; |
||||
var port = '{{ request.META.SERVER_PORT }}'; |
||||
domain = domain.replace(':' + port, ':8888'); |
||||
if (window.location.protocol == 'https:') { |
||||
var ws = "wss://"; |
||||
} else { |
||||
var ws = "ws://"; |
||||
} |
||||
var url = ws + domain + '/chat/' + userId + '/'; |
||||
$(function () { |
||||
console.log('Create WS connection'); |
||||
wsConnect = new WSConnection().connect(url); |
||||
wsConnect.then(function (_socket) { |
||||
socket = _socket; |
||||
}) |
||||
}); |
||||
|
||||
{# var open_order_list = [];#} |
||||
{# getOpenOrdersList();#} |
||||
} |
||||
</script> |
||||
@ -0,0 +1,20 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.9.7 on 2017-01-31 13:09 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('projects', '0053_portfolio_specializations'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='stage', |
||||
name='status', |
||||
field=models.CharField(choices=[('not_agreed', 'Не согласован'), ('send_approve', 'На согласовании'), ('agreed', 'Согласовано'), ('cancel_approve', 'Исполнитель отказался'), ('in_process', 'В процессе'), ('completed', 'Завершен'), ('closed', 'Закрыт')], default='not_agreed', max_length=30), |
||||
), |
||||
] |
||||