Initial commit

This commit is contained in:
raiots 2021-02-02 13:55:18 +08:00
commit 8c0c4f932e
1999 changed files with 666799 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/.idea/
/venv/
/packagesdir/
/db.sqlite3
/identifier.sqlite

20
README.md Normal file
View File

@ -0,0 +1,20 @@
# TasksManager
### Beta 版本的说明
Author [面壁的雨](https://raiot.me)
某残念的练习之作,不断更新中。
请体谅~~一大堆Bug以及各种·逻辑混乱的代码~~
到时候会出一个文档的(或许
from 2020-7-13 to 2021-2-2
鬼知道为什么会用这么长时间
但无论如何beta版本总算完成啦
#### 注意!
* 此版本仅为beta版本请勿在生产环境使用

0
TasksManager/__init__.py Normal file
View File

16
TasksManager/asgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
ASGI config for TasksManager project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'TasksManager.settings')
application = get_asgi_application()

152
TasksManager/settings.py Normal file
View File

@ -0,0 +1,152 @@
"""
Django settings for TasksManager project.
Generated by 'django-admin startproject' using Django 3.1.5.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.1/ref/settings/
"""
import os
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '&!38pk#dv=r!_c(+b&oegc0m(ndzoue+ez*7kvjv2uubuqootp'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'simpleui',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'apps.users',
'apps.tasks',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'TasksManager.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates']
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'TasksManager.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
#STATIC_ROOT = os.path.join(BASE_DIR, "static/")
# 登录链接与登录后跳转路径
LOGIN_URL = '/login'
LOGIN_REDIRECT_URL = '/'
# 自定义用户模型
AUTH_USER_MODEL = 'users.User'
# SimpleUI 配置
# 离线模式
SIMPLEUI_STATIC_OFFLINE = True
# 关闭首页模块以及信息采集模块
SIMPLEUI_HOME_INFO = False
SIMPLEUI_HOME_QUICK = True
SIMPLEUI_HOME_ACTION = True
SIMPLEUI_ANALYSIS = False
SIMPLEUI_HOME_TITLE = '任务管理系统'
# SIMPLEUI_HOME_PAGE = 'https://www.baidu.com' # 可用于嵌入其他链接,这里可以直接方便的嵌入报表链接
SIMPLEUI_HOME_ICON = 'el el-icon-platform-eleme'
# ICON 支持element-ui和fontawesome egfa fa-user
# https://zhuanlan.zhihu.com/p/113447102

26
TasksManager/urls.py Normal file
View File

@ -0,0 +1,26 @@
"""TasksManager URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('apps.tasks.urls', namespace='tasks')),
]
admin.site.site_header = '任务进度管理系统'
admin.site.site_title = '任务进度管理系统'
admin.site.index_title = u'任务进度管理系统'

16
TasksManager/wsgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
WSGI config for TasksManager project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'TasksManager.settings')
application = get_wsgi_application()

1
apps/tasks/__init__.py Normal file
View File

@ -0,0 +1 @@
default_app_config = 'apps.tasks.apps.TasksConfig'

97
apps/tasks/admin.py Normal file
View File

@ -0,0 +1,97 @@
import re
from django.contrib import admin
from django.utils.html import format_html
from . import models
from apps.users.models import TaskProperty
class TaskAdmin(admin.ModelAdmin):
# def formfield_for_manytomany(self, db_field, request, **kwargs):
# if db_field.name == "related_task":
# ori_path = request.path
# f_id = re.sub("\D", "", ori_path)
# try:
# kwargs["queryset"] = models.Task.objects.get(id=f_id).related_task
# return super().formfield_for_manytomany(db_field, request, **kwargs)
# except:
# pass
# # kwargs["queryset"] = models.Task.objects.get(id=2).related_task
def get_changeform_initial_data(self, request):
return {'department': request.user.department}
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'task_property':
kwargs["queryset"] = TaskProperty.objects.filter(own_department=request.user.department)
return super().formfield_for_foreignkey(db_field, request, **kwargs)
list_display = (
'task_property', 'task_id', 'task_topic', 'task_origin', 'aim_value', 'deadline', 'duty_group', 'principal',
'leader', 'task_note',
)
fieldsets = (
(None, {
'fields': (
('task_property', 'task_id', 'task_topic', 'task_origin', 'aim_value', 'deadline', 'duty_group',
'principal', 'leader'),
'task_note', 'related_task', 'department'),
}),
)
raw_id_fields = ("principal", "leader",)
autocomplete_fields = ('related_task',)
search_fields = ('related_task',)
class TodoAdmin(admin.ModelAdmin):
def sub_executor(self, obj):
return ', '.join([a.real_name for a in obj.sub_executor.all()])
fieldsets = (
(None, {
'fields': (
'todo_topic', 'todo_note', 'deadline', 'duty_group', 'main_executor', 'sub_executor', 'predict_work',
'evaluate_factor',
)
}),
('完成情况', {
'fields': (
'real_work', 'complete_note', 'quality_mark', 'maturity'
)
})
)
list_display = (
'todo_topic',
'deadline',
'task_id',
'lined_task',
'task_origin',
'duty_department',
'duty_group',
'main_executor',
# 'sub_executor',
)
list_filter = ('deadline', )
list_display_links = ('todo_topic', 'deadline', )
date_hierarchy = 'deadline'
list_per_page = 20
raw_id_fields = ("main_executor", "sub_executor")
search_fields = ('todo_topic',)
# ordering = ('task_id',)
def approval_state(self, obj):
return format_html('<span style="color:{};">{}</span>', 'green', obj.approval)
def task_id(self, obj):
return obj.task_id
def lined_task(self, obj):
return obj.lined_task
task_id.admin_order_field = 'task__task_id'
task_id.short_description = '任务编号'
lined_task.admin_order_field = 'task__task_topic'
lined_task.short_description = '任务名称'
admin.site.register(models.Task, TaskAdmin)
admin.site.register(models.Todo, TodoAdmin)

6
apps/tasks/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class TasksConfig(AppConfig):
name = 'apps.tasks'
verbose_name = '任务管理'

14
apps/tasks/forms.py Normal file
View File

@ -0,0 +1,14 @@
from django import forms
from .models import Todo
class LoginForm(forms.Form):
username = forms.CharField(error_messages={'required': '用户名不能为空'})
password = forms.CharField()
remember = forms.BooleanField(required=False)
class TodoForm(forms.ModelForm):
class Meta:
model = Todo
fields = ['maturity', 'complete_note']
labels ={'text': ''}
widgets = {'row': '3'}

View File

@ -0,0 +1,50 @@
# Generated by Django 3.1.5 on 2021-01-29 13:31
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Task',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('task_topic', models.CharField(max_length=50, verbose_name='任务名称')),
('task_id', models.CharField(max_length=50, unique=True, verbose_name='任务编号')),
('task_note', models.CharField(max_length=100, verbose_name='任务说明')),
('task_origin', models.CharField(max_length=150, verbose_name='任务来源')),
('aim_value', models.CharField(max_length=50, verbose_name='目标值')),
('deadline', models.DateField(verbose_name='完成时间')),
],
options={
'verbose_name': '年度任务',
'verbose_name_plural': '年度任务',
'ordering': ['deadline'],
},
),
migrations.CreateModel(
name='Todo',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('todo_topic', models.CharField(max_length=50, verbose_name='工作事项')),
('todo_note', models.CharField(blank=True, max_length=100, verbose_name='工作要求及交付物')),
('predict_work', models.DecimalField(decimal_places=1, max_digits=5, verbose_name='预计工作量')),
('evaluate_factor', models.DecimalField(decimal_places=1, max_digits=5, verbose_name='折算系数')),
('maturity', models.CharField(blank=True, choices=[('0%', '0%'), ('10%', '10%'), ('20%', '20%'), ('30%', '30%'), ('40%', '40%'), ('50%', '50%'), ('60%', '60%'), ('70%', '70%'), ('80%', '80%'), ('90%', '90%'), ('100%', '100%')], default='0%', max_length=5, verbose_name='成熟度')),
('real_work', models.DecimalField(blank=True, decimal_places=1, max_digits=5, null=True, verbose_name='实际工作量')),
('complete_note', models.TextField(blank=True, max_length=150, verbose_name='完成情况说明')),
('deadline', models.DateField(verbose_name='完成时间')),
],
options={
'verbose_name': '每月工作事项',
'verbose_name_plural': '每月工作事项',
'ordering': ['deadline'],
},
),
]

View File

@ -0,0 +1,69 @@
# Generated by Django 3.1.5 on 2021-01-29 13:31
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('tasks', '0001_initial'),
('users', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='todo',
name='duty_group',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.mygroup', verbose_name='承办单位'),
),
migrations.AddField(
model_name='todo',
name='main_executor',
field=models.ManyToManyField(related_name='main_executor', to=settings.AUTH_USER_MODEL, verbose_name='承/督办人'),
),
migrations.AddField(
model_name='todo',
name='quality_mark',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='users.qualitymark', verbose_name='质量评价'),
),
migrations.AddField(
model_name='todo',
name='sub_executor',
field=models.ManyToManyField(blank=True, default='', related_name='sub_executor', to=settings.AUTH_USER_MODEL, verbose_name='协办人'),
),
migrations.AddField(
model_name='task',
name='department',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.department', verbose_name='所属单位'),
),
migrations.AddField(
model_name='task',
name='duty_group',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.mygroup', verbose_name='责任单位'),
),
migrations.AddField(
model_name='task',
name='leader',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='leader', to=settings.AUTH_USER_MODEL, verbose_name='主管领导'),
),
migrations.AddField(
model_name='task',
name='principal',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='principal', to=settings.AUTH_USER_MODEL, verbose_name='负责人'),
),
migrations.AddField(
model_name='task',
name='related_task',
field=models.ManyToManyField(blank=True, to='tasks.Todo', verbose_name='任务节点'),
),
migrations.AddField(
model_name='task',
name='task_property',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.taskproperty', verbose_name='任务属性'),
),
]

View File

@ -0,0 +1,25 @@
# Generated by Django 3.1.5 on 2021-01-29 13:35
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0002_auto_20210129_1332'),
('tasks', '0002_auto_20210129_1331'),
]
operations = [
migrations.AlterField(
model_name='task',
name='department',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='department', to='users.department', verbose_name='所属单位'),
),
migrations.AlterField(
model_name='task',
name='duty_group',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='duty_group', to='users.department', verbose_name='责任单位'),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 3.1.5 on 2021-01-29 14:34
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0004_auto_20210129_1434'),
('tasks', '0003_auto_20210129_1335'),
]
operations = [
migrations.AlterField(
model_name='todo',
name='duty_group',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.department', verbose_name='承办单位'),
),
]

View File

@ -0,0 +1,25 @@
# Generated by Django 3.1.5 on 2021-01-30 20:21
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0005_auto_20210130_2021'),
('tasks', '0004_auto_20210129_1434'),
]
operations = [
migrations.AlterField(
model_name='task',
name='department',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='department', to='users.department', verbose_name='所属单位'),
),
migrations.AlterField(
model_name='task',
name='duty_group',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='duty_group', to='users.department', verbose_name='责任单位'),
),
]

View File

@ -0,0 +1,25 @@
# Generated by Django 3.1.5 on 2021-02-01 19:00
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('tasks', '0005_auto_20210130_2021'),
]
operations = [
migrations.RemoveField(
model_name='todo',
name='main_executor',
),
migrations.AddField(
model_name='todo',
name='main_executor',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='main_executor', to=settings.AUTH_USER_MODEL, verbose_name='承/督办人'),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 3.1.5 on 2021-02-01 19:01
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0006_auto_20210201_1900'),
('tasks', '0006_auto_20210201_1900'),
]
operations = [
migrations.AlterField(
model_name='todo',
name='quality_mark',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='users.qualitymark', verbose_name='质量评价'),
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 3.1.5 on 2021-02-01 22:27
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('tasks', '0007_auto_20210201_1901'),
]
operations = [
migrations.AlterModelOptions(
name='todo',
options={'ordering': ['deadline'], 'verbose_name': '工作包', 'verbose_name_plural': '工作包'},
),
]

View File

120
apps/tasks/models.py Normal file
View File

@ -0,0 +1,120 @@
from django.db import models
from apps.users.models import User, MyGroup, QualityMark, TaskProperty, Department
class Todo(models.Model):
todo_topic = models.CharField(
verbose_name='工作事项',
max_length=50
)
todo_note = models.CharField(
verbose_name='工作要求及交付物',
blank=True,
max_length=100
)
# related_task = models.ManyToManyField(Task, verbose_name="关联的主任务")
duty_group = models.ForeignKey('users.Department', on_delete=models.CASCADE, verbose_name='承办单位')
main_executor = models.ForeignKey(User, related_name='main_executor', on_delete=models.SET_NULL, verbose_name='承/督办人', null=True)
sub_executor = models.ManyToManyField(User, related_name='sub_executor', verbose_name='协办人', default='', blank=True)
predict_work = models.DecimalField('预计工作量', max_digits=5, decimal_places=1)
evaluate_factor = models.DecimalField('折算系数', max_digits=5, decimal_places=1)
maturity = models.CharField(
verbose_name='成熟度',
max_length=5,
choices=(
('0%', '0%'),
('10%', '10%'),
('20%', '20%'),
('30%', '30%'),
('40%', '40%'),
('50%', '50%'),
('60%', '60%'),
('70%', '70%'),
('80%', '80%'),
('90%', '90%'),
('100%', '100%')
),
blank=True,
default='0%',
)
real_work = models.DecimalField('实际工作量', max_digits=5, decimal_places=1, blank=True, null=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, verbose_name='质量评价')
deadline = models.DateField(verbose_name='完成时间')
def __str__(self):
date = str(self.deadline)
date = parse_ymd(date)
return str(date) + self.todo_topic
class Meta:
ordering = ['deadline']
verbose_name = '工作包'
verbose_name_plural = '工作包'
@property
def lined_task(self):
lined_task = Task.objects.filter(related_task=self)
for task in lined_task:
return task.task_topic
# TODO 不知道有没有不用for循环直接查的
@property
def task_id(self):
tasks = Task.objects.filter(related_task=self)
for task in tasks:
return task.task_id
def task_origin(self):
tasks = Task.objects.filter(related_task=self)
for task in tasks:
return task.task_origin
def duty_department(self):
tasks = Task.objects.filter(related_task=self)
for task in tasks:
return task.duty_group
@property
def last_month_list(self):
return self.deadline
@property
def get_tatal_num(self):
return self.objects.all().count()
class Task(models.Model):
task_topic = models.CharField(
verbose_name='任务名称',
max_length=50
)
task_id = models.CharField(max_length=50, unique=True, verbose_name='任务编号')
task_note = models.CharField(
verbose_name='任务说明',
max_length=100
)
task_origin = models.CharField(max_length=150, verbose_name='任务来源')
task_property = models.ForeignKey('users.TaskProperty', on_delete=models.CASCADE, verbose_name='任务属性')
related_task = models.ManyToManyField(Todo, verbose_name='任务节点', blank=True)
department = models.ForeignKey('users.Department', related_name='department', on_delete=models.SET_NULL, blank=True, null=True, verbose_name='所属单位')
duty_group = models.ForeignKey('users.Department', related_name='duty_group', on_delete=models.SET_NULL, blank=True, null=True, verbose_name='责任单位')
principal = models.ForeignKey(User, related_name='principal', verbose_name='负责人', on_delete=models.CASCADE)
leader = models.ForeignKey(User, related_name='leader', verbose_name='主管领导', on_delete=models.CASCADE)
aim_value = models.CharField(max_length=50, verbose_name='目标值')
# start_date = models.DateField(verbose_name='起始日期')
deadline = models.DateField(verbose_name='完成时间')
def __str__(self):
return self.task_topic
class Meta:
ordering = ['deadline']
verbose_name = '年度任务'
verbose_name_plural = '年度任务'
def parse_ymd(s):
year_s, mon_s, day_s = s.split('-')
date = mon_s + '' + day_s + ''
return date
# https://www.cnblogs.com/chichung/p/9905835.html

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,47 @@
from django import template
from datetime import datetime
from dateutil.relativedelta import relativedelta
register = template.Library()
@register.filter(name='quarter_cate')
def quarter_cate(value, quarter):
month = value.deadline.strftime('%m')
month = int(month)
quarter = int(quarter)
if quarter == 1 and 1 <= month <= 3:
return value
elif quarter == 2 and 4 <= month <= 6:
return value
elif quarter == 3 and 7 <= month <= 9:
return value
elif quarter == 4 and 10 <= month <= 12:
return value
else:
return ''
@register.filter(name='last_month')
def last_month(value):
curent_date = datetime.strptime(value, '%Y年%m月')
last_date = curent_date - relativedelta(months=+1)
last_month = last_date.strftime('%Y/%m')
return last_month
@register.filter(name='next_month')
def next_month(value):
curent_date = datetime.strptime(value, '%Y年%m月')
next_date = curent_date + relativedelta(months=+1)
next_month = next_date.strftime('%Y/%m')
return next_month
@register.filter(name='this_month')
def this_month(value):
curent_date = datetime.strptime(value, '%Y年%m月')
return curent_date.strftime('%m')

3
apps/tasks/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

15
apps/tasks/urls.py Normal file
View File

@ -0,0 +1,15 @@
from django.urls import path
from apps.tasks import views
app_name = 'tasks'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('login/', views.UserLoginView.as_view(), name='login'),
path('logout/', views.UserLogoutView.as_view(), name='logout'),
path('todolist/', views.TodoListView.as_view(), name='todolist'),
path('todolist/<int:year>/<int:month>/', views.TodoListView.as_view(), name='todolist_month'),
path('group_todolist/', views.GroupTodoList.as_view(), name='group_todolist'),
path('group_todolist/<int:year>/<int:month>/', views.GroupTodoList.as_view(), name='group_todolist_month'),
path('todo/<int:pk>/', views.TodoEntryView.as_view(), name='todo_detail'),
path('tasklist/', views.TaskListView.as_view(), name='tasklist'),
]

80
apps/tasks/views.py Normal file
View File

@ -0,0 +1,80 @@
from django.contrib import auth, messages
from django.contrib.auth import logout
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from django.utils.decorators import method_decorator
import django.utils.timezone as timezone
from django.views import View
# Create your views here.
from apps.tasks.models import Todo, Task
from apps.tasks.forms import TodoForm
class IndexView(View):
def get(self, request):
tasks = Task.objects.filter().order_by('task_id')
context = {'tasks': tasks}
return render(request, 'tasks/tasklist.html', context)
class TodoListView(View):
@method_decorator(login_required)
def get(self, request, year=timezone.now().year, month=timezone.now().month):
my_todo = Todo.objects.filter(main_executor=request.user, deadline__year=year, deadline__month=month)
my_sub_todo = Todo.objects.filter(sub_executor=request.user, deadline__year=year, deadline__month=month)
date = str(year) + '' + str(month) + ''
context = {'my_todo': my_todo, 'my_sub_todo': my_sub_todo, 'date': date}
return render(request, 'tasks/todolist.html', context)
class GroupTodoList(View):
@method_decorator(login_required)
def get(self, request, year=timezone.now().year, month=timezone.now().month):
group_todo = Todo.objects.filter(main_executor__department=request.user.department, deadline__year=year, deadline__month=month)
date = str(year) + '' + str(month) + ''
context = {'group_todo': group_todo, 'date': date}
return render(request, 'tasks/group_todolist.html', context)
class TaskListView(View):
@method_decorator(login_required)
def get(self, request):
tasks = Task.objects.filter().order_by('task_id')
context = {'tasks': tasks}
return render(request, 'tasks/tasklist.html', context)
class UserLoginView(View):
def get(self, request):
return render(request, 'tasks/login.html')
def post(self, request):
username = request.POST.get('username')
password = request.POST.get('password')
user = auth.authenticate(username=username, password=password)
if user:
auth.login(request, user)
messages.success(request, 'hh')
return redirect('tasks:index')
else:
return redirect('tasks:index')
class UserLogoutView(View):
def get(self, request):
logout(request)
return redirect('tasks:index')
class TodoEntryView(View):
def get(self, request, pk):
todo_detail = Todo.objects.get(id=pk)
form = TodoForm(instance=todo_detail)
context = {'todo_detail': todo_detail, 'form': form}
return render(request, 'tasks/todo.html', context)
def post(self, request, pk):
todo_detail = Todo.objects.get(id=pk)
form = TodoForm(instance=todo_detail, data=request.POST)
if form.is_valid():
form.save()
return redirect('tasks:index')
# return redirect('tasks:todo_detail', pk=pk)

1
apps/users/__init__.py Normal file
View File

@ -0,0 +1 @@
default_app_config = 'apps.users.apps.UsersConfig'

46
apps/users/admin.py Normal file
View File

@ -0,0 +1,46 @@
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin, GroupAdmin
from . import models
class MyUserAdmin(UserAdmin):
# @staticmethod
# def group_list(self):
# return ', '.join([a.name for a in self.groups.all()])
# group_list.short_description = '部门/组'
list_display = ('username', 'real_name', 'staff_id', 'department')
fieldsets = (
(None, {'fields': ('username', 'password', 'real_name', 'staff_id', 'department')}),
('权限', {
'fields': ('is_active', 'is_staff', 'is_superuser', 'groups'),
}),
)
class MyGroupAdmin(GroupAdmin):
pass
class DepartmentAdmin(admin.ModelAdmin):
pass
class TaskPropertyAdmin(admin.ModelAdmin):
list_display = (
'task_property', 'own_department'
)
class QualityMarkAdmin(admin.ModelAdmin):
list_display = (
'mark_name',
'mark_value'
)
admin.site.register(models.User, MyUserAdmin)
admin.site.register(models.MyGroup, MyGroupAdmin)
admin.site.register(models.MarkValue)
admin.site.register(models.Department)
admin.site.register(models.QualityMark, QualityMarkAdmin)
admin.site.register(models.TaskProperty, TaskPropertyAdmin)
admin.site.unregister(Group)

7
apps/users/apps.py Normal file
View File

@ -0,0 +1,7 @@
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'apps.users'
verbose_name = '系统配置'

View File

@ -0,0 +1,97 @@
# Generated by Django 3.1.5 on 2021-01-29 13:31
import django.contrib.auth.models
import django.contrib.auth.validators
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name='Department',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50, verbose_name='部门名称')),
],
options={
'verbose_name': '部门',
},
),
migrations.CreateModel(
name='MarkValue',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('mark_value', models.DecimalField(decimal_places=2, max_digits=3)),
],
),
migrations.CreateModel(
name='MyGroup',
fields=[
('group_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='auth.group')),
],
options={
'verbose_name': '权限组',
'verbose_name_plural': '权限组',
},
bases=('auth.group',),
managers=[
('objects', django.contrib.auth.models.GroupManager()),
],
),
migrations.CreateModel(
name='TaskProperty',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('task_property', models.CharField(max_length=50, verbose_name='任务属性')),
],
options={
'verbose_name': '任务属性',
'verbose_name_plural': '任务属性',
},
),
migrations.CreateModel(
name='QualityMark',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('mark_name', models.CharField(max_length=10, verbose_name='评分')),
('mark_value', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.markvalue')),
],
),
migrations.CreateModel(
name='User',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('real_name', models.CharField(max_length=150, verbose_name='姓名')),
('staff_id', models.CharField(max_length=150, verbose_name='工号')),
('department', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.department')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
],
options={
'verbose_name': '用户',
'verbose_name_plural': '用户',
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 3.1.5 on 2021-01-29 13:32
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='user',
name='department',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='users.department'),
),
]

View File

@ -0,0 +1,24 @@
# Generated by Django 3.1.5 on 2021-01-29 14:17
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0002_auto_20210129_1332'),
]
operations = [
migrations.AlterModelOptions(
name='department',
options={'verbose_name': '部门', 'verbose_name_plural': '部门'},
),
migrations.AddField(
model_name='taskproperty',
name='own_department',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='users.department'),
preserve_default=False,
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 3.1.5 on 2021-01-29 14:34
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0003_auto_20210129_1417'),
]
operations = [
migrations.AlterField(
model_name='taskproperty',
name='own_department',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.department', verbose_name='所属部门'),
),
]

View File

@ -0,0 +1,24 @@
# Generated by Django 3.1.5 on 2021-01-30 20:21
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0004_auto_20210129_1434'),
]
operations = [
migrations.AlterField(
model_name='taskproperty',
name='own_department',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='users.department', verbose_name='所属部门'),
),
migrations.AlterField(
model_name='user',
name='department',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='users.department'),
),
]

View File

@ -0,0 +1,31 @@
# Generated by Django 3.1.5 on 2021-02-01 19:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0005_auto_20210130_2021'),
]
operations = [
migrations.AlterModelOptions(
name='markvalue',
options={'verbose_name': '评分值', 'verbose_name_plural': '评分值'},
),
migrations.AlterModelOptions(
name='qualitymark',
options={'verbose_name': '评分名称', 'verbose_name_plural': '评分名称'},
),
migrations.AlterField(
model_name='markvalue',
name='mark_value',
field=models.DecimalField(decimal_places=2, max_digits=3, verbose_name='评分值'),
),
migrations.AlterField(
model_name='qualitymark',
name='mark_name',
field=models.CharField(max_length=10, verbose_name='评分名称'),
),
]

View File

@ -0,0 +1,31 @@
# Generated by Django 3.1.5 on 2021-02-01 22:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0006_auto_20210201_1900'),
]
operations = [
migrations.AlterModelOptions(
name='markvalue',
options={'verbose_name': '评价等级考核系数', 'verbose_name_plural': '评价等级考核系数'},
),
migrations.AlterModelOptions(
name='qualitymark',
options={'verbose_name': '评价等级定义', 'verbose_name_plural': '评价等级定义'},
),
migrations.AlterField(
model_name='markvalue',
name='mark_value',
field=models.DecimalField(decimal_places=2, max_digits=3, verbose_name='评价等级考核系数'),
),
migrations.AlterField(
model_name='qualitymark',
name='mark_name',
field=models.CharField(max_length=10, verbose_name='评价等级定义'),
),
]

View File

66
apps/users/models.py Normal file
View File

@ -0,0 +1,66 @@
from django.db import models
from django.contrib.auth.models import AbstractUser, Group
# Create your models here.
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)
class Meta:
verbose_name = '用户'
verbose_name_plural = '用户'
def __str__(self):
return self.real_name
class MyGroup(Group):
class Meta:
verbose_name = '权限组'
verbose_name_plural = '权限组'
class Department(models.Model):
name = models.CharField(max_length=50, verbose_name='部门名称')
def __str__(self):
return self.name
class Meta:
verbose_name = '部门'
verbose_name_plural = '部门'
class MarkValue(models.Model):
mark_value = models.DecimalField('评价等级考核系数', max_digits=3, decimal_places=2)
def __str__(self):
return str(self.mark_value)
class Meta:
verbose_name = '评价等级考核系数'
verbose_name_plural = verbose_name
class QualityMark(models.Model):
mark_name = models.CharField('评价等级定义', max_length=10)
mark_value = models.ForeignKey('MarkValue', on_delete=models.CASCADE)
def __str__(self):
return self.mark_name
class Meta:
verbose_name = '评价等级定义'
verbose_name_plural = verbose_name
class TaskProperty(models.Model):
own_department = models.ForeignKey('Department', on_delete=models.SET_NULL, null=True, blank=True, verbose_name='所属部门')
task_property = models.CharField(max_length=50, verbose_name='任务属性')
class Meta:
verbose_name = '任务属性'
verbose_name_plural = '任务属性'
def __str__(self):
return self.task_property

3
apps/users/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

3
apps/users/views.py Normal file
View File

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

22
manage.py Normal file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'TasksManager.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

7
requirements.txt Normal file
View File

@ -0,0 +1,7 @@
asgiref==3.3.1
Django==3.1.5
django-simpleui==2021.1.1
python-dateutil==2.8.1
pytz==2020.5
six==1.15.0
sqlparse==0.4.1

32922
static/tasks/dist/css/adminlte.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

12
static/tasks/dist/css/adminlte.min.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

18349
static/tasks/dist/css/alt/adminlte.core.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,643 @@
/*!
* AdminLTE v3.1.0-rc
* Only Pages
* Author: Colorlib
* Website: AdminLTE.io <https://adminlte.io>
* License: Open source - MIT <https://opensource.org/licenses/MIT>
*/
.close, .mailbox-attachment-close {
float: right;
font-size: 1.5rem;
font-weight: 700;
line-height: 1;
color: #000;
text-shadow: 0 1px 0 #fff;
opacity: .5;
}
.close:hover, .mailbox-attachment-close:hover {
color: #000;
text-decoration: none;
}
.close:not(:disabled):not(.disabled):hover, .mailbox-attachment-close:not(:disabled):not(.disabled):hover, .close:not(:disabled):not(.disabled):focus, .mailbox-attachment-close:not(:disabled):not(.disabled):focus {
opacity: .75;
}
button.close, button.mailbox-attachment-close {
padding: 0;
background-color: transparent;
border: 0;
}
a.close.disabled, a.disabled.mailbox-attachment-close {
pointer-events: none;
}
.mailbox-messages > .table {
margin: 0;
}
.mailbox-controls {
padding: 5px;
}
.mailbox-controls.with-border {
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
}
.mailbox-read-info {
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
padding: 10px;
}
.mailbox-read-info h3 {
font-size: 20px;
margin: 0;
}
.mailbox-read-info h5 {
margin: 0;
padding: 5px 0 0;
}
.mailbox-read-time {
color: #999;
font-size: 13px;
}
.mailbox-read-message {
padding: 10px;
}
.mailbox-attachments {
padding-left: 0;
list-style: none;
}
.mailbox-attachments li {
border: 1px solid #eee;
float: left;
margin-bottom: 10px;
margin-right: 10px;
width: 200px;
}
.mailbox-attachment-name {
color: #666;
font-weight: 700;
}
.mailbox-attachment-icon,
.mailbox-attachment-info,
.mailbox-attachment-size {
display: block;
}
.mailbox-attachment-info {
background-color: #f8f9fa;
padding: 10px;
}
.mailbox-attachment-size {
color: #999;
font-size: 12px;
}
.mailbox-attachment-size > span {
display: inline-block;
padding-top: .75rem;
}
.mailbox-attachment-icon {
color: #666;
font-size: 65px;
max-height: 132.5px;
padding: 20px 10px;
text-align: center;
}
.mailbox-attachment-icon.has-img {
padding: 0;
}
.mailbox-attachment-icon.has-img > img {
height: auto;
max-width: 100%;
}
.lockscreen {
background-color: #e9ecef;
}
.lockscreen .lockscreen-name {
font-weight: 600;
text-align: center;
}
.lockscreen-logo {
font-size: 35px;
font-weight: 300;
margin-bottom: 25px;
text-align: center;
}
.lockscreen-logo a {
color: #495057;
}
.lockscreen-wrapper {
margin: 0 auto;
margin-top: 10%;
max-width: 400px;
}
.lockscreen-item {
border-radius: 4px;
background-color: #fff;
margin: 10px auto 30px;
padding: 0;
position: relative;
width: 290px;
}
.lockscreen-image {
border-radius: 50%;
background-color: #fff;
left: -10px;
padding: 5px;
position: absolute;
top: -25px;
z-index: 10;
}
.lockscreen-image > img {
border-radius: 50%;
height: 70px;
width: 70px;
}
.lockscreen-credentials {
margin-left: 70px;
}
.lockscreen-credentials .form-control {
border: 0;
}
.lockscreen-credentials .btn {
background-color: #fff;
border: 0;
padding: 0 10px;
}
.lockscreen-footer {
margin-top: 10px;
}
.dark-mode .lockscreen-item {
background-color: #343a40;
}
.dark-mode .lockscreen-logo a {
color: #fff;
}
.dark-mode .lockscreen-credentials .btn {
background-color: #343a40;
}
.dark-mode .lockscreen-image {
background-color: #6c757d;
}
.login-logo,
.register-logo {
font-size: 2.1rem;
font-weight: 300;
margin-bottom: .9rem;
text-align: center;
}
.login-logo a,
.register-logo a {
color: #495057;
}
.login-page,
.register-page {
-ms-flex-align: center;
align-items: center;
background-color: #e9ecef;
display: -ms-flexbox;
display: flex;
-ms-flex-direction: column;
flex-direction: column;
height: 100vh;
-ms-flex-pack: center;
justify-content: center;
}
.login-box,
.register-box {
width: 360px;
}
@media (max-width: 576px) {
.login-box,
.register-box {
margin-top: .5rem;
width: 90%;
}
}
.login-box .card,
.register-box .card {
margin-bottom: 0;
}
.login-card-body,
.register-card-body {
background-color: #fff;
border-top: 0;
color: #666;
padding: 20px;
}
.login-card-body .input-group .form-control,
.register-card-body .input-group .form-control {
border-right: 0;
}
.login-card-body .input-group .form-control:focus,
.register-card-body .input-group .form-control:focus {
box-shadow: none;
}
.login-card-body .input-group .form-control:focus ~ .input-group-prepend .input-group-text,
.login-card-body .input-group .form-control:focus ~ .input-group-append .input-group-text,
.register-card-body .input-group .form-control:focus ~ .input-group-prepend .input-group-text,
.register-card-body .input-group .form-control:focus ~ .input-group-append .input-group-text {
border-color: #80bdff;
}
.login-card-body .input-group .form-control.is-valid:focus,
.register-card-body .input-group .form-control.is-valid:focus {
box-shadow: none;
}
.login-card-body .input-group .form-control.is-valid ~ .input-group-prepend .input-group-text,
.login-card-body .input-group .form-control.is-valid ~ .input-group-append .input-group-text,
.register-card-body .input-group .form-control.is-valid ~ .input-group-prepend .input-group-text,
.register-card-body .input-group .form-control.is-valid ~ .input-group-append .input-group-text {
border-color: #28a745;
}
.login-card-body .input-group .form-control.is-invalid:focus,
.register-card-body .input-group .form-control.is-invalid:focus {
box-shadow: none;
}
.login-card-body .input-group .form-control.is-invalid ~ .input-group-append .input-group-text,
.register-card-body .input-group .form-control.is-invalid ~ .input-group-append .input-group-text {
border-color: #dc3545;
}
.login-card-body .input-group .input-group-text,
.register-card-body .input-group .input-group-text {
background-color: transparent;
border-bottom-right-radius: 0.25rem;
border-left: 0;
border-top-right-radius: 0.25rem;
color: #777;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
.login-box-msg,
.register-box-msg {
margin: 0;
padding: 0 20px 20px;
text-align: center;
}
.social-auth-links {
margin: 10px 0;
}
.dark-mode .login-card-body,
.dark-mode .register-card-body {
background-color: #343a40;
border-color: #6c757d;
color: #fff;
}
.dark-mode .login-logo a,
.dark-mode .register-logo a {
color: #fff;
}
.error-page {
margin: 20px auto 0;
width: 600px;
}
@media (max-width: 767.98px) {
.error-page {
width: 100%;
}
}
.error-page > .headline {
float: left;
font-size: 100px;
font-weight: 300;
}
@media (max-width: 767.98px) {
.error-page > .headline {
float: none;
text-align: center;
}
}
.error-page > .error-content {
display: block;
margin-left: 190px;
}
@media (max-width: 767.98px) {
.error-page > .error-content {
margin-left: 0;
}
}
.error-page > .error-content > h3 {
font-size: 25px;
font-weight: 300;
}
@media (max-width: 767.98px) {
.error-page > .error-content > h3 {
text-align: center;
}
}
.invoice {
background-color: #fff;
border: 1px solid rgba(0, 0, 0, 0.125);
position: relative;
}
.invoice-title {
margin-top: 0;
}
.dark-mode .invoice {
background-color: #343a40;
}
.profile-user-img {
border: 3px solid #adb5bd;
margin: 0 auto;
padding: 3px;
width: 100px;
}
.profile-username {
font-size: 21px;
margin-top: 5px;
}
.post {
border-bottom: 1px solid #adb5bd;
color: #666;
margin-bottom: 15px;
padding-bottom: 15px;
}
.post:last-of-type {
border-bottom: 0;
margin-bottom: 0;
padding-bottom: 0;
}
.post .user-block {
margin-bottom: 15px;
width: 100%;
}
.post .row {
width: 100%;
}
.dark-mode .post {
color: #fff;
border-color: #6c757d;
}
.product-image {
max-width: 100%;
height: auto;
width: 100%;
}
.product-image-thumbs {
-ms-flex-align: stretch;
align-items: stretch;
display: -ms-flexbox;
display: flex;
margin-top: 2rem;
}
.product-image-thumb {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
border-radius: 0.25rem;
background-color: #fff;
border: 1px solid #dee2e6;
display: -ms-flexbox;
display: flex;
margin-right: 1rem;
max-width: 7rem;
padding: 0.5rem;
}
.product-image-thumb img {
max-width: 100%;
height: auto;
-ms-flex-item-align: center;
align-self: center;
}
.product-image-thumb:hover {
opacity: .5;
}
.product-share a {
margin-right: .5rem;
}
.projects td {
vertical-align: middle;
}
.projects .list-inline {
margin-bottom: 0;
}
.projects img.table-avatar,
.projects .table-avatar img {
border-radius: 50%;
display: inline;
width: 2.5rem;
}
.projects .project-state {
text-align: center;
}
body.iframe-mode .main-sidebar {
display: none;
}
body.iframe-mode .content-wrapper {
margin-left: 0 !important;
margin-top: 0 !important;
padding-bottom: 0 !important;
}
body.iframe-mode .main-header,
body.iframe-mode .main-footer {
display: none;
}
body.iframe-mode-fullscreen {
overflow: hidden;
}
.content-wrapper {
height: 100%;
}
.content-wrapper.iframe-mode .navbar-nav {
overflow-y: auto;
width: 100%;
}
.content-wrapper.iframe-mode .navbar-nav .nav-link {
white-space: nowrap;
}
.content-wrapper.iframe-mode .tab-content {
position: relative;
}
.content-wrapper.iframe-mode .tab-empty {
width: 100%;
display: -ms-flexbox;
display: flex;
-ms-flex-pack: center;
justify-content: center;
-ms-flex-align: center;
align-items: center;
}
.content-wrapper.iframe-mode .tab-loading {
position: absolute;
top: 0;
left: 0;
width: 100%;
display: none;
background-color: #f4f6f9;
}
.content-wrapper.iframe-mode .tab-loading > div {
display: -ms-flexbox;
display: flex;
-ms-flex-pack: center;
justify-content: center;
-ms-flex-align: center;
align-items: center;
width: 100%;
height: 100%;
}
.content-wrapper.iframe-mode iframe {
border: 0;
width: 100%;
height: 100%;
}
.content-wrapper.iframe-mode iframe .content-wrapper {
padding-bottom: 0 !important;
}
body.iframe-mode-fullscreen .content-wrapper.iframe-mode {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin-left: 0 !important;
height: 100%;
min-height: 100%;
z-index: 1048;
}
.content-wrapper.kanban {
height: 1px;
}
.content-wrapper.kanban .content {
height: 100%;
overflow-x: auto;
overflow-y: hidden;
}
.content-wrapper.kanban .content .container,
.content-wrapper.kanban .content .container-fluid {
width: -webkit-max-content;
width: -moz-max-content;
width: max-content;
display: -ms-flexbox;
display: flex;
-ms-flex-align: stretch;
align-items: stretch;
}
.content-wrapper.kanban .content-header + .content {
height: calc(100% - ((2 * 15px) + (1.8rem * 1.2)));
}
.content-wrapper.kanban .card .card-body {
padding: .5rem;
}
.content-wrapper.kanban .card.card-row {
width: 340px;
display: inline-block;
margin: 0 .5rem;
}
.content-wrapper.kanban .card.card-row:first-child {
margin-left: 0;
}
.content-wrapper.kanban .card.card-row .card-body {
height: 100%;
overflow-y: auto;
}
.content-wrapper.kanban .card.card-row .card .card-header {
padding: .5rem .75rem;
}
.content-wrapper.kanban .card.card-row .card .card-body {
padding: .75rem;
}
.content-wrapper.kanban .btn-tool.btn-link {
text-decoration: underline;
padding-left: 0;
padding-right: 0;
}
/*# sourceMappingURL=adminlte.pages.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

251
static/tasks/dist/css/googlefont.css vendored Normal file
View File

@ -0,0 +1,251 @@
/* cyrillic-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: italic;
font-weight: 400;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7qsDJT9g.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Source Sans Pro';
font-style: italic;
font-weight: 400;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7jsDJT9g.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: italic;
font-weight: 400;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7rsDJT9g.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Source Sans Pro';
font-style: italic;
font-weight: 400;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7ksDJT9g.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Source Sans Pro';
font-style: italic;
font-weight: 400;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7osDJT9g.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: italic;
font-weight: 400;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7psDJT9g.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Source Sans Pro';
font-style: italic;
font-weight: 400;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7nsDI.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 300;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmhduz8A.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 300;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwkxduz8A.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 300;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmxduz8A.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 300;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwlBduz8A.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 300;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmBduz8A.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 300;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmRduz8A.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 300;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwlxdu.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNa7lqDY.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xK3dSBYKcSV-LCoeQqfX1RYOo3qPK7lqDY.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNK7lqDY.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xK3dSBYKcSV-LCoeQqfX1RYOo3qO67lqDY.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xK3dSBYKcSV-LCoeQqfX1RYOo3qN67lqDY.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNq7lqDY.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7l.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmhduz8A.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwkxduz8A.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmxduz8A.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlBduz8A.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmBduz8A.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmRduz8A.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
font-display: fallback;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}

BIN
static/tasks/dist/img/AdminLTELogo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
static/tasks/dist/img/avatar.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
static/tasks/dist/img/avatar2.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

BIN
static/tasks/dist/img/avatar3.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
static/tasks/dist/img/avatar4.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
static/tasks/dist/img/avatar5.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

BIN
static/tasks/dist/img/boxed-bg.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

BIN
static/tasks/dist/img/boxed-bg.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
static/tasks/dist/img/credit/cirrus.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/tasks/dist/img/credit/paypal.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
static/tasks/dist/img/credit/paypal2.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
static/tasks/dist/img/credit/visa.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

BIN
static/tasks/dist/img/icons.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/tasks/dist/img/photo1.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 KiB

BIN
static/tasks/dist/img/photo2.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 KiB

BIN
static/tasks/dist/img/photo3.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 KiB

BIN
static/tasks/dist/img/photo4.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
static/tasks/dist/img/prod-1.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
static/tasks/dist/img/prod-2.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
static/tasks/dist/img/prod-3.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
static/tasks/dist/img/prod-4.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
static/tasks/dist/img/prod-5.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
static/tasks/dist/img/user1-128x128.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
static/tasks/dist/img/user2-160x160.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
static/tasks/dist/img/user3-128x128.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
static/tasks/dist/img/user4-128x128.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
static/tasks/dist/img/user5-128x128.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
static/tasks/dist/img/user6-128x128.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
static/tasks/dist/img/user7-128x128.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
static/tasks/dist/img/user8-128x128.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Some files were not shown because too many files have changed in this diff Show More