models.py
from django.db import models
# Create your models here.
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.contrib import auth
from django.core.exceptions import PermissionDenied
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager, User
from django.utils.translation import ugettext_lazy as _
from multiselectfield import MultiSelectField
#安装:pip install django-multiselectfield,针对choices多选用的
from django.utils.safestring import mark_safe
course_choices = (('LinuxL', 'Linux中高级'),
('PythonFullStack', 'Python高级全栈开发'),)
class_type_choices = (('fulltime', '脱产班',),
('online', '网络班'),
('weekend', '周末班',),)
source_type = (('qq', "qq群"),
('referral', "内部转介绍"),
('website', "官方网站"),
('baidu_ads', "百度推广"),
('office_direct', "直接上门"),
('WoM', "口碑"),
('public_class', "公开课"),
('website_luffy', "路飞官网"),
('others', "其它"),)
enroll_status_choices = (('signed', "已报名"),
('unregistered', "未报名"),
('studying', '学习中'),
('paid_in_full', "学费已交齐"))
seek_status_choices = (('A', '近期无报名计划'), ('B', '1个月内报名'), ('C', '2周内报名'), ('D', '1周内报名'),
('E', '定金'), ('F', '到班'), ('G', '全款'), ('H', '无效'),)
pay_type_choices = (('deposit', "订金/报名费"),
('tuition', "学费"),
('transfer', "转班"),
('dropout', "退学"),
('refund', "退款"),)
attendance_choices = (('checked', "已签到"),
('vacate', "请假"),
('late', "迟到"),
('absence', "缺勤"),
('leave_early', "早退"),)
score_choices = ((100, 'A+'),
(90, 'A'),
(85, 'B+'),
(80, 'B'),
(70, 'B-'),
(60, 'C+'),
(50, 'C'),
(40, 'C-'),
(0, ' D'),
(-1, 'N/A'),
(-100, 'COPY'),
(-1000, 'FAIL'),)
class UserInfo(AbstractUser):
#销售,班主任,讲师,三哥
telephone = models.CharField(max_length=32,null=True)
class Customer(models.Model):
"""
客户表(最开始的时候大家都是客户,销售就不停的撩你,你还没交钱就是个客户)
"""
qq = models.CharField(verbose_name='QQ', max_length=64, unique=True, help_text='QQ号必须唯一')
qq_name = models.CharField('QQ昵称', max_length=64, blank=True, null=True)
name = models.CharField('姓名', max_length=32, blank=True, null=True, help_text='学员报名后,请改为真实姓名')
sex_type = (('male', '男'), ('female', '女'))
sex = models.CharField("性别", choices=sex_type, max_length=16, default='male', blank=True, null=True) #存的是male或者female,字符串
birthday = models.DateField('出生日期', default=None, help_text="格式yyyy-mm-dd", blank=True, null=True)
phone = models.CharField('手机号', blank=True, null=True,max_length=32)
# phone = models.CharField('手机号', blank=True, null=True)
source = models.CharField('客户来源', max_length=64, choices=source_type, default='qq')
introduce_from = models.ForeignKey('self', verbose_name="转介绍自学员", blank=True, null=True) #self指的就是自己这个表,和下面写法是一样的效果
# introduce_from = models.ForeignKey('Customer', verbose_name="转介绍自学员", blank=True, null=True,on_delete=models.CASCADE)
course = MultiSelectField("咨询课程", choices=course_choices) #多选,并且存成一个列表的格式
# course = models.CharField("咨询课程", choices=course_choices) #如果你不想用上面的多选功能,可以使用Charfield来存
class_type = models.CharField("班级类型", max_length=64, choices=class_type_choices, default='fulltime')
customer_note = models.TextField("客户备注", blank=True, null=True, )
status = models.CharField("状态", choices=enroll_status_choices, max_length=64, default="unregistered",help_text="选择客户此时的状态") #help_text这种参数基本都是针对admin应用里面用的
date = models.DateTimeField("咨询日期", auto_now_add=True)
last_consult_date = models.DateField("最后跟进日期", auto_now_add=True) #考核销售的跟进情况,如果多天没有跟进,会影响销售的绩效等
next_date = models.DateField("预计再次跟进时间", blank=True, null=True) #销售自己大概记录一下自己下一次会什么时候跟进,也没啥用
#用户表中存放的是自己公司的所有员工。
consultant = models.ForeignKey('UserInfo', verbose_name="销售", blank=True, null=True)
#一个客户可以报多个班,报个脱产班,再报个周末班等,所以是多对多。
class_list = models.ManyToManyField('ClassList', verbose_name="已报班级", )
def __str__(self):
return self.name+":"+self.qq #主要__str__最好是个字符串昂,不然你会遇到很多的坑,还有我们返回的这两个字段填写数据的时候必须写上数据,必然相加会报错,null类型和str类型不能相加等错误信息。
def get_classlist(self): #当我们通过self.get_classlist的时候,就拿到了所有的班级信息,前端显示的时候用
l=[]
for cls in self.class_list.all():
l.append(str(cls))
# return mark_safe(",".join(l)) #纯文本,不用mark_safe也可以昂
return ",".join(l) #纯文本,不用mark_safe也可以昂
class Campuses(models.Model):
"""
校区表
"""
name = models.CharField(verbose_name='校区', max_length=64)
address = models.CharField(verbose_name='详细地址', max_length=512, blank=True, null=True)
def __str__(self):
return self.name
class ClassList(models.Model):
"""
班级表
"""
course = models.CharField("课程名称", max_length=64, choices=course_choices)
semester = models.IntegerField("学期") #python20期等
campuses = models.ForeignKey('Campuses', verbose_name="校区",on_delete=models.CASCADE)
price = models.IntegerField("学费", default=10000)
memo = models.CharField('说明', blank=True, null=True, max_length=100)
start_date = models.DateField("开班日期")
graduate_date = models.DateField("结业日期", blank=True, null=True) #不一定什么时候结业,哈哈,所以可为空
#contract = models.ForeignKey('ContractTemplate', verbose_name="选择合同模版", blank=True, null=True,on_delete=models.CASCADE)
teachers = models.ManyToManyField('UserInfo', verbose_name="老师") #对了,还有一点,如果你用的django2版本的,那么外键字段都需要自行写上on_delete=models.CASCADE
class_type = models.CharField(choices=class_type_choices, max_length=64, verbose_name='班额及类型', blank=True,null=True)
class Meta:
unique_together = ("course", "semester", 'campuses')
def __str__(self):
return "{}{}({})".format(self.get_course_display(), self.semester, self.campuses)
view.py
import os
from NBcrm import settings
from nbapp import form
from django.shortcuts import render,HttpResponse,redirect
from nbapp import models
from django.http import JsonResponse
from django.urls import reverse
from django.contrib import auth
from django.contrib.auth.decorators import login_required
# Create your views here.
#注册
def register(request):
if request.method == 'GET':
form_obj = form.UserForm()
return render(request,'register.html',{'form_obj':form_obj})
else:
form_obj = form.UserForm(request.POST)
if form_obj.is_valid():
data = form_obj.cleaned_data
data.pop('r_password')
models.UserInfo.objects.create_user(**data)
# auth.login(request,user_obj) 注册完之后可以自动进行登录
return redirect('login')
else:
return render(request, 'register.html', {'form_obj': form_obj})
#登录
def login(request):
'''
响应的状态码:
成功:1000
验证码失败:1001
用户名密码失败:1002
:param request:
:return:
'''
response_msg = {'code':None,'msg':None}
if request.method == 'GET':
return render(request, 'login.html')
else:
username = request.POST.get('username')
password = request.POST.get('password')
valid_bode = request.POST.get('valid_code')
#1 首先验证验证码是否正确
if valid_bode.upper() == request.session.get('valid_str').upper():
# 2 验证用户名和密码是不是存在
user_obj = auth.authenticate(username=username,password=password)
#用户名密码正确
if user_obj:
# 3 保存session
auth.login(request,user_obj)
response_msg['code'] = 1000
response_msg['msg'] = '登录成功!'
else:
response_msg['code'] = 1002
response_msg['msg'] = '用户名或者密码输入有误!'
#验证码失败报错
else:
response_msg['code'] = 1001
response_msg['msg'] = '验证码输入有误!'
return JsonResponse(response_msg)
#注销
def logout(request):
auth.logout(request)
return redirect('login')
def get_valid_img(request):
import random
def get_random_color():
return (random.randint(0,255),random.randint(0,255),random.randint(0,255))
from PIL import Image,ImageDraw,ImageFont
img_obj = Image.new('RGB', (200, 34), get_random_color())
draw_obj = ImageDraw.Draw(img_obj)
font_path = os.path.join(settings.BASE_DIR,'statics/font/NAUERT__.TTF')
font_obj = ImageFont.truetype(font_path,16)
sum_str = ''
for i in range(6):
a = random.choice([str(random.randint(0,9)), chr(random.randint(97,122)), chr(random.randint(65,90))]) #4 a 5 D 6 S
sum_str += a
print(sum_str)
draw_obj.text((64,10),sum_str,fill=get_random_color(),font=font_obj)
width=200
height=34
for i in range(5):
x1=random.randint(0,width)
x2=random.randint(0,width)
y1=random.randint(0,height)
y2=random.randint(0,height)
draw_obj.line((x1,y1,x2,y2),fill=get_random_color())
# # 添加噪点
for i in range(10):
#这是添加点,50个点
draw_obj.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color())
#下面是添加很小的弧线,看上去类似于一个点,50个小弧线
x = random.randint(0, width)
y = random.randint(0, height)
draw_obj.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color())
from io import BytesIO
f = BytesIO()
img_obj.save(f,'png')
data = f.getvalue()
#验证码对应的数据保存到session里面
request.session['valid_str'] = sum_str
return HttpResponse(data)
# 如果记录用户想去的路径
# @login_required
# def shopping(request):
# path = request.path
# # return redirect('/login/'+'?next='+path)
# # request.GET.get('next')
# # return HttpResponse('shopping')
#这是一个简答的路由跳转测试
# @login_required
# def shopping(request):
# return HttpResponse('shopping')
#首页
@login_required
def index(request):
# return render(request,'index.html')
return render(request,'index.html')
def customers(request):
all_customers = models.Customer.objects.all()
return render(request,'customers.html',{'all_customers':all_customers})
base.html
{% load static %}
<!DOCTYPE html>
<!--
This is a starter template page. Use this page to start your new project from
scratch. This page gets rid of all links and provides the needed markup only.
-->
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>AdminLTE 2 | Starter</title>
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<link rel="stylesheet" href="{% static 'adminlte/bower_components/bootstrap/dist/css/bootstrap.min.css' %}">
<!-- Font Awesome -->
<link rel="stylesheet" href="{% static 'adminlte/bower_components/font-awesome/css/font-awesome.min.css' %}">
<!-- Ionicons -->
<link rel="stylesheet" href="{% static 'adminlte/bower_components/Ionicons/css/ionicons.min.css' %}">
<!-- Theme style -->
<link rel="stylesheet" href="{% static 'adminlte/dist/css/AdminLTE.min.css' %}">
<!-- AdminLTE Skins. We have chosen the skin-blue for this starter
page. However, you can choose any other skin. Make sure you
apply the skin class to the body tag so the changes take effect. -->
<link rel="stylesheet" href="{% static 'adminlte/dist/css/skins/skin-blue.min.css' %}">
</head>
<!--
BODY TAG OPTIONS:
=================
Apply one or more of the following classes to get the
desired effect
|---------------------------------------------------------|
| SKINS | skin-blue |
| | skin-black |
| | skin-purple |
| | skin-yellow |
| | skin-red |
| | skin-green |
|---------------------------------------------------------|
|LAYOUT OPTIONS | fixed |
| | layout-boxed |
| | layout-top-nav |
| | sidebar-collapse |
| | sidebar-mini |
|---------------------------------------------------------|
-->
<body class="hold-transition skin-blue sidebar-mini">
<div class="wrapper">
<!-- Main Header -->
<header class="main-header">
<!-- Logo -->
<a href="index2.html" class="logo">
<!-- mini logo for sidebar mini 50x50 pixels -->
<span class="logo-mini"><b>A</b>LT</span>
<!-- logo for regular state and mobile devices -->
<span class="logo-lg"><b>NB</b>crm</span>
</a>
<!-- Header Navbar -->
<nav class="navbar navbar-static-top" role="navigation">
<!-- Sidebar toggle button-->
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
<span class="sr-only">Toggle navigation</span>
</a>
<!-- Navbar Right Menu -->
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<!-- Messages: style can be found in dropdown.less-->
<li class="dropdown messages-menu">
<!-- Menu toggle button -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-envelope-o"></i>
<span class="label label-success">4</span>
</a>
<ul class="dropdown-menu">
<li class="header">You have 4 messages</li>
<li>
<!-- inner menu: contains the messages -->
<ul class="menu">
<li><!-- start message -->
<a href="#">
<div class="pull-left">
<!-- User Image -->
<img src="{% static 'adminlte/dist/img/user2-160x160.jpg' %}"
class="img-circle" alt="User Image">
</div>
<!-- Message title and timestamp -->
<h4>
Support Team
<small><i class="fa fa-clock-o"></i> 5 mins</small>
</h4>
<!-- The message -->
<p>Why not buy a new awesome theme?</p>
</a>
</li>
<!-- end message -->
</ul>
<!-- /.menu -->
</li>
<li class="footer"><a href="#">See All Messages</a></li>
</ul>
</li>
<!-- /.messages-menu -->
<!-- Notifications Menu -->
<li class="dropdown notifications-menu">
<!-- Menu toggle button -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-bell-o"></i>
<span class="label label-warning">10</span>
</a>
<ul class="dropdown-menu">
<li class="header">You have 10 notifications</li>
<li>
<!-- Inner Menu: contains the notifications -->
<ul class="menu">
<li><!-- start notification -->
<a href="#">
<i class="fa fa-users text-aqua"></i> 5 new members joined today
</a>
</li>
<!-- end notification -->
</ul>
</li>
<li class="footer"><a href="#">View all</a></li>
</ul>
</li>
<!-- Tasks Menu -->
<li class="dropdown tasks-menu">
<!-- Menu Toggle Button -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-flag-o"></i>
<span class="label label-danger">9</span>
</a>
<ul class="dropdown-menu">
<li class="header">You have 9 tasks</li>
<li>
<!-- Inner menu: contains the tasks -->
<ul class="menu">
<li><!-- Task item -->
<a href="#">
<!-- Task title and progress text -->
<h3>
Design some buttons
<small class="pull-right">20%</small>
</h3>
<!-- The progress bar -->
<div class="progress xs">
<!-- Change the css width attribute to simulate progress -->
<div class="progress-bar progress-bar-aqua" style="width: 20%"
role="progressbar"
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100">
<span class="sr-only">20% Complete</span>
</div>
</div>
</a>
</li>
<!-- end task item -->
</ul>
</li>
<li class="footer">
<a href="#">View all tasks</a>
</li>
</ul>
</li>
<!-- User Account Menu -->
<li class="dropdown user user-menu">
<!-- Menu Toggle Button -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<!-- The user image in the navbar-->
<img src="{% static 'adminlte/dist/img/user2-160x160.jpg' %}" class="user-image"
alt="User Image">
<!-- hidden-xs hides the username on small devices so only the image appears. -->
<span class="hidden-xs">{{ request.user.username }}</span>
</a>
<ul class="dropdown-menu">
<!-- The user image in the menu -->
<li class="user-header">
<img src="{% static 'adminlte/dist/img/user2-160x160.jpg' %}" class="img-circle"
alt="User Image">
<p>
Alexander Pierce - Web Developer
<small>Member since Nov. 2012</small>
</p>
</li>
<!-- Menu Body -->
<li class="user-body">
<div class="row">
<div class="col-xs-4 text-center">
<a href="#">Followers</a>
</div>
<div class="col-xs-4 text-center">
<a href="#">Sales</a>
</div>
<div class="col-xs-4 text-center">
<a href="#">Friends</a>
</div>
</div>
<!-- /.row -->
</li>
<!-- Menu Footer-->
<li class="user-footer">
<div class="pull-left">
<a href="#" class="btn btn-default btn-flat">Profile</a>
</div>
<div class="pull-right">
<a href="{% url 'logout' %}" class="btn btn-default btn-flat">注销</a>
</div>
</li>
</ul>
</li>
<!-- Control Sidebar Toggle Button -->
<li>
<a href="#" data-toggle="control-sidebar"><i class="fa fa-gears"></i></a>
</li>
</ul>
</div>
</nav>
</header>
<!-- Left side column. contains the logo and sidebar -->
<aside class="main-sidebar">
<!-- sidebar: style can be found in sidebar.less -->
<section class="sidebar">
<!-- Sidebar user panel (optional) -->
<div class="user-panel">
<div class="pull-left image">
<img src="{% static 'adminlte/dist/img/user2-160x160.jpg' %}" class="img-circle" alt="User Image">
</div>
<div class="pull-left info">
<p>Alexander Pierce</p>
<!-- Status -->
<a href="#"><i class="fa fa-circle text-success"></i> Online</a>
</div>
</div>
<!-- search form (Optional) -->
<form action="#" method="get" class="sidebar-form">
<div class="input-group">
<input type="text" name="q" class="form-control" placeholder="Search...">
<span class="input-group-btn">
<button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i>
</button>
</span>
</div>
</form>
<!-- /.search form -->
<!-- Sidebar Menu -->
<ul class="sidebar-menu" data-widget="tree">
<li class="header">功能模块</li>
<!-- Optionally, you can add icons to the links -->
<li class="active"><a href="{% url 'customers' %}"><i class="fa fa-link"></i> <span>客户信息</span></a></li>
<li><a href="#"><i class="fa fa-link"></i> <span>Another Link</span></a></li>
<li class="treeview">
<a href="#"><i class="fa fa-link"></i> <span>Multilevel</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li><a href="#">Link in level 2</a></li>
<li><a href="#">Link in level 2</a></li>
</ul>
</li>
</ul>
<!-- /.sidebar-menu -->
</section>
<!-- /.sidebar -->
</aside>
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
base模板页面
<small>Optional description</small>
</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> Level</a></li>
<li class="active">Here</li>
</ol>
</section>
<!-- Main content -->
<section class="content container-fluid">
{% block content %}
{% endblock %}
</section>
<!-- /.content -->
</div>
<!-- /.content-wrapper -->
<!-- Main Footer -->
<footer class="main-footer">
<!-- To the right -->
<div class="pull-right hidden-xs">
Anything you want
</div>
<!-- Default to the left -->
<strong>Copyright © 2016 <a href="#">Company</a>.</strong> All rights reserved.
</footer>
<!-- Control Sidebar -->
<aside class="control-sidebar control-sidebar-dark">
<!-- Create the tabs -->
<ul class="nav nav-tabs nav-justified control-sidebar-tabs">
<li class="active"><a href="#control-sidebar-home-tab" data-toggle="tab"><i class="fa fa-home"></i></a></li>
<li><a href="#control-sidebar-settings-tab" data-toggle="tab"><i class="fa fa-gears"></i></a></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<!-- Home tab content -->
<div class="tab-pane active" id="control-sidebar-home-tab">
<h3 class="control-sidebar-heading">Recent Activity</h3>
<ul class="control-sidebar-menu">
<li>
<a href="javascript:;">
<i class="menu-icon fa fa-birthday-cake bg-red"></i>
<div class="menu-info">
<h4 class="control-sidebar-subheading">Langdon's Birthday</h4>
<p>Will be 23 on April 24th</p>
</div>
</a>
</li>
</ul>
<!-- /.control-sidebar-menu -->
<h3 class="control-sidebar-heading">Tasks Progress</h3>
<ul class="control-sidebar-menu">
<li>
<a href="javascript:;">
<h4 class="control-sidebar-subheading">
Custom Template Design
<span class="pull-right-container">
<span class="label label-danger pull-right">70%</span>
</span>
</h4>
<div class="progress progress-xxs">
<div class="progress-bar progress-bar-danger" style="width: 70%"></div>
</div>
</a>
</li>
</ul>
<!-- /.control-sidebar-menu -->
</div>
<!-- /.tab-pane -->
<!-- Stats tab content -->
<div class="tab-pane" id="control-sidebar-stats-tab">Stats Tab Content</div>
<!-- /.tab-pane -->
<!-- Settings tab content -->
<div class="tab-pane" id="control-sidebar-settings-tab">
<form method="post">
<h3 class="control-sidebar-heading">General Settings</h3>
<div class="form-group">
<label class="control-sidebar-subheading">
Report panel usage
<input type="checkbox" class="pull-right" checked>
</label>
<p>
Some information about this general settings option
</p>
</div>
<!-- /.form-group -->
</form>
</div>
<!-- /.tab-pane -->
</div>
</aside>
<!-- /.control-sidebar -->
<!-- Add the sidebar's background. This div must be placed
immediately after the control sidebar -->
<div class="control-sidebar-bg"></div>
</div>
<!-- ./wrapper -->
<!-- REQUIRED JS SCRIPTS -->
<!-- jQuery 3 -->
<script src="{% static 'adminlte/bower_components/jquery/dist/jquery.min.js' %}"></script>
<!-- Bootstrap 3.3.7 -->
<script src="{% static 'adminlte/bower_components/bootstrap/dist/js/bootstrap.min.js' %}"></script>
<!-- AdminLTE App -->
<script src="{% static 'adminlte/dist/js/adminlte.min.js' %}"></script>
<!-- Optionally, you can add Slimscroll and FastClick plugins.
Both of these plugins are recommended to enhance the
user experience. -->
</body>
</html>
start.html
{% load static %}
<!DOCTYPE html>
<!--
This is a starter template page. Use this page to start your new project from
scratch. This page gets rid of all links and provides the needed markup only.
-->
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>AdminLTE 2 | Starter</title>
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<link rel="stylesheet" href="{% static 'adminlte/bower_components/bootstrap/dist/css/bootstrap.min.css' %}">
<!-- Font Awesome -->
<link rel="stylesheet" href="{% static 'adminlte/bower_components/font-awesome/css/font-awesome.min.css' %}">
<!-- Ionicons -->
<link rel="stylesheet" href="{% static 'adminlte/bower_components/Ionicons/css/ionicons.min.css' %}">
<!-- Theme style -->
<link rel="stylesheet" href="{% static 'adminlte/dist/css/AdminLTE.min.css' %}">
<!-- AdminLTE Skins. We have chosen the skin-blue for this starter
page. However, you can choose any other skin. Make sure you
apply the skin class to the body tag so the changes take effect. -->
<link rel="stylesheet" href="{% static 'adminlte/dist/css/skins/skin-blue.min.css' %}">
</head>
<!--
BODY TAG OPTIONS:
=================
Apply one or more of the following classes to get the
desired effect
|---------------------------------------------------------|
| SKINS | skin-blue |
| | skin-black |
| | skin-purple |
| | skin-yellow |
| | skin-red |
| | skin-green |
|---------------------------------------------------------|
|LAYOUT OPTIONS | fixed |
| | layout-boxed |
| | layout-top-nav |
| | sidebar-collapse |
| | sidebar-mini |
|---------------------------------------------------------|
-->
<body class="hold-transition skin-blue sidebar-mini">
<div class="wrapper">
<!-- Main Header -->
<header class="main-header">
<!-- Logo -->
<a href="index2.html" class="logo">
<!-- mini logo for sidebar mini 50x50 pixels -->
<span class="logo-mini"><b>A</b>LT</span>
<!-- logo for regular state and mobile devices -->
<span class="logo-lg"><b>NB</b>crm</span>
</a>
<!-- Header Navbar -->
<nav class="navbar navbar-static-top" role="navigation">
<!-- Sidebar toggle button-->
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
<span class="sr-only">Toggle navigation</span>
</a>
<!-- Navbar Right Menu -->
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<!-- Messages: style can be found in dropdown.less-->
<li class="dropdown messages-menu">
<!-- Menu toggle button -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-envelope-o"></i>
<span class="label label-success">4</span>
</a>
<ul class="dropdown-menu">
<li class="header">You have 4 messages</li>
<li>
<!-- inner menu: contains the messages -->
<ul class="menu">
<li><!-- start message -->
<a href="#">
<div class="pull-left">
<!-- User Image -->
<img src="{% static 'adminlte/dist/img/user2-160x160.jpg' %}" class="img-circle" alt="User Image">
</div>
<!-- Message title and timestamp -->
<h4>
Support Team
<small><i class="fa fa-clock-o"></i> 5 mins</small>
</h4>
<!-- The message -->
<p>Why not buy a new awesome theme?</p>
</a>
</li>
<!-- end message -->
</ul>
<!-- /.menu -->
</li>
<li class="footer"><a href="#">See All Messages</a></li>
</ul>
</li>
<!-- /.messages-menu -->
<!-- Notifications Menu -->
<li class="dropdown notifications-menu">
<!-- Menu toggle button -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-bell-o"></i>
<span class="label label-warning">10</span>
</a>
<ul class="dropdown-menu">
<li class="header">You have 10 notifications</li>
<li>
<!-- Inner Menu: contains the notifications -->
<ul class="menu">
<li><!-- start notification -->
<a href="#">
<i class="fa fa-users text-aqua"></i> 5 new members joined today
</a>
</li>
<!-- end notification -->
</ul>
</li>
<li class="footer"><a href="#">View all</a></li>
</ul>
</li>
<!-- Tasks Menu -->
<li class="dropdown tasks-menu">
<!-- Menu Toggle Button -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-flag-o"></i>
<span class="label label-danger">9</span>
</a>
<ul class="dropdown-menu">
<li class="header">You have 9 tasks</li>
<li>
<!-- Inner menu: contains the tasks -->
<ul class="menu">
<li><!-- Task item -->
<a href="#">
<!-- Task title and progress text -->
<h3>
Design some buttons
<small class="pull-right">20%</small>
</h3>
<!-- The progress bar -->
<div class="progress xs">
<!-- Change the css width attribute to simulate progress -->
<div class="progress-bar progress-bar-aqua" style="width: 20%" role="progressbar"
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100">
<span class="sr-only">20% Complete</span>
</div>
</div>
</a>
</li>
<!-- end task item -->
</ul>
</li>
<li class="footer">
<a href="#">View all tasks</a>
</li>
</ul>
</li>
<!-- User Account Menu -->
<li class="dropdown user user-menu">
<!-- Menu Toggle Button -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<!-- The user image in the navbar-->
<img src="{% static 'adminlte/dist/img/user2-160x160.jpg' %}" class="user-image" alt="User Image">
<!-- hidden-xs hides the username on small devices so only the image appears. -->
<span class="hidden-xs">{{ request.user.username }}</span>
</a>
<ul class="dropdown-menu">
<!-- The user image in the menu -->
<li class="user-header">
<img src="{% static 'adminlte/dist/img/user2-160x160.jpg' %}" class="img-circle" alt="User Image">
<p>
Alexander Pierce - Web Developer
<small>Member since Nov. 2012</small>
</p>
</li>
<!-- Menu Body -->
<li class="user-body">
<div class="row">
<div class="col-xs-4 text-center">
<a href="#">Followers</a>
</div>
<div class="col-xs-4 text-center">
<a href="#">Sales</a>
</div>
<div class="col-xs-4 text-center">
<a href="#">Friends</a>
</div>
</div>
<!-- /.row -->
</li>
<!-- Menu Footer-->
<li class="user-footer">
<div class="pull-left">
<a href="#" class="btn btn-default btn-flat">Profile</a>
</div>
<div class="pull-right">
<a href="{% url 'logout' %}" class="btn btn-default btn-flat">注销</a>
</div>
</li>
</ul>
</li>
<!-- Control Sidebar Toggle Button -->
<li>
<a href="#" data-toggle="control-sidebar"><i class="fa fa-gears"></i></a>
</li>
</ul>
</div>
</nav>
</header>
<!-- Left side column. contains the logo and sidebar -->
<aside class="main-sidebar">
<!-- sidebar: style can be found in sidebar.less -->
<section class="sidebar">
<!-- Sidebar user panel (optional) -->
<div class="user-panel">
<div class="pull-left image">
<img src="{% static 'adminlte/dist/img/user2-160x160.jpg' %}" class="img-circle" alt="User Image">
</div>
<div class="pull-left info">
<p>Alexander Pierce</p>
<!-- Status -->
<a href="#"><i class="fa fa-circle text-success"></i> Online</a>
</div>
</div>
<!-- search form (Optional) -->
<form action="#" method="get" class="sidebar-form">
<div class="input-group">
<input type="text" name="q" class="form-control" placeholder="Search...">
<span class="input-group-btn">
<button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i>
</button>
</span>
</div>
</form>
<!-- /.search form -->
<!-- Sidebar Menu -->
<ul class="sidebar-menu" data-widget="tree">
<li class="header">HEADER</li>
<!-- Optionally, you can add icons to the links -->
<li class="active"><a href="#"><i class="fa fa-link"></i> <span>Link</span></a></li>
<li><a href="#"><i class="fa fa-link"></i> <span>Another Link</span></a></li>
<li class="treeview">
<a href="#"><i class="fa fa-link"></i> <span>Multilevel</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li><a href="#">Link in level 2</a></li>
<li><a href="#">Link in level 2</a></li>
</ul>
</li>
</ul>
<!-- /.sidebar-menu -->
</section>
<!-- /.sidebar -->
</aside>
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
Page Header
<small>Optional description</small>
</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> Level</a></li>
<li class="active">Here</li>
</ol>
</section>
<!-- Main content -->
<section class="content container-fluid">
<!--------------------------
| Your Page Content Here |
-------------------------->
</section>
<!-- /.content -->
</div>
<!-- /.content-wrapper -->
<!-- Main Footer -->
<footer class="main-footer">
<!-- To the right -->
<div class="pull-right hidden-xs">
Anything you want
</div>
<!-- Default to the left -->
<strong>Copyright © 2016 <a href="#">Company</a>.</strong> All rights reserved.
</footer>
<!-- Control Sidebar -->
<aside class="control-sidebar control-sidebar-dark">
<!-- Create the tabs -->
<ul class="nav nav-tabs nav-justified control-sidebar-tabs">
<li class="active"><a href="#control-sidebar-home-tab" data-toggle="tab"><i class="fa fa-home"></i></a></li>
<li><a href="#control-sidebar-settings-tab" data-toggle="tab"><i class="fa fa-gears"></i></a></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<!-- Home tab content -->
<div class="tab-pane active" id="control-sidebar-home-tab">
<h3 class="control-sidebar-heading">Recent Activity</h3>
<ul class="control-sidebar-menu">
<li>
<a href="javascript:;">
<i class="menu-icon fa fa-birthday-cake bg-red"></i>
<div class="menu-info">
<h4 class="control-sidebar-subheading">Langdon's Birthday</h4>
<p>Will be 23 on April 24th</p>
</div>
</a>
</li>
</ul>
<!-- /.control-sidebar-menu -->
<h3 class="control-sidebar-heading">Tasks Progress</h3>
<ul class="control-sidebar-menu">
<li>
<a href="javascript:;">
<h4 class="control-sidebar-subheading">
Custom Template Design
<span class="pull-right-container">
<span class="label label-danger pull-right">70%</span>
</span>
</h4>
<div class="progress progress-xxs">
<div class="progress-bar progress-bar-danger" style="width: 70%"></div>
</div>
</a>
</li>
</ul>
<!-- /.control-sidebar-menu -->
</div>
<!-- /.tab-pane -->
<!-- Stats tab content -->
<div class="tab-pane" id="control-sidebar-stats-tab">Stats Tab Content</div>
<!-- /.tab-pane -->
<!-- Settings tab content -->
<div class="tab-pane" id="control-sidebar-settings-tab">
<form method="post">
<h3 class="control-sidebar-heading">General Settings</h3>
<div class="form-group">
<label class="control-sidebar-subheading">
Report panel usage
<input type="checkbox" class="pull-right" checked>
</label>
<p>
Some information about this general settings option
</p>
</div>
<!-- /.form-group -->
</form>
</div>
<!-- /.tab-pane -->
</div>
</aside>
<!-- /.control-sidebar -->
<!-- Add the sidebar's background. This div must be placed
immediately after the control sidebar -->
<div class="control-sidebar-bg"></div>
</div>
<!-- ./wrapper -->
<!-- REQUIRED JS SCRIPTS -->
<!-- jQuery 3 -->
<script src="{% static 'adminlte/bower_components/jquery/dist/jquery.min.js' %}"></script>
<!-- Bootstrap 3.3.7 -->
<script src="{% static 'adminlte/bower_components/bootstrap/dist/js/bootstrap.min.js' %}"></script>
<!-- AdminLTE App -->
<script src="{% static 'adminlte/dist/js/adminlte.min.js' %}"></script>
<!-- Optionally, you can add Slimscroll and FastClick plugins.
Both of these plugins are recommended to enhance the
user experience. -->
</body>
</html>
customer.html
{% extends 'base.html' %}
{% block content %}
<section class="content">
<div class="row">
<div class="col-xs-12">
<div class="box">
<div class="box-header">
<h3 class="box-title">客户信息展示</h3>
</div>
<!-- /.box-header -->
<div class="box-body">
<table id="example2" class="table table-bordered table-hover">
<thead>
<tr>
<th>序号</th>
<th>qq</th>
<th>姓名</th>
<th>性别</th>
<th>客户来源</th>
<th>转介绍自学员</th>
<th>咨询课程</th>
<th>选择客户此时的状态</th>
<th>销售</th>
{# <th>已报班级</th>#}
</tr>
</thead>
<tbody>
{% for customer in all_customers %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ customer.qq }}</td>
<td>{{ customer.name }}</td>
<td>{{ customer.get_sex_display }}</td>
<td>{{ customer.get_source_display }}</td>
<td>{{ customer.introduce_from.name }}</td>
<td>{{ customer.course }}</td>
<td>{{ customer.get_status_display }}</td>
<td>{{ customer.consultant.username }}</td>
{# <td>{{ customer.get_classlist }}</td>#}
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- /.box-body -->
</div>
<!-- /.box -->
</div>
<!-- /.col -->
</div>
<!-- /.row -->
</section>
{% endblock %}
urls.py
"""NBcrm URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from nbapp import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
#首页
url(r'^index/', views.index,name='index'),
#注册
url(r'^register/', views.register, name='register'),
#登录
url(r'^login/', views.login, name='login'),
#验证码
url(r'^get_valid_img/', views.get_valid_img, name='get_valid_img'),
#注销
url(r'^logout/', views.logout, name='logout'),
# url(r'^shopping/', views.shopping, name='shopping'),
#展示所有客户信息
url(r'^customers/list/', views.customers, name='customers'),
]
import re
from nbapp import models
from django import forms
from django.forms import widgets
from django.core.exceptions import ValidationError
class UserForm(forms.Form):
username = forms.CharField(max_length=32, min_length=6, label='用户名',
error_messages={'required': '这个字段必须填写!', 'max_length': '最大不能超过32位','min_length': '最小不能低于6位'}, )
password = forms.CharField(max_length=32, min_length=6, label='密码',
error_messages={'required': '这个字段必须填写!', 'max_length': '最大不能超过32位','min_length': '最小不能低于6位'},
widget=widgets.PasswordInput
)
r_password = forms.CharField(max_length=32, min_length=6, label='重复密码',
error_messages={'required': '这个字段必须填写!', 'max_length': '最大不能超过32位','min_length': '最小不能低于6位'},
widget=widgets.PasswordInput)
email = forms.EmailField(max_length=32, label='邮箱',error_messages={'required': '这个字段必须填写!', 'max_length': '最大不能超过32位', 'invalid': '邮箱格式不对'}, )
def clean_username(self):
val = self.cleaned_data.get('username')
user_obj = models.UserInfo.objects.filter(username=val).first()
if user_obj:
raise ValidationError('该用户名已经存在,请换个名字!')
else:
return val
def clean_password(self):
val = self.cleaned_data.get('password')
if val.isdecimal():
raise ValidationError('密码不能为纯数字')
else:
return val
def clean_email(self):
val = self.cleaned_data.get('email')
if re.search('\w+@163.com$', val):
return val
else:
raise ValidationError('必须是163网易邮箱!')
def clean(self):
password = self.cleaned_data.get('password')
r_password = self.cleaned_data.get('r_password')
if password != r_password:
self.add_error('r_password', '两次密码不一致') # 这是给r_password的错误添加这个错误信息
# raise ValidationError('两次密码不一致!') #被总的错误拿到了
else:
return self.cleaned_data
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].widget.attrs.update({
'class': 'form-control'
})
admin.py
from django.contrib import admin
# Register your models here.
from nbapp import models
admin.site.register(models.UserInfo)
admin.site.register(models.Customer)
admin.site.register(models.Campuses)
admin.site.register(models.ClassList)
register.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}" rel="stylesheet">
</head>
<body>
<h1>这是注册页面</h1>
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form action="{% url 'register' %}" method="post" novalidate>
{% csrf_token %}
{% for field in form_obj %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
<span class="text-danger">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<input type="submit" class="btn btn-success pull-right" value="注册">
</form>
</div>
</div>
</div>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
<script>
</script>
</body>
</html>
login.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}" rel="stylesheet">
</head>
<body>
<h1>NBCRM登录页面</h1>
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form>
{% csrf_token %}
<div class="form-group">
<label for="username">用户名</label>
<input type="text" class="form-control" name="username" id="username">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" name="password" id="password">
</div>
<div class="row">
<div class="col-md-6 col-xs-6">
<div class="form-group">
<label for="valid_code">验证码</label>
<input type="text" class="form-control" name="valid_code" id="valid_code">
</div>
</div>
<div class="col-md-6 col-xs-6">
<img id="valid_code_img" src="{% url 'get_valid_img' %}" alt="" style="margin-top: 24px;">
</div>
</div>
<span id="error" class="text-danger"></span>
<input id="login" type="button" value="登录" class="btn btn-primary pull-right">
</form>
</div>
</div>
</div>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
<script>
$('#login').on('click',function () {
var username = $('[name=username]').val();
var password = $('[name=password]').val();
var valid_code = $('[name=valid_code]').val();
var csrf_token = $('[name=csrfmiddlewaretoken]').val();
$.ajax({
url:{% url "login" %},
type:'post',
data:{
username:username,
password:password,
valid_code:valid_code,
csrfmiddlewaretoken:csrf_token,
},
success:function (res) {
//{'code':1000,'msg':'xxx'}
if (res.code === 1000){
{#location.href = {% url 'index' %};#}
var href = location.search.slice(6);
if (href){
location.href = href;
}else {
location.href = {% url 'index' %};
}
}
else {
$('#error').text(res.msg);
}
}
})
});
//点击图片刷新验证码
$('#valid_code_img').click(function () {
$(this)[0].src += '?';
})
</script>
</body>
</html>
index.html
{% extends 'base.html' %}