mirror of https://github.com/raiots/TasksManager
add: chart of work load for each member in department & millions of bugs.
This commit is contained in:
parent
3d08ffce71
commit
d7359e3ea8
|
@ -62,6 +62,13 @@ class TaskAdmin(ImportExportModelAdmin):
|
|||
else:
|
||||
return qs.filter(department=request.user.department)
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
mvDict = dict(request.POST)
|
||||
print(len(mvDict['related_task-0-sub_executor']))
|
||||
obj.related_task__sub_executor_count = int(len(mvDict['related_task-0-sub_executor']))
|
||||
super().save_model(request, obj, form, change)
|
||||
|
||||
|
||||
list_display = (
|
||||
'task_property', 'task_id', 'task_topic', 'task_origin', 'aim_value', 'deadline', 'duty_group', 'principal',
|
||||
'leader', 'task_note',
|
||||
|
@ -124,9 +131,9 @@ class TodoAdmin(ImportExportModelAdmin):
|
|||
(None, {
|
||||
'fields': [
|
||||
'related_task', 'todo_topic', 'todo_note', 'deadline', 'duty_group', 'main_executor', 'sub_executor',
|
||||
'predict_work', 'evaluate_factor',
|
||||
'sub_executor_count', 'predict_work', 'evaluate_factor', 'real_work'
|
||||
],
|
||||
'description': 'aaa'
|
||||
'description': ''
|
||||
}),
|
||||
|
||||
(None, {
|
||||
|
@ -157,6 +164,7 @@ class TodoAdmin(ImportExportModelAdmin):
|
|||
# raw_id_fields = ("sub_executor",)
|
||||
search_fields = ('todo_topic',)
|
||||
ordering = ('related_task', )
|
||||
readonly_fields = [ "attachment"]
|
||||
|
||||
def approval_state(self, obj):
|
||||
return format_html('<span style="color:{};">{}</span>', 'green', obj.approval)
|
||||
|
@ -191,6 +199,17 @@ class TodoAdmin(ImportExportModelAdmin):
|
|||
else:
|
||||
return False
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
# 这一行代码写了一个晚上呜呜! 解决了当保存时,无法从未保存的数据中获取协办人数的问题!
|
||||
mvDict = dict(request.POST)
|
||||
# dicts = request.POST
|
||||
# print(dicts)
|
||||
# for key, values in dicts:
|
||||
# print(key, values)
|
||||
# obj.user = request.user
|
||||
obj.sub_executor_count = int(len(mvDict['sub_executor']))
|
||||
super().save_model(request, obj, form, change)
|
||||
|
||||
# 增加批量操作按钮
|
||||
actions = ['bulk_action']
|
||||
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import time
|
||||
|
||||
from django.db import models
|
||||
from django.http import request
|
||||
|
||||
from apps.users.models import User, MyGroup, QualityMark, TaskProperty, Department
|
||||
|
||||
|
||||
|
@ -18,8 +22,9 @@ class Todo(models.Model):
|
|||
main_executor = models.ForeignKey(User, related_name='main_executor', on_delete=models.CASCADE,
|
||||
verbose_name='承/督办人', blank=True, null=True)
|
||||
sub_executor = models.ManyToManyField(User, related_name='sub_executor', verbose_name='协办人', blank=True)
|
||||
sub_executor_count = models.CharField('协办人数', max_length=32)
|
||||
related_task = models.ForeignKey('Task', related_name='related_task', on_delete=models.CASCADE, verbose_name='年度任务')
|
||||
predict_work = models.DecimalField('预计工作量', max_digits=5, decimal_places=1, blank=True, null=True)
|
||||
predict_work = models.DecimalField('预计工作量', default=0, max_digits=5, decimal_places=1, blank=False)
|
||||
evaluate_factor = models.DecimalField('折算系数', max_digits=5, decimal_places=1, blank=True, default='1')
|
||||
maturity = models.CharField(
|
||||
verbose_name='成熟度',
|
||||
|
@ -28,17 +33,17 @@ class Todo(models.Model):
|
|||
('0%', '0%'),
|
||||
('10%', '10%'),
|
||||
('50%', '50%'),
|
||||
('70%', '70%'),
|
||||
('90%', '90%'),
|
||||
('100%', '100%')
|
||||
),
|
||||
blank=True,
|
||||
default='0%',
|
||||
)
|
||||
real_work = models.DecimalField('实际工作量', max_digits=5, decimal_places=1, blank=True, null=True)
|
||||
real_work = models.DecimalField('实际工作量', default=0, max_digits=5, decimal_places=1, blank=False)
|
||||
complete_note = models.TextField('完成情况说明', max_length=150, blank=True)
|
||||
quality_mark = models.ForeignKey('users.QualityMark', on_delete=models.SET_NULL, blank=True, null=True,
|
||||
verbose_name='质量评价')
|
||||
attachment = models.FileField('交付物查看', blank=True)
|
||||
|
||||
def __str__(self):
|
||||
date = str(self.deadline)
|
||||
|
@ -50,6 +55,13 @@ class Todo(models.Model):
|
|||
verbose_name = '工作包'
|
||||
verbose_name_plural = '工作包'
|
||||
|
||||
# def save(self, *args, **kwargs):
|
||||
# super(Todo, self).save(*args, **kwargs)
|
||||
# print(request.HttpRequest)
|
||||
# # 直接保存报错 needs to have a value for field "id" before this many-to-many relationship can be used.
|
||||
# # self.sub_executor_count = int(self.sub_executor.count())
|
||||
# # Todo.objects.update(sub_executor_count=self.sub_executor.count())
|
||||
|
||||
@property
|
||||
def task_id(self):
|
||||
return self.related_task.task_id
|
||||
|
@ -74,6 +86,18 @@ class Todo(models.Model):
|
|||
def points(self):
|
||||
return int(self.predict_work * self.evaluate_factor)
|
||||
|
||||
@property
|
||||
def main_workload(self):
|
||||
return int(self.predict_work) * int(self.evaluate_factor)
|
||||
|
||||
@property
|
||||
def sub_workload(self):
|
||||
return self.predict_work * (1-int(self.evaluate_factor))/self.sub_executor.count
|
||||
|
||||
@classmethod
|
||||
def sub_member(cls):
|
||||
return cls.sub_executor.count
|
||||
|
||||
def list_sub_executor(self):
|
||||
return ', '.join([a.real_name for a in self.sub_executor.all()])
|
||||
list_sub_executor.short_description = '协办人'
|
||||
|
|
|
@ -6,6 +6,9 @@ from .models import Todo, Task
|
|||
class TodoResources(resources.ModelResource):
|
||||
class Meta:
|
||||
model = Todo
|
||||
fields = ('todo_topic', 'todo_note', 'deadline', 'duty_group__name', 'main_executor__real_name',
|
||||
'sub_executor__real_name', 'sub_executor_count', 'related_task', 'predict_work', 'evaluate_factor',
|
||||
'maturity', 'real_work', 'complete_note', 'quality_mark')
|
||||
|
||||
|
||||
class TaskResources(resources.ModelResource):
|
||||
|
|
|
@ -4,6 +4,7 @@ from apps.tasks import views
|
|||
app_name = 'tasks'
|
||||
urlpatterns = [
|
||||
path('', views.IndexView.as_view(), name='index'),
|
||||
path('<int:year>/<int:month>/', views.IndexView.as_view(), name='index_month'),
|
||||
path('login/', views.UserLoginView.as_view(), name='login'),
|
||||
path('logout/', views.UserLogoutView.as_view(), name='logout'),
|
||||
path('todolist/', views.TodoListView.as_view(), name='todolist'),
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import re
|
||||
from copy import deepcopy
|
||||
|
||||
from django.contrib import auth, messages
|
||||
from django.contrib.auth import logout
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.db.models import Sum, F
|
||||
from django.db.models import Sum, F, FloatField, Count, Q
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.shortcuts import render, redirect
|
||||
from django.utils.decorators import method_decorator
|
||||
import django.utils.timezone as timezone
|
||||
|
@ -10,19 +14,177 @@ from django.views import View
|
|||
from apps.tasks.models import Todo, Task
|
||||
from apps.tasks.forms import TodoForm
|
||||
from apps.users.models import User
|
||||
from functools import reduce
|
||||
import pandas as pd
|
||||
|
||||
|
||||
class IndexView(View):
|
||||
@method_decorator(login_required)
|
||||
def get(self, request):
|
||||
users = User.objects.filter(department=request.user.department)
|
||||
def get(self, request, year=timezone.now().year, month=timezone.now().month):
|
||||
basic_users = User.objects.filter(department=request.user.department).annotate(
|
||||
main_executor_count=Count('main_executor',
|
||||
filter=Q(main_executor__deadline__year=year, main_executor__deadline__month=month)
|
||||
, distinct=True),
|
||||
sub_executor_count=Count('sub_executor',
|
||||
filter=Q(sub_executor__deadline__year=year, sub_executor__deadline__month=month),
|
||||
distinct=True)
|
||||
).values('id', 'real_name', 'main_executor_count', 'sub_executor_count')
|
||||
|
||||
basic_users = [entry for entry in basic_users]
|
||||
basic_user_cal = {}
|
||||
for i in basic_users:
|
||||
basic_user_cal.update({i['id']: i})
|
||||
print(basic_user_cal)
|
||||
|
||||
current_user = User.objects.filter(username=request.user.username).annotate(
|
||||
main_executor_count=Count('main_executor',
|
||||
filter=Q(main_executor__deadline__year=year, main_executor__deadline__month=month)
|
||||
, distinct=True),
|
||||
sub_executor_count=Count('sub_executor',
|
||||
filter=Q(sub_executor__deadline__year=year, sub_executor__deadline__month=month),
|
||||
distinct=True),
|
||||
pre_credit=Sum(
|
||||
F('main_executor__predict_work') * F('main_executor__evaluate_factor'),
|
||||
filter=Q(main_executor__deadline__year=year, main_executor__deadline__month=month),
|
||||
distinct=True,
|
||||
output_field=FloatField()
|
||||
),
|
||||
real_credit=Sum(
|
||||
F('main_executor__real_work') * F('main_executor__evaluate_factor'),
|
||||
filter=Q(main_executor__deadline__year=year, main_executor__deadline__month=month),
|
||||
distinct=True,
|
||||
output_field=FloatField()
|
||||
)
|
||||
)
|
||||
|
||||
department_cal = Todo.objects.filter(main_executor__department=request.user.department,
|
||||
deadline__year=year, deadline__month=month).aggregate(count=Count('id'),
|
||||
pre_total=Sum('predict_work'), real_total=Sum('real_work'), pre_avg=Sum('predict_work'), real_avg=Sum('real_work')).values()
|
||||
keys = ['count', 'pre_total', 'real_total', 'pre_avg', 'real_avg']
|
||||
temp = []
|
||||
for values in department_cal:
|
||||
print(values)
|
||||
temp.append(values)
|
||||
#TODO 解决部门tem无数据报错问题
|
||||
try:
|
||||
tem = [float(tem) for tem in temp]
|
||||
whole = dict(zip(keys, tem))
|
||||
pre_avg = {'pre_avg': float(whole['pre_avg'])/request.user.department.get_user_number}
|
||||
real_avg = {'real_avg': float(whole['real_avg']) / request.user.department.get_user_number}
|
||||
whole.update(pre_avg)
|
||||
whole.update(real_avg)
|
||||
except:
|
||||
whole = {}
|
||||
print('无数据')
|
||||
# print(whole)
|
||||
|
||||
|
||||
|
||||
date = str(year) + '年' + str(month) + '月'
|
||||
|
||||
# points = []
|
||||
# point = User.objects.all()
|
||||
# for i in point:
|
||||
# points.append(i)
|
||||
# points = User.objects.annotate(a=F('main_executor__evaluate_factor'))
|
||||
points = User.objects.annotate(a=Sum(F('main_executor__predict_work') * F('main_executor__evaluate_factor') + F('sub_executor__predict_work') * F('sub_executor__evaluate_factor')))
|
||||
context = {'users': users, 'points': points}
|
||||
# points = User.objects.annotate(a=Coalesce(Sum(F('main_executor__predict_work') * F('main_executor__evaluate_factor')) + Sum(F('sub_executor__predict_work') * F('sub_executor__evaluate_factor')), 0))
|
||||
# points = User.objects.annotate(a=Sum(F('main_executor__predict_work') * F('main_executor__evaluate_factor')), b=Sum(F('sub_executor__predict_work') * F('sub_executor__evaluate_factor')))
|
||||
# points = User.objects.annotate(a=Sum(F('main_executor__main_workload')))
|
||||
|
||||
main_credit = User.objects.filter(department=request.user.department, ).annotate(
|
||||
pre_credit=Sum(
|
||||
F('main_executor__predict_work') * F('main_executor__evaluate_factor'),
|
||||
filter=Q(main_executor__deadline__year=year, main_executor__deadline__month=month),
|
||||
distinct=True,
|
||||
output_field=FloatField()
|
||||
),
|
||||
real_credit=Sum(
|
||||
F('main_executor__real_work') * F('main_executor__evaluate_factor'),
|
||||
filter=Q(main_executor__deadline__year=year, main_executor__deadline__month=month),
|
||||
distinct=True,
|
||||
output_field=FloatField()
|
||||
)
|
||||
).values('id', 'real_name', 'pre_credit', 'real_credit')
|
||||
main_credit = [entry for entry in main_credit] # converts ValuesQuerySet into Python list
|
||||
|
||||
sub_credit = User.objects.filter(department=request.user.department).annotate(
|
||||
pre_credit=Sum(
|
||||
(F('sub_executor__predict_work') * (1 - F('sub_executor__evaluate_factor')) / F(
|
||||
'sub_executor__sub_executor_count')
|
||||
),
|
||||
filter=Q(sub_executor__deadline__year=year, sub_executor__deadline__month=month),
|
||||
output_field=FloatField()
|
||||
),
|
||||
real_credit=Sum(
|
||||
(F('sub_executor__real_work') * (1 - F('sub_executor__evaluate_factor')) / F(
|
||||
'sub_executor__sub_executor_count')
|
||||
),
|
||||
filter=Q(sub_executor__deadline__year=year, sub_executor__deadline__month=month),
|
||||
output_field=FloatField()
|
||||
)
|
||||
).values('id', 'real_name', 'pre_credit', 'real_credit')
|
||||
sub_credit = [entry for entry in sub_credit]
|
||||
|
||||
total_credit = main_credit + sub_credit
|
||||
print(total_credit)
|
||||
|
||||
basic_user_credit = {}
|
||||
if total_credit:
|
||||
df = pd.DataFrame(total_credit)
|
||||
cols = ['id', 'real_name', 'pre_credit', 'real_credit']
|
||||
df = df.loc[:, cols]
|
||||
result = df.groupby(['id', ]).sum()
|
||||
cal_credit = result.T.to_dict('dict')
|
||||
# print(cal_credit)
|
||||
temp_credit = {}
|
||||
basic_user_credit = {}
|
||||
for key, values in cal_credit.items():
|
||||
# print(values['real_credit'])
|
||||
temp_credit['pre_credit'] = values['pre_credit']
|
||||
temp_credit['real_credit'] = values['real_credit']
|
||||
# print(temp_credit)
|
||||
basic_user_credit.update({key: temp_credit})
|
||||
# print(basic_user_credit)
|
||||
temp_credit = {}
|
||||
print(basic_user_credit)
|
||||
else:
|
||||
print("当前页Index无任何人员具有工作包")
|
||||
|
||||
for key in basic_user_cal:
|
||||
basic_user_cal[key].update(basic_user_credit[key])
|
||||
print(basic_user_cal)
|
||||
|
||||
|
||||
|
||||
# ids = []
|
||||
# person_list = []
|
||||
# for person in total_points:
|
||||
# id = person["id"]
|
||||
# temp = {}
|
||||
# if id not in ids:
|
||||
# ids.append(id)
|
||||
# temp_list = filter(lambda x: x["id"] == person["id"], total_points)
|
||||
# for i in temp_list:
|
||||
# temp.update(i)
|
||||
# person_list.append(temp)
|
||||
# else:
|
||||
# continue
|
||||
|
||||
# for i in main_points:
|
||||
# for key, value in i.items():
|
||||
|
||||
# def sum_dict(a, b):
|
||||
# temp = dict()
|
||||
# # python3,dict_keys类似set; | 并集
|
||||
# for key in a.keys() | b.keys():
|
||||
# temp[key] = sum([d.get(key, 0) for d in (a, b)])
|
||||
# return temp
|
||||
#
|
||||
# def test():
|
||||
# # [a,b,c]列表中的参数可以2个也可以多个,自己尝试。
|
||||
# return print(reduce(sum_dict, [a, b, c]))
|
||||
|
||||
context = {'users_data': basic_user_cal, 'date': date, 'current_user': current_user, 'department': whole}
|
||||
return render(request, 'tasks/index.html', context)
|
||||
|
||||
|
||||
|
@ -53,6 +215,7 @@ class TaskListView(View):
|
|||
context = {'tasks': tasks}
|
||||
return render(request, 'tasks/tasklist.html', context)
|
||||
|
||||
|
||||
class UserLoginView(View):
|
||||
def get(self, request):
|
||||
return render(request, 'tasks/login.html')
|
||||
|
@ -68,6 +231,7 @@ class UserLoginView(View):
|
|||
else:
|
||||
return redirect('tasks:index')
|
||||
|
||||
|
||||
class UserLogoutView(View):
|
||||
def get(self, request):
|
||||
logout(request)
|
||||
|
@ -92,4 +256,4 @@ class TodoEntryView(View):
|
|||
|
||||
class AboutView(View):
|
||||
def get(self, request):
|
||||
return render(request, 'tasks/about.html')
|
||||
return render(request, 'tasks/about.html')
|
||||
|
|
|
@ -9,7 +9,7 @@ from django.db.models import Avg, Sum, F, Value
|
|||
class User(AbstractUser):
|
||||
real_name = models.CharField(max_length=150, verbose_name='姓名')
|
||||
staff_id = models.CharField(max_length=150, verbose_name='工号')
|
||||
department = models.ForeignKey('Department', on_delete=models.SET_NULL, null=True, blank=True)
|
||||
department = models.ForeignKey('Department', related_name='member', on_delete=models.SET_NULL, null=True, blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = '用户'
|
||||
|
@ -45,6 +45,10 @@ class Department(models.Model):
|
|||
verbose_name = '部门'
|
||||
verbose_name_plural = '部门'
|
||||
|
||||
@property
|
||||
def get_user_number(self):
|
||||
return self.member.count()
|
||||
|
||||
|
||||
class MarkValue(models.Model):
|
||||
mark_value = models.DecimalField('评价等级考核系数', max_digits=3, decimal_places=2)
|
||||
|
|
|
@ -6,8 +6,10 @@ django-import-export==2.5.0
|
|||
django-simpleui==2021.4.1
|
||||
et-xmlfile==1.0.1
|
||||
MarkupPy==1.14
|
||||
numpy==1.20.2
|
||||
odfpy==1.4.1
|
||||
openpyxl==3.0.7
|
||||
pandas==1.2.4
|
||||
python-dateutil==2.8.1
|
||||
pytz==2020.5
|
||||
PyYAML==5.4.1
|
||||
|
|
|
@ -12,4 +12,9 @@
|
|||
.table-d-center{
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.col-xs-1-5 {
|
||||
width: 20%;
|
||||
float: left;
|
||||
}
|
|
@ -8,12 +8,19 @@
|
|||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h1>总览</h1>
|
||||
<h1>总览 ({{ date }}) </h1>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<ol class="breadcrumb float-sm-right">
|
||||
<li class="breadcrumb-item active"><a href="#">主页</a></li>
|
||||
</ol>
|
||||
{# <ol class="breadcrumb float-sm-right">#}
|
||||
{# <li class="breadcrumb-item active"><a href="#">主页</a></li>#}
|
||||
{# </ol>#}
|
||||
<br>
|
||||
{% load taskfilter %}
|
||||
<ul class="pagination float-md-right">
|
||||
<li class="page-item"><a class="page-link" href="/{{ date|last_month }}">«</a></li>
|
||||
<li class="page-item"><a class="page-link"> {{ date|this_month }}月 </a></li>
|
||||
<li class="page-item"><a class="page-link" href="/{{ date|next_month }}">»</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.container-fluid -->
|
||||
|
@ -23,14 +30,13 @@
|
|||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-6 col-md-3">
|
||||
<div class="col">
|
||||
<div class="info-box">
|
||||
<span class="info-box-icon bg-info elevation-1"><i class="fas fa-tasks"></i></span>
|
||||
|
||||
<span class="info-box-icon bg-danger elevation-1"><i class="fas fa-tasks"></i></span>
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">承办任务数</span>
|
||||
<span class="info-box-text">部门总任务数</span>
|
||||
<span class="info-box-number">
|
||||
{{ request.user.main_executor.count }}
|
||||
{{ department.count|floatformat:'0'|default_if_none:'0' }}
|
||||
<small>个</small>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -38,22 +44,173 @@
|
|||
</div>
|
||||
<!-- /.info-box -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
<div class="col-12 col-sm-6 col-md-3">
|
||||
<div class="info-box mb-3">
|
||||
<span class="info-box-icon bg-danger elevation-1"><i class="fas fa-tasks"></i></span>
|
||||
<!-- /.col -->
|
||||
<div class="col">
|
||||
<div class="info-box mb-3">
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">部门预计总工作量</span>
|
||||
<span class="info-box-number">
|
||||
{{ department.pre_total|default_if_none:'0'|floatformat:'1' }}
|
||||
<small></small>
|
||||
</span>
|
||||
</div>
|
||||
<!-- /.info-box-content -->
|
||||
</div>
|
||||
<!-- /.info-box -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
<div class="col">
|
||||
<div class="info-box mb-3">
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">部门实际总工作量</span>
|
||||
<span class="info-box-number">
|
||||
{{ department.real_total|default_if_none:'0'|floatformat:'1' }}
|
||||
<small></small>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">协办任务数</span>
|
||||
<span class="info-box-number">{{ user.sub_executor.count }}
|
||||
<small>个</small>
|
||||
</span>
|
||||
</div>
|
||||
<!-- /.info-box-content -->
|
||||
</div>
|
||||
<!-- /.info-box -->
|
||||
</div>
|
||||
<!-- /.info-box-content -->
|
||||
</div>
|
||||
<!-- /.info-box -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
<div class="col">
|
||||
<div class="info-box mb-3">
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">部门预计平均工作量</span>
|
||||
<span class="info-box-number">
|
||||
{{ department.pre_avg|default_if_none:'0'|floatformat:'1' }}
|
||||
<small></small>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- /.info-box-content -->
|
||||
</div>
|
||||
<!-- /.info-box -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
<div class="col">
|
||||
<div class="info-box mb-3">
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">部门实际平均工作量</span>
|
||||
<span class="info-box-number">
|
||||
{{ department.real_avg|default_if_none:'0'|floatformat:'1' }}
|
||||
<small></small>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- /.info-box-content -->
|
||||
</div>
|
||||
<!-- /.info-box -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
|
||||
<!-- fix for small devices only -->
|
||||
<div class="clearfix hidden-md-up"></div>
|
||||
|
||||
{# <div class="col-12 col-sm-6 col-md-3">#}
|
||||
{# <div class="info-box mb-3">#}
|
||||
{# <span class="info-box-icon bg-success elevation-1"><i class="fas fa-shopping-cart"></i></span>#}
|
||||
{##}
|
||||
{# <div class="info-box-content">#}
|
||||
{# <span class="info-box-text">Sales</span>#}
|
||||
{# <span class="info-box-number">760</span>#}
|
||||
{# </div>#}
|
||||
{# <!-- /.info-box-content -->#}
|
||||
{# </div>#}
|
||||
{# <!-- /.info-box -->#}
|
||||
{# </div>#}
|
||||
{# <!-- /.col -->#}
|
||||
{# <div class="col-12 col-sm-6 col-md-3">#}
|
||||
{# <div class="info-box mb-3">#}
|
||||
{# <span class="info-box-icon bg-warning elevation-1"><i class="fas fa-users"></i></span>#}
|
||||
{##}
|
||||
{# <div class="info-box-content">#}
|
||||
{# <span class="info-box-text">New Members</span>#}
|
||||
{# <span class="info-box-number">2,000</span>#}
|
||||
{# </div>#}
|
||||
{# <!-- /.info-box-content -->#}
|
||||
{# </div>#}
|
||||
{# <!-- /.info-box -->#}
|
||||
{# </div>#}
|
||||
<!-- /.col -->
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="info-box">
|
||||
<span class="info-box-icon bg-info elevation-1"><i class="fas fa-tasks"></i></span>
|
||||
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text"><b>个人任务数据统计:</b></span>
|
||||
{# <span class="info-box-number">#}
|
||||
{# {% for user in current_user %}{{ user.main_executor_count }}{% endfor %}#}
|
||||
{# <small>个</small>#}
|
||||
{# </span>#}
|
||||
</div>
|
||||
<!-- /.info-box-content -->
|
||||
</div>
|
||||
<!-- /.info-box -->
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="info-box">
|
||||
{# <span class="info-box-icon bg-info elevation-1"><i class="fas fa-tasks"></i></span>#}
|
||||
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">承办任务数</span>
|
||||
<span class="info-box-number">
|
||||
{% for user in current_user %}{{ user.main_executor_count }}{% endfor %}
|
||||
<small>个</small>
|
||||
</span>
|
||||
</div>
|
||||
<!-- /.info-box-content -->
|
||||
</div>
|
||||
<!-- /.info-box -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
<div class="col">
|
||||
<div class="info-box mb-3">
|
||||
{# <span class="info-box-icon bg-danger elevation-1"><i class="fas fa-tasks"></i></span>#}
|
||||
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">协办任务数</span>
|
||||
<span class="info-box-number">
|
||||
{% for user in current_user %}{{ user.sub_executor_count }}{% endfor %}
|
||||
<small>个</small>
|
||||
</span>
|
||||
</div>
|
||||
<!-- /.info-box-content -->
|
||||
</div>
|
||||
<!-- /.info-box -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
<div class="col">
|
||||
<div class="info-box mb-3">
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">预计工作量</span>
|
||||
<span class="info-box-number">
|
||||
{% for user in current_user %}{{ user.pre_credit|default_if_none:'0' }}{% endfor %}
|
||||
<small></small>
|
||||
</span>
|
||||
</div>
|
||||
<!-- /.info-box-content -->
|
||||
</div>
|
||||
<!-- /.info-box -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
<div class="col">
|
||||
<div class="info-box mb-3">
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">实际工作量</span>
|
||||
<span class="info-box-number">
|
||||
{% for user in current_user %}{{ user.real_credit|default_if_none:'0' }}{% endfor %}
|
||||
<small></small>
|
||||
</span>
|
||||
</div>
|
||||
<!-- /.info-box-content -->
|
||||
</div>
|
||||
<!-- /.info-box -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
|
||||
<!-- fix for small devices only -->
|
||||
<div class="clearfix hidden-md-up"></div>
|
||||
|
@ -124,17 +281,65 @@
|
|||
<!-- /.col (MAIN) -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">部门工作统计表</h3>
|
||||
</div>
|
||||
<!-- /.card-header -->
|
||||
<div class="card-body">
|
||||
<div id="example2_wrapper" class="dataTables_wrapper dt-bootstrap4"><div class="row"><div class="col-sm-12 col-md-6"></div><div class="col-sm-12 col-md-6"></div></div><div class="row"><div class="col-sm-12"><table id="example2" class="table table-bordered table-hover dataTable" role="grid" aria-describedby="example2_info">
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th class="sorting_asc" tabindex="0" aria-controls="example2" rowspan="1" colspan="1" aria-sort="ascending" aria-label="Rendering engine: activate to sort column descending">姓名</th>
|
||||
<th class="sorting" tabindex="0" aria-controls="example2" rowspan="1" colspan="1" aria-label="Browser: activate to sort column ascending">承办任务数</th>
|
||||
<th class="sorting" tabindex="0" aria-controls="example2" rowspan="1" colspan="1" aria-label="Platform(s): activate to sort column ascending">协办任务数</th>
|
||||
<th class="sorting" tabindex="0" aria-controls="example2" rowspan="1" colspan="1" aria-label="Engine version: activate to sort column ascending">预计工作量</th>
|
||||
<th class="sorting" tabindex="0" aria-controls="example2" rowspan="1" colspan="1" aria-label="CSS grade: activate to sort column ascending">实际工作量</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users_data.values %}
|
||||
<tr role="row" class="odd">
|
||||
<td class="sorting_1">{{ user.real_name }}</td>
|
||||
<td>{{ user.main_executor_count}}</td>
|
||||
<td>{{ user.sub_executor_count}}</td>
|
||||
<td>{{ user.pre_credit|floatformat:'1' }}</td>
|
||||
<td>{{ user.real_credit|floatformat:'1' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{# <tfoot>#}
|
||||
{# <tr><th rowspan="1" colspan="1">Rendering engine</th><th rowspan="1" colspan="1">Browser</th><th rowspan="1" colspan="1">Platform(s)</th><th rowspan="1" colspan="1">Engine version</th><th rowspan="1" colspan="1">CSS grade</th></tr>#}
|
||||
{# </tfoot>#}
|
||||
</table></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.card-body -->
|
||||
</div>
|
||||
<!-- /.card -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
</div>
|
||||
|
||||
</div><!-- /.container-fluid -->
|
||||
</section>
|
||||
<!-- /.content -->
|
||||
</div>
|
||||
|
||||
{# <div class="content-wrapper">#}
|
||||
{# {{ main_points }}#}
|
||||
{# <br>#}
|
||||
{# {{ sub_points }}#}
|
||||
{# <br>#}
|
||||
{# {{ points }}#}
|
||||
{# {{ points.3.credit }}#}
|
||||
{# {% for point in points.values %}'{{ point }}', {% endfor %}#}
|
||||
{# {% for point in points %}#}
|
||||
{# {{ point }}#}
|
||||
{# {{ point.a }}#}
|
||||
{# {% endfor %}#}
|
||||
|
||||
{##}
|
||||
{# {% for user in users %}#}
|
||||
{# {{ user }}#}
|
||||
{# {{ user.get_predict_work_count.total_predict_work }}#}
|
||||
|
@ -146,7 +351,7 @@
|
|||
{# {% endfor %}#}
|
||||
{# </br>#}
|
||||
{# {% endfor %}#}
|
||||
|
||||
{##}
|
||||
{# </div>#}
|
||||
{% endblock %}
|
||||
|
||||
|
@ -160,29 +365,51 @@
|
|||
* Here we will create a few charts using ChartJS
|
||||
*/
|
||||
var areaChartData = {
|
||||
labels : [{% for user in users %}'{{ user }}', {% endfor %}],
|
||||
labels : [{% for user in users_data.values %}'{{ user.real_name }}', {% endfor %}],
|
||||
datasets: [
|
||||
{
|
||||
label : '协办任务',
|
||||
backgroundColor : 'rgba(114,140,212,1)',
|
||||
borderColor : 'rgba(114,140,212,1)',
|
||||
pointRadius : false,
|
||||
pointColor : 'rgba(114,140,212,1)',
|
||||
pointStrokeColor : '#c1c7d1',
|
||||
pointHighlightFill : '#fff',
|
||||
pointHighlightStroke: 'rgba(220,220,220,1)',
|
||||
data : [{% for user in users_data.values %}'{{ user.sub_executor_count }}', {% endfor %}]
|
||||
},
|
||||
{
|
||||
label : '承办任务',
|
||||
backgroundColor : 'rgba(60,141,188,0.9)',
|
||||
borderColor : 'rgba(60,141,188,0.8)',
|
||||
backgroundColor : 'rgba(23,162,184,0.9)',
|
||||
borderColor : 'rgba(100,98,204,0.8)',
|
||||
pointRadius : false,
|
||||
pointColor : '#3b8bba',
|
||||
pointStrokeColor : 'rgba(60,141,188,1)',
|
||||
pointHighlightFill : '#fff',
|
||||
pointHighlightStroke: 'rgba(60,141,188,1)',
|
||||
data : [{% for user in users %}'{{ user.main_executor.count }}', {% endfor %}]
|
||||
data : [{% for user in users_data.values %}'{{ user.main_executor_count }}', {% endfor %}]
|
||||
},
|
||||
{
|
||||
label : '协办任务',
|
||||
backgroundColor : 'rgba(210, 214, 222, 1)',
|
||||
borderColor : 'rgba(210, 214, 222, 1)',
|
||||
pointRadius : false,
|
||||
pointColor : 'rgba(210, 214, 222, 1)',
|
||||
pointStrokeColor : '#c1c7d1',
|
||||
{
|
||||
label : '预计工作量',
|
||||
backgroundColor : 'rgba(210, 214, 222,1)',
|
||||
borderColor : 'rgba(210, 214, 222,1)',
|
||||
pointRadius : false,
|
||||
pointColor : '#3b8bba',
|
||||
pointStrokeColor : 'rgba(60,141,188,1)',
|
||||
pointHighlightFill : '#fff',
|
||||
pointHighlightStroke: 'rgba(220,220,220,1)',
|
||||
data : [{% for user in users %}'{{ user.sub_executor.count }}', {% endfor %}]
|
||||
pointHighlightStroke: 'rgba(60,141,188,1)',
|
||||
data : [{% for user in users_data.values %}'{{ user.pre_credit|floatformat:'1' }}', {% endfor %}]
|
||||
},
|
||||
{
|
||||
label : '工作量',
|
||||
backgroundColor : 'rgba(253,199,101,0.9)',
|
||||
borderColor : 'rgba(253,199,101,0.8)',
|
||||
pointRadius : false,
|
||||
pointColor : '#3b8bba',
|
||||
pointStrokeColor : 'rgba(60,141,188,1)',
|
||||
pointHighlightFill : '#fff',
|
||||
pointHighlightStroke: 'rgba(60,141,188,1)',
|
||||
data : [{% for user in users_data.values %}'{{ user.real_credit|floatformat:'1' }}', {% endfor %}]
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
|
@ -37,11 +37,15 @@
|
|||
<dl class="row">
|
||||
<dt class="col-sm-4">工作事项</dt>
|
||||
<dd class="col-sm-8">{{ todo_detail.todo_topic }}</dd>
|
||||
<dt class="col-sm-4">交付物</dt>
|
||||
<dd class="col-sm-8">{{ todo_detail.todo_note }}</dd>
|
||||
<dt class="col-sm-4">完成时间</dt>
|
||||
<dd class="col-sm-8">{{ todo_detail.deadline }}</dd>
|
||||
{# <dd class="col-sm-8 offset-sm-4">Donec id elit non mi porta gravida at eget metus.</dd>#}
|
||||
<dt class="col-sm-4">交付物</dt>
|
||||
<dd class="col-sm-8">{{ todo_detail.todo_note }}</dd>
|
||||
<dt class="col-sm-4">任务编号</dt>
|
||||
<dd class="col-sm-8">{{ todo_detail.task_id }}</dd>
|
||||
<dt class="col-sm-4">任务来源</dt>
|
||||
<dd class="col-sm-8">{{ todo_detail.task_origin }}</dd>
|
||||
<dt class="col-sm-4">责任单位</dt>
|
||||
<dd class="col-sm-8">{{ todo_detail.duty_group }}</dd>
|
||||
<dt class="col-sm-4">承/督办人</dt>
|
||||
|
@ -50,6 +54,12 @@
|
|||
<dd class="col-sm-8">{{ todo_detail.sub_executor.all|join:', ' }}</dd>
|
||||
<dt class="col-sm-4">预计工作量</dt>
|
||||
<dd class="col-sm-8">{{ todo_detail.predict_work }}</dd>
|
||||
<dt class="col-sm-4">折算系数</dt>
|
||||
<dd class="col-sm-8">{{ todo_detail.evaluate_factor }}</dd>
|
||||
<dt class="col-sm-4">实际工作量</dt>
|
||||
<dd class="col-sm-8">{{ todo_detail.real_work }}</dd>
|
||||
<dt class="col-sm-4">成熟度</dt>
|
||||
<dd class="col-sm-8">{{ todo_detail.maturity }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<!-- /.card-body -->
|
||||
|
|
Loading…
Reference in New Issue