mirror of
https://github.com/RobbieHan/sandboxMP.git
synced 2026-02-03 19:03:15 +08:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45630bd451 | ||
|
|
b85d89642d | ||
|
|
832c55ab34 | ||
|
|
f72efee2e1 | ||
|
|
2bba133771 | ||
|
|
2261bc6b3a | ||
|
|
005b62a01e | ||
|
|
0b04685f2f |
4
.idea/sandboxMP.iml
generated
4
.idea/sandboxMP.iml
generated
@@ -12,7 +12,9 @@
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/apps" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
|
||||
1672
.idea/workspace.xml
generated
1672
.idea/workspace.xml
generated
File diff suppressed because it is too large
Load Diff
3
apps/__init__.py
Normal file
3
apps/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# @Time : 2018/10/17 14:54
|
||||
# @Author : RobbieHan
|
||||
# @File : __init__.py.py
|
||||
BIN
apps/__pycache__/__init__.cpython-36.pyc
Normal file
BIN
apps/__pycache__/__init__.cpython-36.pyc
Normal file
Binary file not shown.
0
apps/system/__init__.py
Normal file
0
apps/system/__init__.py
Normal file
BIN
apps/system/__pycache__/__init__.cpython-36.pyc
Normal file
BIN
apps/system/__pycache__/__init__.cpython-36.pyc
Normal file
Binary file not shown.
BIN
apps/system/__pycache__/admin.cpython-36.pyc
Normal file
BIN
apps/system/__pycache__/admin.cpython-36.pyc
Normal file
Binary file not shown.
BIN
apps/system/__pycache__/apps.cpython-36.pyc
Normal file
BIN
apps/system/__pycache__/apps.cpython-36.pyc
Normal file
Binary file not shown.
BIN
apps/system/__pycache__/forms.cpython-36.pyc
Normal file
BIN
apps/system/__pycache__/forms.cpython-36.pyc
Normal file
Binary file not shown.
BIN
apps/system/__pycache__/mixin.cpython-36.pyc
Normal file
BIN
apps/system/__pycache__/mixin.cpython-36.pyc
Normal file
Binary file not shown.
BIN
apps/system/__pycache__/models.cpython-36.pyc
Normal file
BIN
apps/system/__pycache__/models.cpython-36.pyc
Normal file
Binary file not shown.
BIN
apps/system/__pycache__/urls.cpython-36.pyc
Normal file
BIN
apps/system/__pycache__/urls.cpython-36.pyc
Normal file
Binary file not shown.
BIN
apps/system/__pycache__/views.cpython-36.pyc
Normal file
BIN
apps/system/__pycache__/views.cpython-36.pyc
Normal file
Binary file not shown.
BIN
apps/system/__pycache__/views_structure.cpython-36.pyc
Normal file
BIN
apps/system/__pycache__/views_structure.cpython-36.pyc
Normal file
Binary file not shown.
BIN
apps/system/__pycache__/views_user.cpython-36.pyc
Normal file
BIN
apps/system/__pycache__/views_user.cpython-36.pyc
Normal file
Binary file not shown.
3
apps/system/admin.py
Normal file
3
apps/system/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
5
apps/system/apps.py
Normal file
5
apps/system/apps.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class SystemConfig(AppConfig):
|
||||
name = 'apps.system'
|
||||
17
apps/system/forms.py
Normal file
17
apps/system/forms.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# @Time : 2018/10/17 23:13
|
||||
# @Author : RobbieHan
|
||||
# @File : forms.py
|
||||
|
||||
from django import forms
|
||||
from .models import Structure
|
||||
|
||||
|
||||
class LoginForm(forms.Form):
|
||||
username = forms.CharField(required=True, error_messages={"requeired": "请填写用户名"})
|
||||
password = forms.CharField(required=True, error_messages={"requeired": "请填写密码"})
|
||||
|
||||
|
||||
class StructureForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Structure
|
||||
fields = ['type', 'name', 'parent']
|
||||
112
apps/system/migrations/0001_initial.py
Normal file
112
apps/system/migrations/0001_initial.py
Normal file
@@ -0,0 +1,112 @@
|
||||
# Generated by Django 2.1.2 on 2018-10-17 15:09
|
||||
|
||||
from django.conf import settings
|
||||
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', '0009_alter_user_last_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UserProfile',
|
||||
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=30, verbose_name='first name')),
|
||||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
||||
('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')),
|
||||
('name', models.CharField(default='', max_length=20, verbose_name='姓名')),
|
||||
('birthday', models.DateField(blank=True, null=True, verbose_name='出生日期')),
|
||||
('gender', models.CharField(choices=[('male', '男'), ('female', '女')], default='male', max_length=10, verbose_name='性别')),
|
||||
('mobile', models.CharField(default='', max_length=11, verbose_name='手机号码')),
|
||||
('email', models.EmailField(max_length=50, verbose_name='邮箱')),
|
||||
('image', models.ImageField(blank=True, default='image/default.jpg', null=True, upload_to='image/%Y/%m')),
|
||||
('post', models.CharField(blank=True, max_length=50, null=True, verbose_name='职位')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '用户信息',
|
||||
'verbose_name_plural': '用户信息',
|
||||
'ordering': ['id'],
|
||||
},
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Menu',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=30, unique=True, verbose_name='菜单名')),
|
||||
('icon', models.CharField(blank=True, max_length=50, null=True, verbose_name='图标')),
|
||||
('code', models.CharField(blank=True, max_length=50, null=True, verbose_name='编码')),
|
||||
('url', models.CharField(blank=True, max_length=128, null=True, unique=True)),
|
||||
('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='system.Menu', verbose_name='父菜单')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '菜单',
|
||||
'verbose_name_plural': '菜单',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Role',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=32, unique=True, verbose_name='角色')),
|
||||
('desc', models.CharField(blank=True, max_length=50, null=True, verbose_name='描述')),
|
||||
('permissions', models.ManyToManyField(blank=True, to='system.Menu', verbose_name='URL授权')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Structure',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=60, verbose_name='名称')),
|
||||
('type', models.CharField(choices=[('unit', '单位'), ('department', '部门')], default='department', max_length=20, verbose_name='类型')),
|
||||
('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='system.Structure', verbose_name='父类架构')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '组织架构',
|
||||
'verbose_name_plural': '组织架构',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='userprofile',
|
||||
name='department',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='system.Structure', verbose_name='部门'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='userprofile',
|
||||
name='groups',
|
||||
field=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'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='userprofile',
|
||||
name='roles',
|
||||
field=models.ManyToManyField(blank=True, to='system.Role', verbose_name='角色'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='userprofile',
|
||||
name='superior',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='上级主管'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='userprofile',
|
||||
name='user_permissions',
|
||||
field=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'),
|
||||
),
|
||||
]
|
||||
0
apps/system/migrations/__init__.py
Normal file
0
apps/system/migrations/__init__.py
Normal file
BIN
apps/system/migrations/__pycache__/0001_initial.cpython-36.pyc
Normal file
BIN
apps/system/migrations/__pycache__/0001_initial.cpython-36.pyc
Normal file
Binary file not shown.
BIN
apps/system/migrations/__pycache__/__init__.cpython-36.pyc
Normal file
BIN
apps/system/migrations/__pycache__/__init__.cpython-36.pyc
Normal file
Binary file not shown.
12
apps/system/mixin.py
Normal file
12
apps/system/mixin.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# @Time : 2018/10/17 15:15
|
||||
# @Author : RobbieHan
|
||||
# @File : mixin.py.py
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
|
||||
class LoginRequiredMixin(object):
|
||||
@classmethod
|
||||
def as_view(cls, **init_kwargs):
|
||||
view = super(LoginRequiredMixin, cls).as_view(**init_kwargs)
|
||||
return login_required(view)
|
||||
73
apps/system/models.py
Normal file
73
apps/system/models.py
Normal file
@@ -0,0 +1,73 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
|
||||
|
||||
class Menu(models.Model):
|
||||
"""
|
||||
菜单
|
||||
"""
|
||||
name = models.CharField(max_length=30, unique=True, verbose_name="菜单名") # unique=True, 这个字段在表中必须有唯一值.
|
||||
parent = models.ForeignKey("self", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="父菜单")
|
||||
icon = models.CharField(max_length=50, null=True, blank=True, verbose_name="图标")
|
||||
code = models.CharField(max_length=50, null=True, blank=True, verbose_name="编码")
|
||||
url = models.CharField(max_length=128, unique=True, null=True, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '菜单'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
@classmethod
|
||||
def get_menu_by_request_url(cls, url):
|
||||
return dict(menu=Menu.objects.get(url=url))
|
||||
|
||||
|
||||
class Role(models.Model):
|
||||
"""
|
||||
角色:用于权限绑定
|
||||
"""
|
||||
name = models.CharField(max_length=32, unique=True, verbose_name="角色")
|
||||
permissions = models.ManyToManyField("menu", blank=True, verbose_name="URL授权")
|
||||
desc = models.CharField(max_length=50, blank=True, null=True, verbose_name="描述")
|
||||
|
||||
|
||||
class Structure(models.Model):
|
||||
"""
|
||||
组织架构
|
||||
"""
|
||||
type_choices = (("unit", "单位"), ("department", "部门"))
|
||||
name = models.CharField(max_length=60, verbose_name="名称")
|
||||
type = models.CharField(max_length=20, choices=type_choices, default="department", verbose_name="类型")
|
||||
parent = models.ForeignKey("self", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="父类架构")
|
||||
|
||||
class Meta:
|
||||
verbose_name = "组织架构"
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class UserProfile(AbstractUser):
|
||||
name = models.CharField(max_length=20, default="", verbose_name="姓名")
|
||||
birthday = models.DateField(null=True, blank=True, verbose_name="出生日期")
|
||||
gender = models.CharField(max_length=10, choices=(("male", "男"), ("female", "女")),
|
||||
default="male", verbose_name="性别")
|
||||
mobile = models.CharField(max_length=11, default="", verbose_name="手机号码")
|
||||
email = models.EmailField(max_length=50, verbose_name="邮箱")
|
||||
image = models.ImageField(upload_to="image/%Y/%m", default="image/default.jpg",
|
||||
max_length=100, null=True, blank=True)
|
||||
department = models.ForeignKey("Structure", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="部门")
|
||||
post = models.CharField(max_length=50, null=True, blank=True, verbose_name="职位")
|
||||
superior = models.ForeignKey("self", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="上级主管")
|
||||
roles = models.ManyToManyField("role", verbose_name="角色", blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "用户信息"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ['id']
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
4
apps/system/tests.py
Normal file
4
apps/system/tests.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
|
||||
16
apps/system/urls.py
Normal file
16
apps/system/urls.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from django.urls import path, re_path
|
||||
|
||||
from .views import SystemView
|
||||
from . import views_structure
|
||||
|
||||
app_name = 'system'
|
||||
|
||||
urlpatterns = [
|
||||
path('', SystemView.as_view(), name='login'),
|
||||
path('basic/structure/', views_structure.StructureView.as_view(), name='basic-structure'),
|
||||
path('basic/structure/create/', views_structure.StructureCreateView.as_view(), name='basic-structure-create'),
|
||||
path('basic/structure/list/', views_structure.StructureListView.as_view(), name='basic-structure-list'),
|
||||
path('basic/structure/delete/', views_structure.StructureDeleteView.as_view(), name='basic-structure-delete'),
|
||||
path('basic/structure/add_user/', views_structure.Structure2UserView.as_view(), name='basic-structure-add_user'),
|
||||
]
|
||||
|
||||
11
apps/system/views.py
Normal file
11
apps/system/views.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from django.shortcuts import render
|
||||
from django.views.generic.base import View
|
||||
|
||||
from .mixin import LoginRequiredMixin
|
||||
|
||||
|
||||
class SystemView(LoginRequiredMixin, View):
|
||||
|
||||
def get(self, request):
|
||||
return render(request, 'system/system_index.html')
|
||||
|
||||
89
apps/system/views_structure.py
Normal file
89
apps/system/views_structure.py
Normal file
@@ -0,0 +1,89 @@
|
||||
# @Time : 2018/10/18 23:04
|
||||
# @Author : RobbieHan
|
||||
# @File : views_structure.py
|
||||
|
||||
import json
|
||||
|
||||
from django.views.generic.base import TemplateView
|
||||
from django.views.generic.base import View
|
||||
from django.shortcuts import render
|
||||
from django.shortcuts import HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from .mixin import LoginRequiredMixin
|
||||
from .models import Structure
|
||||
from .forms import StructureForm
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class StructureView(LoginRequiredMixin, TemplateView):
|
||||
|
||||
template_name = 'system/structure/structure.html'
|
||||
|
||||
|
||||
class StructureCreateView(LoginRequiredMixin, View):
|
||||
|
||||
def get(self, request):
|
||||
ret = dict(structure_all=Structure.objects.all())
|
||||
if 'id' in request.GET and request.GET['id']:
|
||||
structure = get_object_or_404(Structure, pk=request.GET['id'])
|
||||
ret['structure'] = structure
|
||||
return render(request, 'system/structure/structure_create.html', ret)
|
||||
|
||||
def post(self, request):
|
||||
res = dict(result=False)
|
||||
if 'id' in request.POST and request.POST['id']:
|
||||
structure = get_object_or_404(Structure, pk=request.POST['id'])
|
||||
else:
|
||||
structure = Structure()
|
||||
structure_form = StructureForm(request.POST, instance=structure)
|
||||
if structure_form.is_valid():
|
||||
structure_form.save()
|
||||
res['result'] = True
|
||||
return HttpResponse(json.dumps(res), content_type='application/json')
|
||||
|
||||
|
||||
class StructureListView(LoginRequiredMixin, View):
|
||||
|
||||
def get(self, request):
|
||||
fields = ['id', 'name', 'type', 'parent__name']
|
||||
ret = dict(data=list(Structure.objects.values(*fields)))
|
||||
return HttpResponse(json.dumps(ret), content_type='application/json')
|
||||
|
||||
|
||||
class StructureDeleteView(LoginRequiredMixin, View):
|
||||
|
||||
def post(self, request):
|
||||
ret = dict(result=False)
|
||||
if 'id' in request.POST and request.POST['id']:
|
||||
id_list = map(int, request.POST['id'].split(','))
|
||||
Structure.objects.filter(id__in=id_list).delete()
|
||||
ret['result'] = True
|
||||
return HttpResponse(json.dumps(ret), content_type='application/json')
|
||||
|
||||
|
||||
class Structure2UserView(LoginRequiredMixin, View):
|
||||
|
||||
def get(self, request):
|
||||
if 'id' in request.GET and request.GET['id']:
|
||||
structure = get_object_or_404(Structure, pk=int(request.GET['id']))
|
||||
added_users = structure.userprofile_set.all()
|
||||
all_users = User.objects.all()
|
||||
un_add_users = set(all_users).difference(added_users)
|
||||
ret = dict(structure=structure, added_users=added_users, un_add_users=list(un_add_users))
|
||||
return render(request, 'system/structure/structure_user.html', ret)
|
||||
|
||||
def post(self, request):
|
||||
res = dict(result=False)
|
||||
id_list = None
|
||||
structure = get_object_or_404(Structure, pk=int(request.POST['id']))
|
||||
if 'to' in request.POST and request.POST.getlist('to', []):
|
||||
id_list = map(int, request.POST.getlist('to', []))
|
||||
structure.userprofile_set.clear()
|
||||
if id_list:
|
||||
for user in User.objects.filter(id__in=id_list):
|
||||
structure.userprofile_set.add(user)
|
||||
res['result'] = True
|
||||
return HttpResponse(json.dumps(res), content_type='application/json')
|
||||
54
apps/system/views_user.py
Normal file
54
apps/system/views_user.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# @Time : 2018/10/16 23:11
|
||||
# @Author : RobbieHan
|
||||
# @File : views_user.py
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.views.generic.base import View
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.contrib.auth import authenticate, login, logout
|
||||
from django.urls import reverse
|
||||
|
||||
from .forms import LoginForm
|
||||
from .mixin import LoginRequiredMixin
|
||||
|
||||
|
||||
class IndexView(LoginRequiredMixin, View):
|
||||
|
||||
def get(self, request):
|
||||
return render(request, 'index.html')
|
||||
|
||||
|
||||
class LoginView(View):
|
||||
|
||||
def get(self, request):
|
||||
if not request.user.is_authenticated:
|
||||
return render(request, 'system/users/login.html')
|
||||
else:
|
||||
return HttpResponseRedirect('/')
|
||||
|
||||
def post(self, request):
|
||||
redirect_to = request.GET.get('next', '/')
|
||||
login_form = LoginForm(request.POST)
|
||||
ret = dict(login_form=login_form)
|
||||
if login_form.is_valid():
|
||||
user_name = request.POST['username']
|
||||
pass_word = request.POST['password']
|
||||
user = authenticate(username=user_name, password=pass_word)
|
||||
if user is not None:
|
||||
if user.is_active:
|
||||
login(request, user)
|
||||
return HttpResponseRedirect(redirect_to)
|
||||
else:
|
||||
ret['msg'] = '用户未激活!'
|
||||
else:
|
||||
ret['msg'] = '用户名或密码错误!'
|
||||
else:
|
||||
ret['msg'] = '用户和密码不能为空!'
|
||||
return render(request, 'system/users/login.html', ret)
|
||||
|
||||
|
||||
class LogoutView(View):
|
||||
|
||||
def get(self, request):
|
||||
logout(request)
|
||||
return HttpResponseRedirect(reverse('login'))
|
||||
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -11,10 +11,12 @@ https://docs.djangoproject.com/en/2.1/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
|
||||
@@ -37,6 +39,7 @@ INSTALLED_APPS = [
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'system',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@@ -51,6 +54,8 @@ MIDDLEWARE = [
|
||||
|
||||
ROOT_URLCONF = 'sandboxMP.urls'
|
||||
|
||||
AUTH_USER_MODEL = 'system.UserProfile'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
@@ -121,3 +126,9 @@ USE_TZ = False
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
|
||||
|
||||
MEDIA_URL = '/media/'
|
||||
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
|
||||
LOGIN_URL = '/login/'
|
||||
|
||||
@@ -14,8 +14,25 @@ Including another URLconf
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path
|
||||
from django.urls import path, include
|
||||
from django.conf import settings
|
||||
from django.urls import re_path
|
||||
from django.views.static import serve
|
||||
|
||||
from system.views_user import IndexView, LoginView, LogoutView
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('', IndexView.as_view(), name='index'),
|
||||
path('login/', LoginView.as_view(), name='login'),
|
||||
path('logout/', LogoutView.as_view(), name='logout'),
|
||||
path('system/', include('system.urls', namespace='system')),
|
||||
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
urlpatterns += [
|
||||
re_path(r'^media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT}),
|
||||
|
||||
]
|
||||
252
templates/system/structure/structure.html
Normal file
252
templates/system/structure/structure.html
Normal file
@@ -0,0 +1,252 @@
|
||||
{% extends "base-left.html" %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'plugins/datatables/jquery.dataTables.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div id="devlist">
|
||||
<div class="box box-primary" id="liebiao">
|
||||
<div class="box-header">
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnCreate" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-plus"></i>新增
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div class="btn-group pull-left"> </div>
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnDelete" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-trash"></i>删除
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<table id="dtbList" class="display" cellspacing="0" width="100%">
|
||||
<thead>
|
||||
<tr valign="middle">
|
||||
<th><input type="checkbox" id="checkAll"></th>
|
||||
<th>ID</th>
|
||||
<th>名称</th>
|
||||
<th>类别</th>
|
||||
<th>所属</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<br> <br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- /.content -->
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{% static 'plugins/datatables/jquery.dataTables.min.js' %}"></script>
|
||||
<script src="{% static 'plugins/datatables/dataTables.const.js' %}"></script>
|
||||
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var oDataTable = null;
|
||||
$(function () {
|
||||
oDataTable = initTable();
|
||||
|
||||
function initTable() {
|
||||
var oTable = $('#dtbList').DataTable($.extend(true, {},
|
||||
DATATABLES_CONSTANT.DATA_TABLES.DEFAULT_OPTION,
|
||||
{
|
||||
ajax: {
|
||||
"url": "{% url 'system:basic-structure-list' %}",
|
||||
|
||||
},
|
||||
columns: [
|
||||
DATATABLES_CONSTANT.DATA_TABLES.COLUMN.CHECKBOX,
|
||||
{
|
||||
data: "id",
|
||||
width: "5%",
|
||||
},
|
||||
{
|
||||
data: "name",//parent
|
||||
width: "20%",
|
||||
},
|
||||
|
||||
{
|
||||
data: "type",
|
||||
render: function (data, type, row, meta) {
|
||||
if (data == 'unit') {
|
||||
return "单位";
|
||||
} else if (data == 'department') {
|
||||
return "部门";
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
data: "parent__name",
|
||||
},
|
||||
|
||||
{
|
||||
data: "id",
|
||||
width: "12%",
|
||||
bSortable: "false",
|
||||
render: function (data, type, row, meta) {
|
||||
var ret = "";
|
||||
var ret = "<button title='详情-编辑' onclick='doUpdate("
|
||||
+ data + ")'><i class='glyphicon glyphicon-pencil'></i></button>";
|
||||
ret = ret + "<button title='关联用户' onclick='doAddUser("
|
||||
+ data + ")'><i class='glyphicon glyphicon-user'></i></button>";
|
||||
ret = ret + "<button title='删除' onclick='doDelete("
|
||||
+ data + ")'><i class='glyphicon glyphicon-trash'></i></button>";
|
||||
return ret;
|
||||
}
|
||||
}],
|
||||
"order": [
|
||||
[1, 'id']
|
||||
],
|
||||
}));
|
||||
return oTable;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$("#btnCreate").click(function () {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '新增',
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
area: ['800px', '400px'],
|
||||
content: "{% url 'system:basic-structure-create' %}",
|
||||
end: function () {
|
||||
//新增内容,弹窗关闭后刷新oDatable
|
||||
oDataTable.ajax.reload();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//checkbox全选
|
||||
$("#checkAll").on("click", function () {
|
||||
if ($(this).prop("checked") === true) {
|
||||
$("input[name='checkList']").prop("checked", $(this).prop("checked"));
|
||||
$('#example tbody tr').addClass('selected');
|
||||
} else {
|
||||
$("input[name='checkList']").prop("checked", false);
|
||||
$('#example tbody tr').removeClass('selected');
|
||||
}
|
||||
});
|
||||
|
||||
//批量删除
|
||||
$("#btnDelete").click(function () {
|
||||
if ($("input[name='checkList']:checked").length == 0) {
|
||||
layer.msg("请选择要删除的记录");
|
||||
return;
|
||||
}
|
||||
|
||||
var arrId = new Array();
|
||||
$("input[name='checkList']:checked").each(function () {
|
||||
//alert($(this).val());
|
||||
arrId.push($(this).val());
|
||||
});
|
||||
|
||||
sId = arrId.join(',');
|
||||
|
||||
layer.alert('确定删除吗?', {
|
||||
title: '提示'
|
||||
, icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
|
||||
, time: 0 //不自动关闭
|
||||
, btn: ['YES', 'NO']
|
||||
, yes: function (index) {
|
||||
layer.close(index);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "{% url 'system:basic-structure-delete' %}",
|
||||
data: {"id": sId, csrfmiddlewaretoken: '{{ csrf_token }}'},
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert("操作成功", {icon: 1});
|
||||
oDataTable.ajax.reload();
|
||||
} else {
|
||||
//alert(msg.message);
|
||||
layer.alert("操作失败", {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//删除单个数据
|
||||
function doDelete(id) {
|
||||
layer.alert('确定删除吗?', {
|
||||
title: '提示'
|
||||
, icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
|
||||
, time: 0 //不自动关闭
|
||||
, btn: ['YES', 'NO']
|
||||
, yes: function (index) {
|
||||
layer.close(index);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "{% url 'system:basic-structure-delete' %}",
|
||||
data: {"id": id, csrfmiddlewaretoken: '{{ csrf_token }}'}, //防止post数据时报 csrf_token 403
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('删除成功', {icon: 1});
|
||||
oDataTable.ajax.reload();
|
||||
} else {
|
||||
//alert(msg.message);
|
||||
layer.alert('删除失败', {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function doUpdate(id) {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '编辑',
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
area: ['800px', '400px'],
|
||||
content: ["{% url 'system:basic-structure-create' %}" + '?id=' + id, 'no'],
|
||||
end: function () {
|
||||
oDataTable.ajax.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function doAddUser(id) {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '编辑',
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
area: ['800px', '600px'],
|
||||
content: ["{% url 'system:basic-structure-add_user' %}" + '?id=' + id, 'no'],
|
||||
end: function () {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
94
templates/system/structure/structure_create.html
Normal file
94
templates/system/structure/structure_create.html
Normal file
@@ -0,0 +1,94 @@
|
||||
{% extends 'base-layer.html' %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="box box-danger">
|
||||
<form class="form-horizontal" id="addForm" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="box-body">
|
||||
<fieldset>
|
||||
<legend>
|
||||
<h4>组织架构信息</h4>
|
||||
</legend>
|
||||
<input type="hidden" name="id" value="{{ structure.id }}" />
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">名称</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="name" type="text" value="{{ structure.name }}" />
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">类别</label>
|
||||
<div class="col-sm-3">
|
||||
<select class="form-control" name="type">
|
||||
<option value={{ structure.type }}> {{ structure.get_type_display|default:"--类别--" }} </option>
|
||||
<option value="unit">单位</option>
|
||||
<option value="department">部门</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">所属</label>
|
||||
<div class="col-sm-3">
|
||||
<select class="form-control" name="parent">
|
||||
<option value={{ structure.parent_id|default_if_none:"" }}> {{ structure.parent.name|default:"" }}
|
||||
<option></option>
|
||||
{% for stru in structure_all %}
|
||||
<option value={{ stru.id }}> {{ stru.name }} </option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
</div>
|
||||
<div class="box-footer ">
|
||||
<div class="row span7 text-center ">
|
||||
<button type="button" id="btnCancel" class="btn btn-default margin-right ">重置</button>
|
||||
<button type="button" id="btnSave" class="btn btn-info margin-right ">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script type="text/javascript">
|
||||
|
||||
$("#btnSave").click(function () {
|
||||
var data = $("#addForm").serialize();
|
||||
$.ajax({
|
||||
type: $("#addForm").attr('method'),
|
||||
url: "{% url 'system:basic-structure-create' %}",
|
||||
data: data,
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('数据保存成功!', {icon: 1}, function (index) {
|
||||
parent.layer.closeAll(); //关闭所有弹窗
|
||||
});
|
||||
} else {
|
||||
layer.alert('数据保存失败', {icon: 5});
|
||||
//$('errorMessage').html(msg.message)
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/*点取消刷新新页面*/
|
||||
$("#btnCancel").click(function () {
|
||||
window.location.reload();
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
103
templates/system/structure/structure_user.html
Normal file
103
templates/system/structure/structure_user.html
Normal file
@@ -0,0 +1,103 @@
|
||||
{% extends 'base-layer.html' %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
|
||||
{% endblock %}
|
||||
{% block main %}
|
||||
<div class="box box-danger">
|
||||
<form class="form-horizontal" id="selectUsersForm" action="" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name='id' value="{{ structure.id }}"/>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-xs-5">
|
||||
<label class="control-label">可选用户:</label>
|
||||
<select name="from" id="multiselect" class="form-control" size="18" multiple="multiple">
|
||||
{% for item in un_add_users %}
|
||||
<option value="{{ item.id }}">{{ item.name }}({{ item.username }})</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<br><br><br><br><br><br>
|
||||
<button type="button" id="multiselect_rightAll" class="btn btn-block"><i
|
||||
class="glyphicon glyphicon-forward"></i></button>
|
||||
<button type="button" id="multiselect_rightSelected" class="btn btn-block"><i
|
||||
class="glyphicon glyphicon-chevron-right"></i></button>
|
||||
<button type="button" id="multiselect_leftSelected" class="btn btn-block"><i
|
||||
class="glyphicon glyphicon-chevron-left"></i></button>
|
||||
<button type="button" id="multiselect_leftAll" class="btn btn-block"><i
|
||||
class="glyphicon glyphicon-backward"></i></button>
|
||||
</div>
|
||||
<div class="col-xs-5">
|
||||
<label class="control-label">{{structure.name}}-已绑定用户:</label>
|
||||
<select name="to" id="multiselect_to" class="form-control" size="18" multiple="multiple">
|
||||
{% for item in added_users %}
|
||||
<option value="{{ item.id }}">{{ item.name }}({{ item.username }})</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 margin-top-5">
|
||||
<p class="text-maroon">*注意:一个用户只能隶属一个部门,如果选择的用户已存在部门,用户将会从原有部门移出</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer ">
|
||||
<div class="row span7 text-center ">
|
||||
<button type="button" id="btnCancel" class="btn btn-default margin-right ">重置</button>
|
||||
<button type="button" id="btnSave" class="btn btn-info margin-right ">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{% static 'plugins/select/multiselect.min.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
//初始化多选列表
|
||||
$('#multiselect').multiselect({
|
||||
search: {
|
||||
left: '<input type="text" class="form-control" placeholder="Search..." />',
|
||||
right: '<input type="text" class="form-control" placeholder="Search..." />',
|
||||
},
|
||||
fireSearch: function (value) {
|
||||
return value.length > 3;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
$("#btnSave").click(function () {
|
||||
$('#multiselect_to option').prop('selected', true);
|
||||
var data = $("#selectUsersForm").serialize();
|
||||
console.log(data);
|
||||
$.ajax({
|
||||
type: $("#selectUsersForm").attr('method'),
|
||||
url: "{% url 'system:basic-structure-add_user' %}",
|
||||
data: data,
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('操作成功', {icon: 1});
|
||||
} else {
|
||||
//alert(msg.message);
|
||||
layer.alert('操作失败', {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/*点取消刷新新页面*/
|
||||
$("#btnCancel").click(function () {
|
||||
window.location.reload();
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
21
templates/system/system_index.html
Normal file
21
templates/system/system_index.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{% extends "base-left.html" %}
|
||||
{% load staticfiles %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
系统管理首页:system_index,content是页面定义的主要区域,
|
||||
头部和底部内容以及导航栏都是通过模板继承的,之后的所有
|
||||
功能前端页面都是在content内进行编辑。
|
||||
</section>
|
||||
|
||||
<!-- /.content -->
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user