add: chart of work load for each member in department & millions of bugs.

This commit is contained in:
raiots 2021-05-05 00:48:03 +08:00
parent 3d08ffce71
commit d7359e3ea8
10 changed files with 512 additions and 53 deletions

View File

@ -62,6 +62,13 @@ class TaskAdmin(ImportExportModelAdmin):
else: else:
return qs.filter(department=request.user.department) 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 = ( list_display = (
'task_property', 'task_id', 'task_topic', 'task_origin', 'aim_value', 'deadline', 'duty_group', 'principal', 'task_property', 'task_id', 'task_topic', 'task_origin', 'aim_value', 'deadline', 'duty_group', 'principal',
'leader', 'task_note', 'leader', 'task_note',
@ -124,9 +131,9 @@ class TodoAdmin(ImportExportModelAdmin):
(None, { (None, {
'fields': [ 'fields': [
'related_task', 'todo_topic', 'todo_note', 'deadline', 'duty_group', 'main_executor', 'sub_executor', '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, { (None, {
@ -157,6 +164,7 @@ class TodoAdmin(ImportExportModelAdmin):
# raw_id_fields = ("sub_executor",) # raw_id_fields = ("sub_executor",)
search_fields = ('todo_topic',) search_fields = ('todo_topic',)
ordering = ('related_task', ) ordering = ('related_task', )
readonly_fields = [ "attachment"]
def approval_state(self, obj): def approval_state(self, obj):
return format_html('<span style="color:{};">{}</span>', 'green', obj.approval) return format_html('<span style="color:{};">{}</span>', 'green', obj.approval)
@ -191,6 +199,17 @@ class TodoAdmin(ImportExportModelAdmin):
else: else:
return False 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'] actions = ['bulk_action']

View File

@ -1,4 +1,8 @@
import time
from django.db import models from django.db import models
from django.http import request
from apps.users.models import User, MyGroup, QualityMark, TaskProperty, Department 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, main_executor = models.ForeignKey(User, related_name='main_executor', on_delete=models.CASCADE,
verbose_name='承/督办人', blank=True, null=True) verbose_name='承/督办人', blank=True, null=True)
sub_executor = models.ManyToManyField(User, related_name='sub_executor', verbose_name='协办人', blank=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='年度任务') 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') evaluate_factor = models.DecimalField('折算系数', max_digits=5, decimal_places=1, blank=True, default='1')
maturity = models.CharField( maturity = models.CharField(
verbose_name='成熟度', verbose_name='成熟度',
@ -28,17 +33,17 @@ class Todo(models.Model):
('0%', '0%'), ('0%', '0%'),
('10%', '10%'), ('10%', '10%'),
('50%', '50%'), ('50%', '50%'),
('70%', '70%'),
('90%', '90%'), ('90%', '90%'),
('100%', '100%') ('100%', '100%')
), ),
blank=True, blank=True,
default='0%', 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) complete_note = models.TextField('完成情况说明', max_length=150, blank=True)
quality_mark = models.ForeignKey('users.QualityMark', on_delete=models.SET_NULL, blank=True, null=True, quality_mark = models.ForeignKey('users.QualityMark', on_delete=models.SET_NULL, blank=True, null=True,
verbose_name='质量评价') verbose_name='质量评价')
attachment = models.FileField('交付物查看', blank=True)
def __str__(self): def __str__(self):
date = str(self.deadline) date = str(self.deadline)
@ -50,6 +55,13 @@ class Todo(models.Model):
verbose_name = '工作包' verbose_name = '工作包'
verbose_name_plural = '工作包' 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 @property
def task_id(self): def task_id(self):
return self.related_task.task_id return self.related_task.task_id
@ -74,6 +86,18 @@ class Todo(models.Model):
def points(self): def points(self):
return int(self.predict_work * self.evaluate_factor) 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): def list_sub_executor(self):
return ', '.join([a.real_name for a in self.sub_executor.all()]) return ', '.join([a.real_name for a in self.sub_executor.all()])
list_sub_executor.short_description = '协办人' list_sub_executor.short_description = '协办人'

View File

@ -6,6 +6,9 @@ from .models import Todo, Task
class TodoResources(resources.ModelResource): class TodoResources(resources.ModelResource):
class Meta: class Meta:
model = Todo 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): class TaskResources(resources.ModelResource):

View File

@ -4,6 +4,7 @@ from apps.tasks import views
app_name = 'tasks' app_name = 'tasks'
urlpatterns = [ urlpatterns = [
path('', views.IndexView.as_view(), name='index'), 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('login/', views.UserLoginView.as_view(), name='login'),
path('logout/', views.UserLogoutView.as_view(), name='logout'), path('logout/', views.UserLogoutView.as_view(), name='logout'),
path('todolist/', views.TodoListView.as_view(), name='todolist'), path('todolist/', views.TodoListView.as_view(), name='todolist'),

View File

@ -1,7 +1,11 @@
import re
from copy import deepcopy
from django.contrib import auth, messages from django.contrib import auth, messages
from django.contrib.auth import logout from django.contrib.auth import logout
from django.contrib.auth.decorators import login_required 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.shortcuts import render, redirect
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
import django.utils.timezone as timezone 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.models import Todo, Task
from apps.tasks.forms import TodoForm from apps.tasks.forms import TodoForm
from apps.users.models import User from apps.users.models import User
from functools import reduce
import pandas as pd
class IndexView(View): class IndexView(View):
@method_decorator(login_required) @method_decorator(login_required)
def get(self, request): def get(self, request, year=timezone.now().year, month=timezone.now().month):
users = User.objects.filter(department=request.user.department) 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 = [] # points = []
# point = User.objects.all() # point = User.objects.all()
# for i in point: # for i in point:
# points.append(i) # points.append(i)
# points = User.objects.annotate(a=F('main_executor__evaluate_factor')) # 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'))) # 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))
context = {'users': users, 'points': points} # 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) return render(request, 'tasks/index.html', context)
@ -53,6 +215,7 @@ class TaskListView(View):
context = {'tasks': tasks} context = {'tasks': tasks}
return render(request, 'tasks/tasklist.html', context) return render(request, 'tasks/tasklist.html', context)
class UserLoginView(View): class UserLoginView(View):
def get(self, request): def get(self, request):
return render(request, 'tasks/login.html') return render(request, 'tasks/login.html')
@ -68,6 +231,7 @@ class UserLoginView(View):
else: else:
return redirect('tasks:index') return redirect('tasks:index')
class UserLogoutView(View): class UserLogoutView(View):
def get(self, request): def get(self, request):
logout(request) logout(request)

View File

@ -9,7 +9,7 @@ from django.db.models import Avg, Sum, F, Value
class User(AbstractUser): class User(AbstractUser):
real_name = models.CharField(max_length=150, verbose_name='姓名') real_name = models.CharField(max_length=150, verbose_name='姓名')
staff_id = 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: class Meta:
verbose_name = '用户' verbose_name = '用户'
@ -45,6 +45,10 @@ class Department(models.Model):
verbose_name = '部门' verbose_name = '部门'
verbose_name_plural = '部门' verbose_name_plural = '部门'
@property
def get_user_number(self):
return self.member.count()
class MarkValue(models.Model): class MarkValue(models.Model):
mark_value = models.DecimalField('评价等级考核系数', max_digits=3, decimal_places=2) mark_value = models.DecimalField('评价等级考核系数', max_digits=3, decimal_places=2)

View File

@ -6,8 +6,10 @@ django-import-export==2.5.0
django-simpleui==2021.4.1 django-simpleui==2021.4.1
et-xmlfile==1.0.1 et-xmlfile==1.0.1
MarkupPy==1.14 MarkupPy==1.14
numpy==1.20.2
odfpy==1.4.1 odfpy==1.4.1
openpyxl==3.0.7 openpyxl==3.0.7
pandas==1.2.4
python-dateutil==2.8.1 python-dateutil==2.8.1
pytz==2020.5 pytz==2020.5
PyYAML==5.4.1 PyYAML==5.4.1

View File

@ -13,3 +13,8 @@
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
} }
.col-xs-1-5 {
width: 20%;
float: left;
}

View File

@ -8,12 +8,19 @@
<div class="container-fluid"> <div class="container-fluid">
<div class="row mb-2"> <div class="row mb-2">
<div class="col-sm-6"> <div class="col-sm-6">
<h1>总览</h1> <h1>总览 ({{ date }}) </h1>
</div> </div>
<div class="col-sm-6"> <div class="col-sm-6">
<ol class="breadcrumb float-sm-right"> {# <ol class="breadcrumb float-sm-right">#}
<li class="breadcrumb-item active"><a href="#">主页</a></li> {# <li class="breadcrumb-item active"><a href="#">主页</a></li>#}
</ol> {# </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> </div>
</div><!-- /.container-fluid --> </div><!-- /.container-fluid -->
@ -23,14 +30,13 @@
<section class="content"> <section class="content">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-3"> <div class="col">
<div class="info-box"> <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"> <div class="info-box-content">
<span class="info-box-text">承办任务数</span> <span class="info-box-text">部门总任务数</span>
<span class="info-box-number"> <span class="info-box-number">
{{ request.user.main_executor.count }} {{ department.count|floatformat:'0'|default_if_none:'0' }}
<small></small> <small></small>
</span> </span>
</div> </div>
@ -39,13 +45,136 @@
<!-- /.info-box --> <!-- /.info-box -->
</div> </div>
<!-- /.col --> <!-- /.col -->
<div class="col-12 col-sm-6 col-md-3"> <div class="col">
<div class="info-box mb-3"> <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">
{{ 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>
<!-- /.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"> <div class="info-box-content">
<span class="info-box-text">协办任务数</span> <span class="info-box-text">协办任务数</span>
<span class="info-box-number">{{ user.sub_executor.count }} <span class="info-box-number">
{% for user in current_user %}{{ user.sub_executor_count }}{% endfor %}
<small></small> <small></small>
</span> </span>
</div> </div>
@ -54,6 +183,34 @@
<!-- /.info-box --> <!-- /.info-box -->
</div> </div>
<!-- /.col --> <!-- /.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 --> <!-- fix for small devices only -->
<div class="clearfix hidden-md-up"></div> <div class="clearfix hidden-md-up"></div>
@ -124,17 +281,65 @@
<!-- /.col (MAIN) --> <!-- /.col (MAIN) -->
</div> </div>
<!-- /.row --> <!-- /.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 --> </div><!-- /.container-fluid -->
</section> </section>
<!-- /.content --> <!-- /.content -->
</div> </div>
{# <div class="content-wrapper">#} {# <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 %}#} {# {% for point in points %}#}
{# {{ point }}#} {# {{ point }}#}
{# {{ point.a }}#}
{# {% endfor %}#} {# {% endfor %}#}
{##}
{# {% for user in users %}#} {# {% for user in users %}#}
{# {{ user }}#} {# {{ user }}#}
{# {{ user.get_predict_work_count.total_predict_work }}#} {# {{ user.get_predict_work_count.total_predict_work }}#}
@ -146,7 +351,7 @@
{# {% endfor %}#} {# {% endfor %}#}
{# </br>#} {# </br>#}
{# {% endfor %}#} {# {% endfor %}#}
{##}
{# </div>#} {# </div>#}
{% endblock %} {% endblock %}
@ -160,29 +365,51 @@
* Here we will create a few charts using ChartJS * Here we will create a few charts using ChartJS
*/ */
var areaChartData = { var areaChartData = {
labels : [{% for user in users %}'{{ user }}', {% endfor %}], labels : [{% for user in users_data.values %}'{{ user.real_name }}', {% endfor %}],
datasets: [ 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 : '承办任务', label : '承办任务',
backgroundColor : 'rgba(60,141,188,0.9)', backgroundColor : 'rgba(23,162,184,0.9)',
borderColor : 'rgba(60,141,188,0.8)', borderColor : 'rgba(100,98,204,0.8)',
pointRadius : false, pointRadius : false,
pointColor : '#3b8bba', pointColor : '#3b8bba',
pointStrokeColor : 'rgba(60,141,188,1)', pointStrokeColor : 'rgba(60,141,188,1)',
pointHighlightFill : '#fff', pointHighlightFill : '#fff',
pointHighlightStroke: 'rgba(60,141,188,1)', 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 : '协办任务', label : '预计工作量',
backgroundColor : 'rgba(210, 214, 222,1)', backgroundColor : 'rgba(210, 214, 222,1)',
borderColor : 'rgba(210, 214, 222,1)', borderColor : 'rgba(210, 214, 222,1)',
pointRadius : false, pointRadius : false,
pointColor : 'rgba(210, 214, 222, 1)', pointColor : '#3b8bba',
pointStrokeColor : '#c1c7d1', pointStrokeColor : 'rgba(60,141,188,1)',
pointHighlightFill : '#fff', pointHighlightFill : '#fff',
pointHighlightStroke: 'rgba(220,220,220,1)', pointHighlightStroke: 'rgba(60,141,188,1)',
data : [{% for user in users %}'{{ user.sub_executor.count }}', {% endfor %}] 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 %}]
}, },
] ]
} }

View File

@ -37,11 +37,15 @@
<dl class="row"> <dl class="row">
<dt class="col-sm-4">工作事项</dt> <dt class="col-sm-4">工作事项</dt>
<dd class="col-sm-8">{{ todo_detail.todo_topic }}</dd> <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> <dt class="col-sm-4">完成时间</dt>
<dd class="col-sm-8">{{ todo_detail.deadline }}</dd> <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>#} {# <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> <dt class="col-sm-4">责任单位</dt>
<dd class="col-sm-8">{{ todo_detail.duty_group }}</dd> <dd class="col-sm-8">{{ todo_detail.duty_group }}</dd>
<dt class="col-sm-4">承/督办人</dt> <dt class="col-sm-4">承/督办人</dt>
@ -50,6 +54,12 @@
<dd class="col-sm-8">{{ todo_detail.sub_executor.all|join:', ' }}</dd> <dd class="col-sm-8">{{ todo_detail.sub_executor.all|join:', ' }}</dd>
<dt class="col-sm-4">预计工作量</dt> <dt class="col-sm-4">预计工作量</dt>
<dd class="col-sm-8">{{ todo_detail.predict_work }}</dd> <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> </dl>
</div> </div>
<!-- /.card-body --> <!-- /.card-body -->