10 Commits
v1.02 ... v1.12

Author SHA1 Message Date
RobbieHan
1526767e87 menu create 2018-11-09 23:22:13 +08:00
RobbieHan
64a8fab611 user management 2018-11-06 12:42:31 +08:00
RobbieHan
45630bd451 structure2user 2018-10-23 19:10:55 +08:00
RobbieHan
b85d89642d structure update & delete 2018-10-21 16:46:38 +08:00
RobbieHan
832c55ab34 structure list 2018-10-20 14:32:30 +08:00
RobbieHan
f72efee2e1 structure create 2018-10-19 19:22:54 +08:00
RobbieHan
2bba133771 SystemIndex 2018-10-17 23:27:14 +08:00
RobbieHan
2261bc6b3a workspace 2018-10-17 15:23:04 +08:00
RobbieHan
005b62a01e workspace 2018-10-17 15:22:21 +08:00
RobbieHan
0b04685f2f authenticate 2018-10-17 15:19:17 +08:00
48 changed files with 2721 additions and 1240 deletions

4
.idea/sandboxMP.iml generated
View File

@@ -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>

1745
.idea/workspace.xml generated

File diff suppressed because it is too large Load Diff

3
apps/__init__.py Normal file
View File

@@ -0,0 +1,3 @@
# @Time : 2018/10/17 14:54
# @Author : RobbieHan
# @File : __init__.py.py

Binary file not shown.

Binary file not shown.

21
apps/custom.py Normal file
View File

@@ -0,0 +1,21 @@
# @Time : 2018/11/9 22:06
# @Author : RobbieHan
# @File : custom.py
import json
from django.views.generic import CreateView
from django.shortcuts import HttpResponse
from system.mixin import LoginRequiredMixin
class SimpleInfoCreateView(LoginRequiredMixin, CreateView):
def post(self, request, *args, **kwargs):
res = dict(result=False)
form = self.get_form()
if form.is_valid():
form.save()
res['result'] = True
return HttpResponse(json.dumps(res), content_type='application/json')

0
apps/system/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

3
apps/system/admin.py Normal file
View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

5
apps/system/apps.py Normal file
View File

@@ -0,0 +1,5 @@
from django.apps import AppConfig
class SystemConfig(AppConfig):
name = 'apps.system'

127
apps/system/forms.py Normal file
View File

@@ -0,0 +1,127 @@
# @Time : 2018/10/17 23:13
# @Author : RobbieHan
# @File : forms.py
import re
from django import forms
from django.contrib.auth import get_user_model
from .models import Structure, Menu
User = get_user_model()
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']
class UserCreateForm(forms.ModelForm):
password = forms.CharField(
required=True,
min_length=6,
max_length=20,
error_messages={
"required": "密码不能为空",
"min_length": "密码长度最少6位数",
}
)
confirm_password = forms.CharField(
required=True,
min_length=6,
max_length=20,
error_messages={
"required": "确认密码不能为空",
"min_length": "密码长度最少6位数",
}
)
class Meta:
model = User
fields = [
'name', 'gender', 'birthday', 'username', 'mobile', 'email',
'department', 'post', 'superior', 'is_active', 'roles', 'password'
]
error_messages = {
"name": {"required": "姓名不能为空"},
"username": {"required": "用户名不能为空"},
"email": {"required": "邮箱不能为空"},
"mobile": {
"required": "手机号码不能为空",
"max_length": "输入有效的手机号码",
"min_length": "输入有效的手机号码"
}
}
def clean(self):
cleaned_data = super(UserCreateForm, self).clean()
username = cleaned_data.get("username")
mobile = cleaned_data.get("mobile", "")
email = cleaned_data.get("email")
password = cleaned_data.get("password")
confirm_password = cleaned_data.get("confirm_password")
if User.objects.filter(username=username).count():
raise forms.ValidationError('用户名:{}已存在'.format(username))
if password != confirm_password:
raise forms.ValidationError("两次密码输入不一致")
if User.objects.filter(mobile=mobile).count():
raise forms.ValidationError('手机号码:{}已存在'.format(mobile))
REGEX_MOBILE = "^1[3578]\d{9}$|^147\d{8}$|^176\d{8}$"
if not re.match(REGEX_MOBILE, mobile):
raise forms.ValidationError("手机号码非法")
if User.objects.filter(email=email).count():
raise forms.ValidationError('邮箱:{}已存在'.format(email))
class UserUpdateForm(forms.ModelForm):
class Meta:
model = User
fields = [
'name', 'gender', 'birthday', 'username', 'mobile', 'email',
'department', 'post', 'superior', 'is_active', 'roles'
]
class PasswordChangeForm(forms.Form):
password = forms.CharField(
required=True,
min_length=6,
max_length=20,
error_messages={
"required": u"密码不能为空"
})
confirm_password = forms.CharField(
required=True,
min_length=6,
max_length=20,
error_messages={
"required": u"确认密码不能为空"
})
def clean(self):
cleaned_data = super(PasswordChangeForm, self).clean()
password = cleaned_data.get("password")
confirm_password = cleaned_data.get("confirm_password")
if password != confirm_password:
raise forms.ValidationError("两次密码输入不一致")
class MenuForm(forms.ModelForm):
class Meta:
model = Menu
fields = '__all__'

View 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'),
),
]

View File

12
apps/system/mixin.py Normal file
View 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
View 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
View File

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

27
apps/system/urls.py Normal file
View File

@@ -0,0 +1,27 @@
from django.urls import path, re_path
from .views import SystemView
from . import views_structure, views_user, views_menu
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'),
path('basic/user/', views_user.UserView.as_view(), name='basic-user'),
path('basic/user/list/', views_user.UserListView.as_view(), name='basic-user-list'),
path('basic/user/create/', views_user.UserCreateView.as_view(), name='basic-user-create'),
path('basic/user/detail/', views_user.UserDetailView.as_view(), name='basic-user-detail'),
path('basic/user/update/', views_user.UserUpdateView.as_view(), name='basic-user-update'),
path('basic/user/password_change/', views_user.PasswordChangeView.as_view(), name='basic-user-password_change'),
path('basic/user/delete/', views_user.UserDeleteView.as_view(), name='basic-user-delete'),
path('basic/user/enable/', views_user.UserEnableView.as_view(), name='basic-user-enable'),
path('basic/user/disable/', views_user.UserDisableView.as_view(), name='basic-user-disable'),
path('rbac/menu/create/', views_menu.MenuCreateView.as_view(), name='rbac-menu-create'),
]

11
apps/system/views.py Normal file
View 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')

17
apps/system/views_menu.py Normal file
View File

@@ -0,0 +1,17 @@
# @Time : 2018/11/9 12:24
# @Author : RobbieHan
# @File : views.menu.py
from apps.custom import SimpleInfoCreateView
from .models import Menu
class MenuCreateView(SimpleInfoCreateView):
model = Menu
fields = '__all__'
extra_context = dict(menu_all=Menu.objects.all())

View 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')

218
apps/system/views_user.py Normal file
View File

@@ -0,0 +1,218 @@
# @Time : 2018/10/16 23:11
# @Author : RobbieHan
# @File : views_user.py
import re
import json
from django.shortcuts import render, HttpResponse
from django.views.generic.base import View, TemplateView
from django.http import HttpResponseRedirect
from django.contrib.auth import authenticate, login, logout, get_user_model
from django.urls import reverse
from django.contrib.auth.hashers import make_password
from django.shortcuts import get_object_or_404
from django.db.models import Q
from .forms import LoginForm, UserCreateForm, UserUpdateForm, PasswordChangeForm
from .mixin import LoginRequiredMixin
from .models import Structure, Role
User = get_user_model()
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'))
class UserView(LoginRequiredMixin, TemplateView):
template_name = 'system/users/user.html'
class UserListView(LoginRequiredMixin, View):
def get(self, request):
fields = ['id', 'name', 'gender', 'mobile', 'email', 'department__name', 'post', 'superior__name', 'is_active']
filters = dict()
if 'select' in request.GET and request.GET['select']:
filters['is_active'] = request.GET['select']
ret = dict(data=list(User.objects.filter(**filters).values(*fields)))
return HttpResponse(json.dumps(ret), content_type='application/json')
class UserCreateView(LoginRequiredMixin, View):
"""
添加用户
"""
def get(self, request):
users = User.objects.exclude(username='admin')
structures = Structure.objects.values()
roles = Role.objects.values()
ret = {
'users': users,
'structures': structures,
'roles': roles,
}
return render(request, 'system/users/user_create.html', ret)
def post(self, request):
user_create_form = UserCreateForm(request.POST)
if user_create_form.is_valid():
new_user = user_create_form.save(commit=False)
new_user.password = make_password(user_create_form.cleaned_data['password'])
new_user.save()
user_create_form.save_m2m()
ret = {'status': 'success'}
else:
pattern = '<li>.*?<ul class=.*?><li>(.*?)</li>'
errors = str(user_create_form.errors)
user_create_form_errors = re.findall(pattern, errors)
ret = {
'status': 'fail',
'user_create_form_errors': user_create_form_errors[0]
}
return HttpResponse(json.dumps(ret), content_type='application/json')
class UserDetailView(LoginRequiredMixin, View):
def get(self, request):
user = get_object_or_404(User, pk=int(request.GET['id']))
users = User.objects.exclude(Q(id=int(request.GET['id'])) | Q(username='admin'))
structures = Structure.objects.values()
roles = Role.objects.values()
user_roles = user.roles.values()
ret = {
'user': user,
'structures': structures,
'users': users,
'roles': roles,
'user_roles': user_roles
}
return render(request, 'system/users/user_detail.html', ret)
class UserUpdateView(LoginRequiredMixin, View):
def post(self, request):
if 'id' in request.POST and request.POST['id']:
user = get_object_or_404(User, pk=int(request.POST['id']))
else:
user = get_object_or_404(User, pk=int(request.user.id))
user_update_form = UserUpdateForm(request.POST, instance=user)
if user_update_form.is_valid():
user_update_form.save()
ret = {"status": "success"}
else:
ret = {"status": "fail", "message": user_update_form.errors}
return HttpResponse(json.dumps(ret), content_type="application/json")
class PasswordChangeView(LoginRequiredMixin, View):
def get(self, request):
ret = dict()
if 'id' in request.GET and request.GET['id']:
user = get_object_or_404(User, pk=int(request.GET.get('id')))
ret['user'] = user
return render(request, 'system/users/passwd_change.html', ret)
def post(self, request):
if 'id' in request.POST and request.POST['id']:
user = get_object_or_404(User, pk=int(request.POST['id']))
form = PasswordChangeForm(request.POST)
if form.is_valid():
new_password = request.POST['password']
user.set_password(new_password)
user.save()
ret = {'status': 'success'}
else:
pattern = '<li>.*?<ul class=.*?><li>(.*?)</li>'
errors = str(form.errors)
password_change_form_errors = re.findall(pattern, errors)
ret = {
'status': 'fail',
'password_change_form_errors': password_change_form_errors[0]
}
return HttpResponse(json.dumps(ret), content_type='application/json')
class UserDeleteView(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(','))
User.objects.filter(id__in=id_list).delete()
ret['result'] = True
return HttpResponse(json.dumps(ret), content_type='application/json')
class UserEnableView(LoginRequiredMixin, View):
"""
启用用户:单个或批量启用
"""
def post(self, request):
if 'id' in request.POST and request.POST['id']:
id_nums = request.POST.get('id')
queryset = User.objects.extra(where=["id IN(" + id_nums + ")"])
queryset.filter(is_active=False).update(is_active=True)
ret = {'result': 'True'}
return HttpResponse(json.dumps(ret), content_type='application/json')
class UserDisableView(LoginRequiredMixin, View):
"""
启用用户:单个或批量启用
"""
def post(self, request):
if 'id' in request.POST and request.POST['id']:
id_nums = request.POST.get('id')
queryset = User.objects.extra(where=["id IN(" + id_nums + ")"])
queryset.filter(is_active=True).update(is_active=False)
ret = {'result': 'True'}
return HttpResponse(json.dumps(ret), content_type='application/json')

Binary file not shown.

View File

@@ -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/'

View File

@@ -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}),
]

View File

@@ -8,7 +8,7 @@ scratch. This page gets rid of all links and provides the needed markup only.
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>SandBoxOA</title>
<title>SandBoxMP</title>
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'plugins/font-awesome/css/font-awesome.min.css' %}">
@@ -52,7 +52,7 @@ scratch. This page gets rid of all links and provides the needed markup only.
<div class="menu-info">
<h4 class="control-sidebar-subheading">SandBox</h4>
<p>沙盒协同办公平台</p>
<p>沙盒运维管理平台</p>
</div>
</a>
</li>

View File

@@ -0,0 +1,101 @@
{% extends 'base-layer.html' %}
{% load staticfiles %}
{% block css %}
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
<!-- iCheck for checkboxes and radio inputs -->
{% 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>
<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"/>
</div>
<label class="col-sm-2 control-label">代码</label>
<div class="col-sm-3">
<input class="form-control" name="code" type="text"/>
</div>
</div>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">图标</label>
<div class="col-sm-3">
<input class="form-control" name="icon" type="text" />
</div>
<label class="col-sm-2 control-label">父菜单</label>
<div class="col-sm-3">
<select class="form-control select2" name="parent">
<option value="{{ menu.parent.id }}">{{ menu.parent.name }}</option>
{% for parent_menu in menu_all %}
<option value={{ parent_menu.id }}> {{ parent_menu.name }} </option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">URL</label>
<div class="col-sm-8">
<input class="form-control" name="url" type="text" />
</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 src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
<script type="text/javascript">
$("#btnSave").click(function () {
var data = $("#addForm").serialize();
$.ajax({
type: $("#addForm").attr('method'),
url: "{% url 'system:rbac-menu-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();
});
$(function () {
//Initialize Select2 Elements
$(".select2").select2();
});
</script>
{% endblock %}

View 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">&nbsp</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 %}

View 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 %}

View 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 %}

View File

@@ -0,0 +1,21 @@
{% extends "base-left.html" %}
{% load staticfiles %}
{% block content %}
<!-- Main content -->
<section class="content">
系统管理首页system_indexcontent是页面定义的主要区域
头部和底部内容以及导航栏都是通过模板继承的,之后的所有
功能前端页面都是在content内进行编辑。
</section>
<!-- /.content -->
{% endblock %}
{% block javascripts %}
{% endblock %}

View File

@@ -0,0 +1,95 @@
{% extends 'base-layer.html' %}
{% load staticfiles %}
{% block css %}
{% endblock %}
{% block main %}
<div class="box box-danger">
<form class="form-horizontal" id="addForm" method="post">
{% csrf_token %}
<input type="hidden" name='id' value="{{ user.id }}"/>
<input type="hidden" name='user' value="save"/>
<div class="box-body">
<fieldset>
<legend>
<h4>基本信息</h4>
</legend>
<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" readonly="readonly"
value="{{ user.name }}"/>
</div>
<label class="col-sm-2 control-label">用户名</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="username" readonly="readonly"
value="{{ user.username }}"/>
</div>
</div>
<h4>密码信息</h4>
</legend>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">密码</label>
<div class="col-sm-3">
<input class="form-control" name="password" type="password" value=""/>
</div>
<label class="col-sm-2 control-label">确认密码</label>
<div class="col-sm-3">
<input class="form-control" name="confirm_password" type="password" value=""/>
</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 src="{% static 'plugins/combo-select/jquery.combo.select.js' %}"></script>
<script src="{% static 'bootstrap/js/bootstrap-datetimepicker.js' %}"></script>
<script type="text/javascript">
$("#btnSave").click(function () {
var data = $("#addForm").serialize();
$.ajax({
type: $("#addForm").attr('method'),
url: "{% url 'system:basic-user-password_change' %}",
data: data,
cache: false,
success: function (msg) {
if (msg.status == 'success') {
layer.alert('密码修改成功!', {icon: 1}, function (index) {
parent.layer.closeAll();
});
} else if (msg.status == 'fail') {
layer.alert(msg.password_change_form_errors, {icon: 5});
//$('errorMessage').html(msg.message)
}
return;
}
});
});
/*点取消刷新页面*/
$("#btnCancel").click(function () {
window.location.reload();
})
</script>
{% endblock %}

View File

@@ -0,0 +1,396 @@
{% 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="btnRefresh" class="btn btn-default">
<i class="glyphicon glyphicon-repeat"></i>刷新
</button>
</div>
<div class="btn-group pull-left">&nbsp</div>
<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">&nbsp</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 class="btn-group pull-left">&nbsp</div>
<div class="btn-group pull-left">
<button type="button" id="btnEnable" class="btn btn-default">
<i class="glyphicon glyphicon-ok-circle"></i>启用
</button>
<button type="button" id="btnDisable" class="btn btn-default">
<i class="glyphicon glyphicon-ban-circle"></i>禁用
</button>
</div>
<div class="btn-group pull-right">
<form class="form-inline">
<div class="form-group">
<label>用户状态:</label>
<select id="select" name="select" class="form-control">
<option style='text-align:center' value=''>-----所有-----</option>
<option value="True">启用</option>
<option value="False">禁用</option>
</select>
</div>
</form>
</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>
<th>部门</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-user-list' %}",
"data": function (d) {
d.select = $("#select").val();
}
},
columns: [
DATATABLES_CONSTANT.DATA_TABLES.COLUMN.CHECKBOX,
{
data: "id",
width: "5%",
},
{
data: "name",//parent
width: "10%",
},
{
data: "gender",
width: "10%",
render: function (data, type, row, meta) {
if (data == 'male') {
return "男";
} else {
return "女";
}
}
},
{
data: "mobile",
},
{
data: "email",
},
{
data: "department__name",
},
{
data: "post",
},
{
data: "superior__name",
},
{
data: "is_active",
render: function (data) {
if (data == true) {
return "启用";
} else {
return "禁用";
}
}
},
{
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 name='btnChangepasswd' title='修改密码' onclick='doChangepasswd("
+ data + ")'><i class='glyphicon glyphicon-asterisk'></i></button>";
ret = ret + "<button name='btnConfig' title='删除' onclick='doDelete("
+ data + ")'><i class='glyphicon glyphicon-trash'></i></button>";
return ret;
}
}],
"order": [
[2, 'desc']
],
}));
return oTable;
}
});
</script>
<script type="text/javascript">
$("#btnCreate").click(function () {
var div = layer.open({
type: 2,
title: '新增',
shadeClose: false,
maxmin: true,
area: ['800px', '720px'],
content: '/system/basic/user/create',
end: function () {
//关闭时做的事情
oDataTable.ajax.reload();
}
});
layer.full(div)
});
// 跳转到用户详情页面
function doUpdate(id) {
var div = layer.open({
type: 2,
title: '编辑',
shadeClose: false,
maxmin: true,
area: ['800px', '650px'],
content: ["{% url 'system:basic-user-detail' %}" + '?id=' + id, 'no'],
end: function () {
oDataTable.ajax.reload();
}
});
layer.full(div)
}
function doChangepasswd(id) {
layer.open({
type: 2,
title: '编辑',
shadeClose: false,
maxmin: true,
area: ['850px', '350px'],
content: ["{% url 'system:basic-user-password_change' %}" + '?id=' + id, 'no'],
end: function () {
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-user-delete' %}",
data: {"id": sId, csrfmiddlewaretoken: '{{ csrf_token }}'},
cache: false,
success: function (msg) {
if (msg.result) {
layer.alert("操作成功");
oDataTable.ajax.reload();
} else {
//alert(msg.message);
layer.alert("操作失败");
}
return;
}
});
}
});
});
//批量启用
$("#btnEnable").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-user-enable' %}",
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: 5});
}
return;
}
});
}
});
});
//批量禁用
$("#btnDisable").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-user-disable' %}",
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: 5});
}
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-user-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: 5});
}
return;
}
});
}
});
}
$("#select").change(function () {
//alert($("#select").val())
oDataTable.ajax.reload();
});
</script>
{% endblock %}

View File

@@ -0,0 +1,202 @@
{% extends 'base-layer.html' %}
{% load staticfiles %}
{% block css %}
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap-datetimepicker.min.css' %}">
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
{% endblock %}
{% block main %}
<div class="box box-danger">
<form class="form-horizontal" id="addForm" method="post">
{% csrf_token %}
<input type="hidden" name='id' value="{{ user.id }}"/>
<input type="hidden" name='user' value="save"/>
<div class="box-body">
<fieldset>
<legend>
<h4>基本信息</h4>
</legend>
<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=""/>
</div>
<label class="col-sm-2 control-label">性别</label>
<div class="col-sm-3">
<select class="form-control" name="gender">
<option value="male"></option>
<option value="famale"></option>
</select>
</div>
</div>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">生日</label>
<div class="col-sm-3">
<input type="text" class="form-control pull-right form_datetime" name="birthday"/>
</div>
<label class="col-sm-2 control-label">用户名</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="username"/>
</div>
</div>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">状态</label>
<div class="col-sm-6">
<label class="control-label">
<input type="radio" class="minimal" name="is_active" value="True" checked>启用
</label>
<label class="control-label">
<input type="radio" class="minimal" name="is_active" value="False">禁用
</label>
</div>
</div>
<legend>
<h4>密码信息</h4>
</legend>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">密码</label>
<div class="col-sm-3">
<input class="form-control" name="password" type="password" value=""/>
</div>
<label class="col-sm-2 control-label">确认密码</label>
<div class="col-sm-3">
<input class="form-control" name="confirm_password" type="password" value=""/>
</div>
</div>
<legend>
<h4>联系信息</h4>
</legend>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">手机</label>
<div class="col-sm-3">
<input class="form-control" name="mobile" type="text"/>
</div>
<label class="col-sm-2 control-label">邮箱</label>
<div class="col-sm-3">
<input class="form-control" name="email" type="text"/>
</div>
</div>
<legend>
<h4>职员信息</h4>
</legend>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">入职日期</label>
<div class="col-sm-3">
<input type="text" class="form-control pull-right form_datetime" name="joined_date"/>
</div>
<label class="col-sm-2 control-label">部门</label>
<div class="col-sm-3">
<select class="form-control select2" style="width:100%;" name="department">
<option value="">--部门--</option>
{% for structure in structures %}
<option value="{{ structure.id }}">{{ structure.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">岗位</label>
<div class="col-sm-3">
<input class="form-control" name="post" type="text"/>
</div>
<label class="col-sm-2 control-label">上级</label>
<div class="col-sm-3">
<select class="form-control select2" style="width:100%;" name="superior">
<option value="">--上级--</option>
{% for user in users %}
<option value="{{ user.id }}">{{ user.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">所属角色组</label>
<div class="col-sm-6">
{% for role in roles %}
<label class="control-label">
<input type="checkbox" class="minimal" name="roles" value="{{ role.id }}"
{% if role in user_roles %}checked{% endif %}>
{{ role.name }}
</label>
{% endfor %}
</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 src="{% static 'bootstrap/js/bootstrap-datetimepicker.js' %}"></script>
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
<script type="text/javascript">
$("#btnSave").click(function () {
var data = $("#addForm").serialize();
$.ajax({
type: $("#addForm").attr('method'),
url: "{% url 'system:basic-user-create' %}",
data: data,
cache: false,
success: function (msg) {
if (msg.status == 'success') {
layer.alert('用户添加成功!', {icon: 1}, function (index) {
parent.layer.closeAll(); //关闭所有弹窗
});
} else if (msg.status == 'fail') {
layer.alert(msg.user_create_form_errors, {icon: 5});
//$('errorMessage').html(msg.message)
}
return;
}
});
});
/*点取消刷新新页面*/
$("#btnCancel").click(function () {
window.location.reload();
})
/*input 时间输入选择*/
$(".form_datetime").datetimepicker({
language: 'zh',
minView: 'month', //选择范围只到日期,不选择时分
//weekStart: 1,
//todayBtn: 1,
autoclose: 1,
todayHighlight: 1,
//startView: 2,
forceParse: 0,
showMeridian: 1,
format: 'yyyy-mm-dd'
}).on('changeDate', function (ev) {
$(this).datetimepicker('hide');
});
$(function () {
//Initialize Select2 Elements
$(".select2").select2();
});
</script>
{% endblock %}

View File

@@ -0,0 +1,192 @@
{% extends 'base-layer.html' %}
{% load staticfiles %}
{% block css %}
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap-datetimepicker.min.css' %}">
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
{% endblock %}
{% block main %}
<div class="box box-danger">
<form class="form-horizontal" id="addForm" method="post">
{% csrf_token %}
<input type="hidden" name='id' value="{{ user.id }}"/>
<input type="hidden" name='user' value="save"/>
<div class="box-body">
<fieldset>
<legend>
<h4>基本信息</h4>
</legend>
<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="{{ user.name }}"/>
</div>
<label class="col-sm-2 control-label">性别</label>
<div class="col-sm-3">
<select class="form-control" name="gender">
<option value={{ user.gender }}> {{ user.get_gender_display }} </option>
<option value="male"></option>
<option value="famale"></option>
</select>
</div>
</div>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">生日</label>
<div class="col-sm-3">
<input type="text" class="form-control pull-right form_datetime" name="birthday"
value="{{ user.birthday|date:"Y-m-d" }}"/>
</div>
<label class="col-sm-2 control-label">用户名</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="username" readonly="readonly"
value="{{ user.username }}"/>
</div>
</div>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">状态</label>
<div class="col-sm-6">
<label class="control-label">
<input type="radio" class="minimal" name="is_active" value="True"
{% ifequal user.is_active True %}checked{% endifequal %}>启用
</label>
<label class="control-label">
<input type="radio" class="minimal" name="is_active" value="False"
{% ifequal user.is_active False %}checked{% endifequal %}>禁用
</label>
</div>
</div>
<legend>
<h4 clase="">联系信息</h4>
</legend>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">手机</label>
<div class="col-sm-3">
<input class="form-control" name="mobile" readonly="readonly" type="text"
value="{{ user.mobile }}"/>
</div>
<label class="col-sm-2 control-label">邮箱</label>
<div class="col-sm-3">
<input class="form-control" name="email" type="text" value="{{ user.email }}"/>
</div>
</div>
<legend>
<h4>职员信息</h4>
</legend>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">入职日期</label>
<div class="col-sm-3">
<input type="text" class="form-control pull-right form_datetime" name="joined_date"
value="{{ user.joined_date|date:"Y-m-d" }}"/>
</div>
<label class="col-sm-2 control-label">部门</label>
<div class="col-sm-3">
<select class="form-control select2" style="width:100%;" name="department">
<option value="{{ user.department.id }}">{{ user.department.name|default:"--部门--" }}</option>
{% for structure in structures %}
<option value="{{ structure.id }}">{{ structure.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">岗位</label>
<div class="col-sm-3">
<input class="form-control" name="post" type="text"
value="{{ user.post|default_if_none:"" }}"/>
</div>
<label class="col-sm-2 control-label">上级</label>
<div class="col-sm-3">
<select class="form-control select2" style="width:100%;" name="superior">
<option value="{{ user.superior.id }}">{{ user.superior.name|default:"--上级--" }}</option>
{% for user in users %}
<option value="{{ user.id }}">{{ user.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">所属角色组</label>
<div class="col-sm-6">
{% for role in roles %}
<label class="control-label">
<input type="checkbox" class="minimal" name="roles" value="{{ role.id }}"
{% if role in user_roles %}checked{% endif %}>
{{ role.name }}
</label>
{% endfor %}
</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 src="{% static 'bootstrap/js/bootstrap-datetimepicker.js' %}"></script>
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
<script type="text/javascript">
/*点取消刷新新页面*/
$("#btnCancel").click(function () {
window.location.reload();
})
/*input 时间输入选择*/
$(".form_datetime").datetimepicker({
language: 'zh',
minView: 'month',
//weekStart: 1,
//todayBtn: 1,
autoclose: 1,
todayHighlight: 1,
//startView: 2,
forceParse: 0,
showMeridian: 1,
format: 'yyyy-mm-dd'
}).on('changeDate', function (ev) {
$(this).datetimepicker('hide');
});
$(function () {
//Initialize Select2 Elements
$(".select2").select2();
});
$("#btnSave").click(function () {
var data = $("#addForm").serialize();
$.ajax({
type: $("#addForm").attr('method'),
url: "{% url 'system:basic-user-update' %}",
data: data,
cache: false,
success: function (msg) {
if (msg.status == 'success') {
layer.alert('数据保存成功!', {icon: 1}, function (index) {
parent.layer.closeAll(); //关闭所有弹窗
});
} else if (msg.status == 'fail') {
layer.alert('数据保存失败', {icon: 5});
//$('errorMessage').html(msg.message)
}
return;
}
});
});
</script>
{% endblock %}