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:
|
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']
|
||||||
|
|
||||||
|
|
|
@ -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 = '协办人'
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -13,3 +13,8 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.col-xs-1-5 {
|
||||||
|
width: 20%;
|
||||||
|
float: left;
|
||||||
|
}
|
|
@ -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 %}]
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 -->
|
||||||
|
|
Loading…
Reference in New Issue