http 9 years ago
parent
commit
556aa772d0
  1. 6
      abonapp/models.py
  2. 17
      accounts_app/views.py
  3. 1
      ip_pool/models.py
  4. 1
      ip_pool/views.py
  5. 7027
      static/css/bootstrap.min.css
  6. 72
      static/css/custom.css
  7. 709
      static/js/bootstrap.min.js
  8. 201
      static/js/my.js
  9. 2
      taskapp/context_proc.py
  10. 9
      taskapp/forms.py
  11. 8
      taskapp/handle.sh
  12. 38
      taskapp/models.py
  13. 1
      taskapp/urls.py
  14. 79
      taskapp/views.py
  15. 6
      templates/accounts/acc_list.html
  16. 14
      templates/accounts/ext.htm
  17. 43
      templates/accounts/profile_chgroup.html
  18. 7
      templates/base.html
  19. 20
      templates/taskapp/add_edit_task.html
  20. 12
      templates/taskapp/tasklist.html
  21. 13
      templates/taskapp/tasklist_active.html
  22. 12
      templates/taskapp/tasklist_all.html
  23. 13
      templates/taskapp/tasklist_finish.html
  24. 13
      templates/taskapp/tasklist_own.html
  25. 43
      templates/taskapp/view.html

6
abonapp/models.py

@ -5,7 +5,6 @@ from django.shortcuts import get_object_or_404
from django.utils import timezone
from django.utils.datetime_safe import datetime
from django.db import models
from django.conf import settings
from django.core.validators import DecimalValidator
from agent import get_TransmitterClientKlass, NetExcept
@ -29,6 +28,7 @@ class LogicError(Exception):
class AbonGroup(models.Model):
title = models.CharField(max_length=127, unique=True)
profiles = models.ManyToManyField(UserProfile, related_name='abon_groups')
class Meta:
db_table = 'abonent_groups'
@ -40,7 +40,7 @@ class AbonGroup(models.Model):
class AbonLog(models.Model):
abon = models.ForeignKey('Abon')
amount = models.FloatField(default=0.0)
author = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='+')
author = models.ForeignKey(UserProfile, related_name='+')
comment = models.CharField(max_length=128)
date = models.DateTimeField(auto_now_add=True)
@ -310,7 +310,7 @@ class InvoiceForPayment(models.Model):
comment = models.CharField(max_length=128)
date_create = models.DateTimeField(auto_now_add=True)
date_pay = models.DateTimeField(blank=True, null=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='+')
author = models.ForeignKey(UserProfile, related_name='+')
def __unicode__(self):
return "%s -> %d $" % (self.abon.username, self.amount)

17
accounts_app/views.py

@ -6,7 +6,7 @@ from django.shortcuts import render, redirect, get_object_or_404, resolve_url
from django.template.context_processors import csrf
from django.http import Http404
from django.contrib.auth.models import Group, Permission
from accounts_app.forms import SetupPerms
from abonapp.models import AbonGroup
from photo_app.models import Photo
from models import UserProfile
@ -81,15 +81,16 @@ def profile_show(request, id=0):
@mydefs.only_admins
def chgroup(request, uid):
usr = get_object_or_404(UserProfile, id=uid)
usergroups = usr.groups.all()
othergroups = filter(lambda g: g not in usergroups, Group.objects.all())
# Group.objects.exclude(user__in=usergroups)
if request.method == 'POST':
ag = request.POST.getlist('ag')
usr.abon_groups.clear()
usr.abon_groups.add(*[int(d) for d in ag])
usr.save()
abongroups = AbonGroup.objects.all()
return render(request, 'accounts/profile_chgroup.html', {
'uid': uid,
'userprofile': usr,
'allgroups': othergroups,
'usergroups': usergroups
'abongroups': abongroups
})
@ -215,12 +216,10 @@ def acc_list(request):
# @permission_required('accounts_app.change_userprofile')
def perms(request, id):
profile = get_object_or_404(UserProfile, id=id)
frm = SetupPerms()
own_permissions = UserProfile.get_all_permissions(profile)
return render(request, 'accounts/settings/permissions.html', {
'uid': id,
'form': frm,
'own_permissions': own_permissions
})

1
ip_pool/models.py

@ -33,7 +33,6 @@ class IpPoolItemManager(models.Manager):
sql_strs = map(lambda tip: r"(%d)" % tip, range(start_ip, end_ip + 1))
sql = r'INSERT INTO ip_pool_ippoolitem (ip) VALUES %s' % r",".join(sql_strs)
print sql
cursor = connection.cursor()
cursor.execute(sql)

1
ip_pool/views.py

@ -10,7 +10,6 @@ import mydefs
@mydefs.only_admins
def home(request):
pools = IpPoolItem.objects.get_pools()
print pools
if pools:
pools = map(lambda ip: (mydefs.int2ip(ip[0]), mydefs.int2ip(ip[1]), ip[2]), pools)

7027
static/css/bootstrap.min.css
File diff suppressed because it is too large
View File

72
static/css/custom.css

@ -31,23 +31,15 @@ body {
/* Hide for mobile, show later */
.sidebar {
display: none;
}
@media (min-width: 768px) {
.sidebar {
position: fixed;
top: 39px;
bottom: 0;
left: 0;
z-index: 1000;
display: block;
padding: 20px;
overflow-x: hidden;
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
background-color: #303840;
border-right: 1px solid #eee;
}
background-color: #303840;
overflow-x: hidden;
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
position: fixed;
display: block;
top: 39px;
bottom: 0;
padding: 20px;
border-right: 1px solid #eee;
}
/* Sidebar navigation */
@ -57,6 +49,9 @@ body {
margin-left: -20px;
border-top: 1px solid #576a7d;
}
@media (max-width: 767px){
.nav-sidebar{margin-right: -15px;}
}
.nav-sidebar > li > a {
padding-right: 20px;
@ -167,3 +162,46 @@ td.btn-group {
.selectajax button.selectajax-btn{
text-align: left;
}
/*
* Off Canvas
* --------------------------------------------------
*/
@media screen and (max-width: 767px) {
.row-offcanvas {
position: relative;
-webkit-transition: all .25s ease-out;
-moz-transition: all .25s ease-out;
transition: all .25s ease-out;
}
.row-offcanvas-left {
left: 0;
}
.row-offcanvas-left
.sidebar-offcanvas {
left: -50%; /* 6 columns */
}
.row-offcanvas-left.active {
left: 50%; /* 6 columns */
}
.sidebar-offcanvas {
position: absolute;
top: 0;
width: 50%; /* 6 columns */
}
}
button[data-toggle=offcanvas]{
position: absolute;
left: 0;
top: 194px;
z-index: 1;
height: 42px;
background-color: #44596b;
border: 0;
}

709
static/js/bootstrap.min.js
File diff suppressed because it is too large
View File

201
static/js/my.js

@ -1,120 +1,125 @@
function errShow(errContent) {
//window.history.back();
//window.history.back();
$('#modContent').html('<div class="modal-header warning">\
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>\
<h4 class="modal-title" id="myModalLabel"><span class="glyphicon glyphicon-warning-sign"></span>\
Ошибка\
$('#modContent').html('<div class="modal-header warning">\
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>\
<h4 class="modal-title" id="myModalLabel"><span class="glyphicon glyphicon-warning-sign"></span>\
Ошибка\
</h4>\
</div>\
<div class="modal-body">' +
errContent
+ '</div>\
errContent
+ '</div>\
<div class="modal-footer">\
<button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button>\
<button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button>\
</div>');
$('#modFrm').modal();
$('#modFrm').modal();
}
$(document).ajaxError(function (ev, jqXHR, ajaxSettings, thrownError) {
//loaderShow(false);
errShow(jqXHR.status + ': ' + jqXHR.statusText);
//loaderShow(false);
errShow(jqXHR.status + ': ' + jqXHR.statusText);
});
// SelectAjax
(function ($) {
$.fn.selectajax = function (opt) {
var settings = $.extend( {
url : '/api'
}, opt);
var selectbtn = this.children('button.selectajax-btn');
var selectinp = this.children('input[type=text].selectajax-inp');
var selecthid = this.children('input[type=hidden].selectajax-hid');
var selectul = this.children('ul.selectajax-ul');
var selectajax_click = function(){
var a = $(this).children('a');
var hr = a.attr('href');
var tx = a.text();
selecthid.val(hr.substr(1));
console.debug(tx);
selectbtn.text(tx).removeClass('hidden');
selectinp.addClass('hidden').val(tx);
};
var refresh = function(){
$.getJSON(settings.url, {'s': this.value}, function (r) {
selectul.empty();
r.forEach(function (o) {
var li = $('<li><a href="#' + o.id + '">' + o.name + ": " + o.fio + '</a></li>');
selectul.append(li);
li.on('click', selectajax_click)
});
});
};
selectinp.on('keyup', refresh).on('focusin',refresh);
selectbtn.on('click',function(){
selectinp.removeClass('hidden');
$(this).addClass('hidden');
selectinp.focus().trigger('click.bs.dropdown');
return false;
});
selectul.children().on('click', selectajax_click);
};
$.fn.selectajax = function (opt) {
var settings = $.extend( {
url : '/api'
}, opt);
var selectbtn = this.children('button.selectajax-btn');
var selectinp = this.children('input[type=text].selectajax-inp');
var selecthid = this.children('input[type=hidden].selectajax-hid');
var selectul = this.children('ul.selectajax-ul');
var selectajax_click = function(){
var a = $(this).children('a');
var hr = a.attr('href');
var tx = a.text();
selecthid.val(hr.substr(1));
console.debug(tx);
selectbtn.text(tx).removeClass('hidden');
selectinp.addClass('hidden').val(tx);
};
var refresh = function(){
$.getJSON(settings.url, {'s': this.value}, function (r) {
selectul.empty();
r.forEach(function (o) {
var li = $('<li><a href="#' + o.id + '">' + o.name + ": " + o.fio + '</a></li>');
selectul.append(li);
li.on('click', selectajax_click)
});
});
};
selectinp.on('keyup', refresh).on('focusin',refresh);
selectbtn.on('click',function(){
selectinp.removeClass('hidden');
$(this).addClass('hidden');
selectinp.focus().trigger('click.bs.dropdown');
return false;
});
selectul.children().on('click', selectajax_click);
};
})(jQuery);
$(document).ready(function () {
// ajax tabs
$('.nav-tabs a').on('show.bs.tab', function (e) {
var ct = $(e.target).attr('href');
var remoteUrl = $(this).attr('data-tab-remote');
if (remoteUrl !== '') {
$(ct).load(remoteUrl);
}
});
// Live html5 image preview
if (window.File && window.FileReader && window.FileList && window.Blob) {
$('input[type=file].live_review').on('change', function () {
var reader = new FileReader();
var img = $('img[alt=ava]')[0];
reader.readAsDataURL(this.files[0]);
reader.onload = function (e) {
img.src = e.target.result;
}
});
} else {
console.warn("Ваш браузер не поддерживает FileAPI");
}
// Validate inputs of form
$('input.form-control[pattern]').keyup(function () {
var pr = $(this).closest('.form-group-sm,.form-group');
pr.removeClass('has-success');
pr.removeClass('has-error');
pr.find('.form-control-feedback').remove();
if ($(this)[0].checkValidity()) {
pr.addClass('has-success');
$(this).after('<span class="glyphicon glyphicon-ok form-control-feedback"></span>');
} else {
pr.addClass('has-error');
$(this).after('<span class="glyphicon glyphicon-remove form-control-feedback"></span>');
}
});
$('div.selectajax').selectajax({
url: '/abons/api/abon_filter'
});
// ajax tabs
$('.nav-tabs a').on('show.bs.tab', function (e) {
var ct = $(e.target).attr('href');
var remoteUrl = $(this).attr('data-tab-remote');
if (remoteUrl !== '') {
$(ct).load(remoteUrl);
}
});
// Live html5 image preview
if (window.File && window.FileReader && window.FileList && window.Blob) {
$('input[type=file].live_review').on('change', function () {
var reader = new FileReader();
var img = $('img[alt=ava]')[0];
reader.readAsDataURL(this.files[0]);
reader.onload = function (e) {
img.src = e.target.result;
}
});
} else {
var t = "Ваш браузер не поддерживает FileAPI";
console.warn(t);
alert(t);
}
// Validate inputs of form
$('input.form-control[pattern]').keyup(function () {
var pr = $(this).closest('.form-group-sm,.form-group');
pr.removeClass('has-success');
pr.removeClass('has-error');
pr.find('.form-control-feedback').remove();
if ($(this)[0].checkValidity()) {
pr.addClass('has-success');
$(this).after('<span class="glyphicon glyphicon-ok form-control-feedback"></span>');
} else {
pr.addClass('has-error');
$(this).after('<span class="glyphicon glyphicon-remove form-control-feedback"></span>');
}
});
$('div.selectajax').selectajax({
url: '/abons/api/abon_filter'
});
$('[data-toggle=offcanvas]').click(function () {
$('.row-offcanvas').toggleClass('active');
});
});

2
taskapp/context_proc.py

@ -6,7 +6,7 @@ from taskapp.models import Task
def get_active_tasks_count(request):
tasks_count = 0
if not isinstance(request.user, AnonymousUser):
tasks_count = Task.objects.filter(recipient=request.user, state='S').count()
tasks_count = Task.objects.filter(recipients=request.user, state='S').count()
return {
'tasks_count': tasks_count
}

9
taskapp/forms.py

@ -2,25 +2,20 @@
from datetime import datetime, timedelta
from django import forms
from models import Task
from accounts_app.models import UserProfile
class TaskFrm(forms.ModelForm):
recipient = forms.ModelChoiceField(
queryset=UserProfile.objects.filter(is_admin=True),
widget=forms.Select(attrs={'class': 'form-control', 'required':''})
)
class Meta:
model = Task
exclude = ['time_of_create', 'author']
exclude = ['time_of_create', 'author', 'recipients', 'device']
widgets = {
'descr': forms.TextInput(attrs={
'placeholder': u'Краткое описание',
'class': "form-control",
'required': ''
}),
'device': forms.Select(attrs={'class': 'form-control', 'required':''}),
#'device': forms.Select(attrs={'class': 'form-control', 'required':''}),
'priority': forms.Select(attrs={'class': 'form-control'}),
'state': forms.Select(attrs={'class': 'form-control'}),
'out_date': forms.DateInput(attrs={'class': 'form-control'}),

8
taskapp/handle.sh

@ -2,7 +2,7 @@
FIRST="$1" # $1 - 'start' or 'change'
FAIL_MODE="$2" # $2 - mode
DEVICE_IP="$3" # $3 - dev ip
RESERVED="$3" # $3 - (dev ip)
STATE="$4" # $4 - state
AUTHOR_TEL="$5" # $5 - author telephone
RECIPIENT_TEL="$6" # $6 - recipient telephone
@ -21,6 +21,12 @@ else
text="Изм"
fi
# Если сигнал самому себе то молчим
if [[ "$AUTHOR_TEL" == "$RECIPIENT_TEL" ]]
then
exit
fi
# Если задача 'На выполнении' то молчим
if [[ "$STATE" == "C" ]]
then

38
taskapp/models.py

@ -8,7 +8,7 @@ from django.db import models
from django.conf import settings
from abonapp.models import Abon
from devapp.models import Device
#from devapp.models import Device
from djing.settings import BASE_DIR
@ -41,20 +41,17 @@ TASK_TYPES = (
class Task(models.Model):
descr = models.CharField(max_length=128)
recipient = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='+')
recipients = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='them_task')
author = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='+')
device = models.ForeignKey(Device, related_name='dev')
#device = models.ForeignKey(Device, related_name='dev')
priority = models.CharField(max_length=1, choices=TASK_PRIORITIES, default=TASK_PRIORITIES[2][0])
out_date = models.DateField(null=True, blank=True, default=datetime.now() + timedelta(days=7))
out_date = models.DateField(null=True, blank=True, default=datetime.now() + timedelta(days=3))
time_of_create = models.DateTimeField(auto_now_add=True)
state = models.CharField(max_length=1, choices=TASK_STATES, default=TASK_STATES[0][0])
attachment = models.ImageField(upload_to='task_attachments/%Y.%m.%d', blank=True, null=True)
mode = models.CharField(max_length=2, choices=TASK_TYPES, default=TASK_TYPES[0][0])
abon = models.ForeignKey(Abon, on_delete=models.SET_NULL, null=True, blank=True, related_name='+')
def __unicode__(self):
return self.descr
class Meta:
db_table = 'task'
ordering = ('-id',)
@ -105,19 +102,20 @@ def task_handler(sender, instance, **kwargs):
act_type=b'e',
who=instance.author
)
call(['%s/handle.sh' % cur_dir,
first_param, # start or change
instance.get_mode_display(), # mode - Характер поломки
instance.device.ip_address, # ip устройства
instance.state, # Состояние задачи (новая|выполнена)
instance.author.telephone, # Телефон автора задачи
instance.recipient.telephone, # Телефон ответственного монтажника
instance.descr, # Описание задачи
# Если указан абонент то инфа о нём
instance.abon.fio if instance.abon else '<нет фио>',
instance.abon.address if instance.abon else '<нет адреса>',
instance.abon.telephone if instance.abon else '<нет телефона>',
group_name]) # Имя группы абонента
for recipient in instance.recipients.all():
call(['%s/handle.sh' % cur_dir,
first_param, # start or change
instance.get_mode_display(), # mode - Характер поломки
'N', # (ip устройства) Зарезервировано
instance.state, # Состояние задачи (новая|выполнена)
instance.author.telephone, # Телефон автора задачи
recipient.telephone, # Телефон ответственного монтажника
instance.descr, # Описание задачи
# Если указан абонент то инфа о нём
instance.abon.fio if instance.abon else '<нет фио>',
instance.abon.address if instance.abon else '<нет адреса>',
instance.abon.telephone if instance.abon else '<нет телефона>',
group_name]) # Имя группы абонента
models.signals.post_save.connect(task_handler, sender=Task)

1
taskapp/urls.py

@ -5,6 +5,7 @@ import views
urlpatterns = [
url(r'^$', views.home, name='home'),
url(r'^(?P<task_id>\d+)$', views.view, name='view'),
url(r'^(?P<task_id>\d+)/edit$', views.task_add_edit, name='edit'),
url(r'^(?P<task_id>\d+)/delete$', views.task_delete, name='delete'),
url(r'^(?P<task_id>\d+)/fin$', views.task_finish, name='finish'),

79
taskapp/views.py

@ -2,7 +2,7 @@
from django.contrib.auth.decorators import login_required, permission_required
from django.shortcuts import render, redirect, get_object_or_404
from abonapp.models import Abon
from datetime import date
from models import Task
from mydefs import pag_mn, only_admins, safe_int
from forms import TaskFrm
@ -11,7 +11,7 @@ from forms import TaskFrm
@login_required
@only_admins
def home(request):
tasks = Task.objects.filter(recipient=request.user, state='S') # Новые задачи
tasks = Task.objects.filter(recipients=request.user, state='S') # Новые задачи
# filter
# dir, field = order_helper(request)
@ -28,7 +28,7 @@ def home(request):
@login_required
@only_admins
def active_tasks(request):
tasks = Task.objects.filter(recipient=request.user, state='C') # На выполнении
tasks = Task.objects.filter(recipients=request.user, state='C') # На выполнении
tasks = pag_mn(request, tasks)
return render(request, 'taskapp/tasklist_active.html', {
'tasks': tasks
@ -38,7 +38,7 @@ def active_tasks(request):
@login_required
@only_admins
def finished_tasks(request):
tasks = Task.objects.filter(recipient=request.user, state='F') # Выполненные
tasks = Task.objects.filter(recipients=request.user, state='F') # Выполненные
tasks = pag_mn(request, tasks)
return render(request, 'taskapp/tasklist_finish.html', {
'tasks': tasks
@ -58,7 +58,7 @@ def own_tasks(request):
@login_required
@only_admins
def my_tasks(request):
tasks = Task.objects.filter(recipient=request.user) # Все задачи
tasks = Task.objects.filter(recipients=request.user) # Все задачи
tasks = pag_mn(request, tasks)
return render(request, 'taskapp/tasklist.html', {
'tasks': tasks
@ -78,52 +78,73 @@ def all_tasks(request):
@permission_required('taskapp.can_delete_task')
def task_delete(request, task_id):
task = get_object_or_404(Task, id=task_id)
if request.user != task.recipient:
# нельзя удалить назначенную мне задачу
if request.user not in task.recipients.all():
task.delete()
return redirect('taskapp:home')
@login_required
@only_admins
def view(request, task_id):
tsk = get_object_or_404(Task, id=task_id)
toc = date(tsk.time_of_create.year, tsk.time_of_create.month, tsk.time_of_create.day)
time_diff = tsk.out_date - toc
return render(request, 'taskapp/view.html', {
'task': tsk,
'time_diff': time_diff
})
@login_required
@permission_required('taskapp.can_change_task')
def task_add_edit(request, task_id=0):
task_id = safe_int(task_id)
warntext = ''
uid = request.GET.get('uid')
selected_abon = None
frm = TaskFrm()
# чтоб при добавлении сразу был выбран исполнитель
frm_recipient_id = safe_int(request.GET.get('rp'))
#frm_recipient_id = safe_int(request.GET.get('rp'))
if task_id == 0:
tsk = Task()
tsk.author = request.user
else:
tsk = get_object_or_404(Task, id=task_id)
frm = TaskFrm(instance=tsk)
selected_abon = tsk.abon
if uid:
selected_abon = get_object_or_404(Abon, username=str(uid))
if request.method == 'POST':
tsk.author = request.user
frm = TaskFrm(request.POST, request.FILES, instance=tsk)
if frm.is_valid():
frm.save()
return redirect('taskapp:home')
else:
warntext = u'Исправте ошибки'
else:
if task_id == 0:
try:
uid = int(uid or 0)
selected_abon = None if uid == 0 else get_object_or_404(Abon, username=str(uid))
frm = TaskFrm(initial={
'recipient': frm_recipient_id,
'abon': selected_abon
})
except ValueError:
warntext=u'Передаваемый логин абонента должен состоять только из цифр'
frm = TaskFrm(initial={
'recipient': frm_recipient_id
})
task_instance = frm.save()
# получим абонента, выбранного в форме
selected_abon = task_instance.abon
if selected_abon:
# получаем аккаунты назначенные на группу выбранного абонента
profiles = selected_abon.group.profiles.filter(is_active=True).filter(is_admin=True)
# если нашли кого-нибудь
if profiles.count() > 0:
# выбираем их id в базе
profile_ids = [prof.id for prof in profiles]
# добавляем найденных работников в задачу
task_instance.recipients.add(*profile_ids)
# окончательно сохраняемся
task_instance.save()
return redirect('taskapp:home')
else:
warntext=u'Нет ответственных за группу, в которой находится выбранный абонент'
else:
warntext=u'Нужно выбрать абонента'
else:
frm = TaskFrm(instance=tsk)
selected_abon = tsk.abon
warntext = u'Ошибка в полях формы в задаче'
return render(request, 'taskapp/add_edit_task.html', {
'warntext': warntext,

6
templates/accounts/acc_list.html

@ -33,15 +33,15 @@
<td>{% if usr.email %}<a href="mailto:{{ usr.email }}">{{ usr.email }}{% else %}
Нету{% endif %}</a></td>
<td class="btn-group">
<a href="{% url 'acc_app:appoint_task' usr.id %}" class="btn btn-sm btn-default"
<a href="#" class="btn btn-sm btn-default disabled"
title="Дать задание">
<span class="glyphicon glyphicon-tasks"></span>
</a>
<a href="{% url 'privmsg:send_message' %}?a={{ usr.id }}" class="btn btn-sm btn-info"
<a href="{% url 'privmsg:send_message' %}?a={{ usr.id }}" class="btn btn-sm btn-info disabled"
title="Отправить сообщение">
<span class="glyphicon glyphicon-envelope"></span>
</a>
<a href="#" class="btn btn-sm btn-danger">
<a href="#" class="btn btn-sm btn-danger disabled">
<span class="glyphicon glyphicon-remove"></span>
</a>
</td>

14
templates/accounts/ext.htm

@ -21,7 +21,7 @@
<a href="{% url 'acc_app:setup_info' %}" class="btn btn-primary btn-sm" role="button">
<span class="glyphicon glyphicon-edit"></span> Редактировать</a>
{% endif %}
<a href="{% url 'taskapp:add' %}?rp={{ userprofile.id }}" class="btn btn-default btn-sm" role="button">
<a href="#" class="btn btn-default btn-sm disabled" role="button">
<span class="glyphicon glyphicon-star-empty"></span> Дать задачу</a>
</div>
</div>
@ -30,15 +30,15 @@
<div class="col-sm-9">
<h3>{{ userprofile.username|default:"&lt;Нет ника&gt;" }}</h3>
<ul class="nav nav-tabs">
<li class="active">
<a href="#livetab_content" data-tab-remote="{% url 'acc_app:other_profile' uid %}" role="tab"
data-toggle="tab">
{% url 'acc_app:other_profile' uid as profile_url %}
<li{% if profile_url == request.path %} class="active"{% endif %}>
<a href="{{ profile_url }}">
Администратор
</a>
</li>
<li>
<a href="#livetab_content" data-tab-remote="{% url 'acc_app:profile_setup_group' uid %}" role="tab"
data-toggle="tab">
{% url 'acc_app:profile_setup_group' uid as profilegroups_url %}
<li{% if profilegroups_url == request.path %} class="active"{% endif %}>
<a href="{{ profilegroups_url }}">
Группы
</a>
</li>

43
templates/accounts/profile_chgroup.html

@ -1,34 +1,23 @@
{% extends request.is_ajax|yesno:'nullcont.htm,accounts/ext.htm' %}
{% block content %}
<legend>Принадлежность аккаунта группам</legend>
<form action="{% url 'acc_app:profile_permissions' userprofile.id %}" method="post" role="form">{% csrf_token %}
<div class="form-group">
<label for="sel_left">Доступные группы</label>
<select name="allgroups" multiple id="sel_left" class="form-group">
{% for gr in allgroups %}
<option value="{{ gr.id }}">{{ gr.name }}</option>
{% endfor %}
</select>
<legend>Ответственность администратора к группам абонентов</legend>
<form action="{% url 'acc_app:profile_setup_group' userprofile.id %}" method="post" role="form">{% csrf_token %}
{% for ag in abongroups %}
<div class="checkbox">
<label>
{% if userprofile in ag.profiles.all %}
<input name="ag" type="checkbox" value="{{ ag.id }}" checked/>
{% else %}
<input name="ag" type="checkbox" value="{{ ag.id }}"/>
{% endif %}
{{ ag.title }}
</label>
</div>
{% endfor %}
<div class="btn-group">
<input type="submit" class="btn btn-primary" value="Сохранить"> <input type="reset" class="btn btn-default" value="Сбросить">
</div>
<ul class="form-group">
<li><a href="javascript:chooser_select('sel_left','sel_right');" class="btn btn-sm btn-default">
<span class="glyphicon glyphicon-chevron-right"></span>
</a></li>
<li><a href="javascript:chooser_select('sel_right','sel_left');" class="btn btn-sm btn-default">
<span class="glyphicon glyphicon-chevron-left"></span>
</a></li>
</ul>
<div class="form-group">
<label for="sel_right">Группы пользователя</label>
<select name="ingroups" multiple id="sel_right" class="form-group">
{% for gr in usergroups %}
<option value="{{ gr.id }}">{{ gr.name }}</option>
{% endfor %}
</select>
</div>
<br/>
<input type="submit" value="Сохранить"> <input type="reset" value="Сбросить">
</form>
{% endblock %}

7
templates/base.html

@ -81,10 +81,10 @@
<div class="container-fluid">
<div class="row">
<div class="row row-offcanvas row-offcanvas-left">
<!-- Left menu -->
<div class="col-sm-2 sidebar">
<div class="col-sm-2 sidebar sidebar-offcanvas" role="navigation">
<div class="row profile_img">
<div class="col-sm-5">
@ -163,6 +163,9 @@
<!-- Main content -->
<div class="col-sm-10 col-sm-offset-2 main">
<p class="pull-left visible-xs">
<button type="button" data-toggle="offcanvas"></button>
</p>
{% block main %}{% endblock %}

20
templates/taskapp/add_edit_task.html

@ -21,10 +21,10 @@
<div class="panel-body">
{% if task_id %}
<form role="form" action="{% url 'taskapp:edit' task_id %}"
<form role="form" action="{% url 'taskapp:edit' task_id %}" method="post" enctype="multipart/form-data">
{% else %}
<form role="form" action="{% url 'taskapp:add' %}"
{% endif %} method="post" enctype="multipart/form-data">
<form role="form" action="{% url 'taskapp:add' %}" method="post" enctype="multipart/form-data">
{% endif %}
{% csrf_token %}<input type="hidden" name="MAX_FILE_SIZE" value="409600"/>
<div class="form-group">
@ -35,22 +35,14 @@
{{ form.descr }}{{ form.descr.errors }}
</div>
</div>
<div class="form-group">
<label for="id_recipient">Ответственный за выполнение задачи</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
{{ form.recipient }}{{ form.recipient.errors }}
</div>
</div>
<div class="form-group">
<!--<div class="form-group">
<label for="id_device">С каким устройством связано</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-hdd"></span></span>
{{ form.device }}{{ form.device.errors }}
{ { form.device }}{ { form.device.errors }}
</div>
</div>
</div>-->
<div class="form-group">
<label for="id_mode">Характер поломки</label>

12
templates/taskapp/tasklist.html

@ -6,13 +6,11 @@
<thead>
<tr>
<th>#</th>
<th class="col-sm-2">Пару слов..</th>
<th class="col-sm-1">Кому назначена</th>
<th class="col-sm-4">Пару слов..</th>
<th class="col-sm-1">Кто назначил</th>
<th class="col-sm-1">Характер поломки</th>
<th class="col-sm-1">Состояние</th>
<th class="col-sm-1">Приоритет</th>
<th class="col-sm-1">Устройство</th>
<th class="col-sm-1">Дата создания</th>
<th class="col-sm-1">Приложение</th>
<th class="col-sm-2" colspan="3">Действия</th>
@ -30,14 +28,12 @@
{% else %}
<tr>{% endif %}
<td>{{ task.id }}</td>
<td><a href="{% url 'taskapp:view' task.id %}" target="_blank">{{ task.id }}</a></td>
<td>{{ task.descr }}</td>
<td><a href="{% url 'acc_app:other_profile' task.recipient.id %}" title="{{ task.recipient.get_full_name }}">{{ task.recipient.username }}</a></td>
<td><a href="{% url 'acc_app:other_profile' task.author.id %}" title="{{ task.author.get_full_name }}">{{ task.author.username }}</a></td>
<td>{{ task.get_mode_display }}</td>
<td>{{ task.get_state_display }}</td>
<td>{{ task.get_priority_display }}</td>
<td><a href="{% url 'devapp:view' task.device.id %}" target="_blank">{{ task.device.ip_address }}</a></td>
<td>{{ task.time_of_create|date:'d N yг H:i:s' }}</td>
<td>{% if task.attachment %}<a href="{{ task.attachment.url }}" target="_blank">{{ task.attachment.name }}</a>{% else %}&horbar;{% endif %}</td>
<td colspan="3" class="btn-group btn-group-justified">
@ -56,13 +52,13 @@
</tr>
{% empty %}
<tr>
<td colspan="13">Список пуст</td>
<td colspan="11">Список пуст</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="13">
<td colspan="11">
{% include 'taskapp/footer_btns.html' %}
</td>
</tr>

13
templates/taskapp/tasklist_active.html

@ -6,13 +6,11 @@
<thead>
<tr>
<th>#</th>
<th class="col-sm-2">Пару слов..</th>
<th class="col-sm-1">Кому назначена</th>
<th class="col-sm-4">Пару слов..</th>
<th class="col-sm-1">Кто назначил</th>
<th class="col-sm-1">Характер поломки</th>
<th class="col-sm-1">Состояние</th>
<th class="col-sm-1">Приоритет</th>
<th class="col-sm-1">Устройство</th>
<th class="col-sm-1">Дата создания</th>
<th class="col-sm-1">Приложение</th>
<th class="col-sm-2" colspan="3">Действия</th>
@ -30,16 +28,13 @@
{% else %}
<tr>{% endif %}
<td>{{ task.id }}</td>
<td><a href="{% url 'taskapp:view' task.id %}" target="_blank">{{ task.id }}</a></td>
<td>{{ task.descr }}</td>
<td><a href="{% url 'acc_app:other_profile' task.recipient.id %}"
title="{{ task.recipient.get_full_name }}">{{ task.recipient.username }}</a></td>
<td><a href="{% url 'acc_app:other_profile' task.author.id %}"
title="{{ task.author.get_full_name }}">{{ task.author.username }}</a></td>
<td>{{ task.get_mode_display }}</td>
<td>{{ task.get_state_display }}</td>
<td>{{ task.get_priority_display }}</td>
<td><a href="{% url 'devapp:view' task.device.id %}" target="_blank">{{ task.device.ip_address }}</a></td>
<td>{{ task.time_of_create|date:'d N yг H:i:s' }}</td>
<td>{% if task.attachment %}<a href="{{ task.attachment.url }}" target="_blank">{{ task.attachment.name }}</a>{% else %}&horbar;{% endif %}</td>
<td colspan="3" class="btn-group">
@ -60,13 +55,13 @@
</tr>
{% empty %}
<tr>
<td colspan="13">Список пуст</td>
<td colspan="11">Список пуст</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="13">
<td colspan="11">
{% include 'taskapp/footer_btns.html' %}
</td>
</tr>

12
templates/taskapp/tasklist_all.html

@ -23,13 +23,11 @@
<thead>
<tr>
<th>#</th>
<th class="col-sm-2">Пару слов..</th>
<th class="col-sm-1">Кому назначена</th>
<th class="col-sm-4">Пару слов..</th>
<th class="col-sm-1">Кто назначил</th>
<th class="col-sm-1">Характер поломки</th>
<th class="col-sm-1">Состояние</th>
<th class="col-sm-1">Приоритет</th>
<th class="col-sm-1">Устройство</th>
<th class="col-sm-1">Дата создания</th>
<th class="col-sm-1">Приложение</th>
<th class="col-sm-2" colspan="3">Действия</th>
@ -47,14 +45,12 @@
{% else %}
<tr>{% endif %}
<td>{{ task.id }}</td>
<td><a href="{% url 'taskapp:view' task.id %}" target="_blank">{{ task.id }}</a></td>
<td>{{ task.descr }}</td>
<td><a href="{% url 'acc_app:other_profile' task.recipient.id %}" title="{{ task.recipient.get_full_name }}">{{ task.recipient.username }}</a></td>
<td><a href="{% url 'acc_app:other_profile' task.author.id %}" title="{{ task.author.get_full_name }}">{{ task.author.username }}</a></td>
<td>{{ task.get_mode_display }}</td>
<td>{{ task.get_state_display }}</td>
<td>{{ task.get_priority_display }}</td>
<td><a href="{% url 'devapp:view' task.device.id %}" target="_blank">{{ task.device.ip_address }}</a></td>
<td>{{ task.time_of_create|date:'d N yг H:i:s' }}</td>
<td>{% if task.attachment %}<a href="{{ task.attachment.url }}" target="_blank">{{ task.attachment.name }}</a>{% else %}&horbar;{% endif %}</td>
<td colspan="3" class="btn-group btn-group-justified">
@ -67,13 +63,13 @@
</tr>
{% empty %}
<tr>
<td colspan="13">Список пуст</td>
<td colspan="12">Список пуст</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="13">
<td colspan="12">
{% include 'taskapp/footer_btns.html' %}
</td>
</tr>

13
templates/taskapp/tasklist_finish.html

@ -6,13 +6,11 @@
<thead>
<tr>
<th>#</th>
<th class="col-sm-2">Пару слов..</th>
<th class="col-sm-1">Кому назначена</th>
<th class="col-sm-4">Пару слов..</th>
<th class="col-sm-1">Кто назначил</th>
<th class="col-sm-1">Характер поломки</th>
<th class="col-sm-1">Состояние</th>
<th class="col-sm-1">Приоритет</th>
<th class="col-sm-1">Устройство</th>
<th class="col-sm-1">Дата создания</th>
<th class="col-sm-1">Приложение</th>
<th class="col-sm-2" colspan="3">Действия</th>
@ -30,16 +28,13 @@
{% else %}
<tr>{% endif %}
<td>{{ task.id }}</td>
<td><a href="{% url 'taskapp:view' task.id %}" target="_blank">{{ task.id }}</a></td>
<td>{{ task.descr }}</td>
<td><a href="{% url 'acc_app:other_profile' task.recipient.id %}"
title="{{ task.recipient.get_full_name }}">{{ task.recipient.username }}</a></td>
<td><a href="{% url 'acc_app:other_profile' task.author.id %}"
title="{{ task.author.get_full_name }}">{{ task.author.username }}</a></td>
<td>{{ task.get_mode_display }}</td>
<td>{{ task.get_state_display }}</td>
<td>{{ task.get_priority_display }}</td>
<td><a href="{% url 'devapp:view' task.device.id %}" target="_blank">{{ task.device.ip_address }}</a></td>
<td>{{ task.time_of_create|date:'d N yг H:i:s' }}</td>
<td>{% if task.attachment %}<a href="{{ task.attachment.url }}" target="_blank">{{ task.attachment.name }}</a>{% else %}&horbar;{% endif %}</td>
<td colspan="3" class="btn-group">
@ -53,13 +48,13 @@
</tr>
{% empty %}
<tr>
<td colspan="13">Список пуст</td>
<td colspan="11">Список пуст</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="13">
<td colspan="11">
{% include 'taskapp/footer_btns.html' %}
</td>
</tr>

13
templates/taskapp/tasklist_own.html

@ -6,12 +6,10 @@
<thead>
<tr>
<th>#</th>
<th class="col-sm-4">Пару слов..</th>
<th class="col-sm-1">Кому назначена</th>
<th class="col-sm-6">Пару слов..</th>
<th class="col-sm-1">Характер поломки</th>
<th class="col-sm-1">Состояние</th>
<th class="col-sm-1">Приоритет</th>
<th class="col-sm-1">Устройство</th>
<th class="col-sm-1">Дата создания</th>
<th class="col-sm-1">Приложение</th>
<th class="col-sm-1">Действия</th>
@ -29,14 +27,11 @@
{% else %}
<tr>{% endif %}
<td>{{ task.id }}</td>
<td><a href="{% url 'taskapp:view' task.id %}" target="_blank">{{ task.id }}</a></td>
<td>{{ task.descr }}</td>
<td><a href="{% url 'acc_app:other_profile' task.recipient.id %}"
title="{{ task.recipient.get_full_name }}">{{ task.recipient.username }}</a></td>
<td>{{ task.get_mode_display }}</td>
<td>{{ task.get_state_display }}</td>
<td>{{ task.get_priority_display }}</td>
<td><a href="{% url 'devapp:view' task.device.id %}" target="_blank">{{ task.device.ip_address }}</a></td>
<td>{{ task.time_of_create|date:'d N yг H:i:s' }}</td>
<td>{% if task.attachment %}<a href="{{ task.attachment.url }}" target="_blank">{{ task.attachment.name }}</a>{% else %}&horbar;{% endif %}</td>
<td class="btn-group">
@ -50,13 +45,13 @@
</tr>
{% empty %}
<tr>
<td colspan="10">Все ваши задачи выполнены</td>
<td colspan="8">Все ваши задачи выполнены</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="10">
<td colspan="8">
{% include 'taskapp/footer_btns.html' %}
</td>
</tr>

43
templates/taskapp/view.html

@ -0,0 +1,43 @@
{% extends request.is_ajax|yesno:'bajax.html,base.html' %}
{% block main %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'taskapp:home' %}">Задачи</a></li>
<li class="active">#{{ task.id }}</li>
</ol>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Описание задачи</h3>
</div>
<div class="panel-body">
<p>Описание: {{ task.descr }}</p>
Исполнители:
<ul>
{% for recipient in task.recipients.all %}
<li><a href="{% url 'acc_app:other_profile' recipient.id %}" target="_blank">{{ recipient.get_full_name }}</a></li>
{% endfor %}
</ul>
Задача действительна до {{ task.out_date|date:'d E Y' }}<br>
Дата создания {{ task.time_of_create|date:'d E Y' }}<br>
Времени осталось {{ time_diff }}<br>
Тип задачи: {{ task.get_mode_display }}<br>
Абонент
{% if task.abon %}
<a href="{% url 'abonapp:abon_home' task.abon.group.id task.abon.id %}" target="_blank">{{ task.abon.get_full_name }}</a>
{% else %}
<i>&lt;Не выбран&gt;</i>
{% endif %}<br>
{% if task.attachment %}
Приложение:
<a href="{{ task.attachment.url }}" class="thumbnail" target="_blank">
<img src="{{ task.attachment.url }}">
</a>
{% endif %}
</div>
</div>
{% endblock %}
Loading…
Cancel
Save