会议室预定
CRM之会议室预订系统代码
views
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from django.shortcuts import render,redirect,HttpResponse 2 from book import models 3 from django.contrib import auth 4 from django.http import JsonResponse 5 import datetime,json 6 from django.db.models import Q 7 # Create your views here. 8 9 def index(request): 10 today = datetime.datetime.now().date() 11 date = request.GET.get("date",today) 12 13 14 res = {"status": 200, } 15 if request.method=="POST": 16 17 ############添加选中的数据################## 18 19 post_data = request.POST.get("post_data") 20 data_info = json.loads(post_data) 21 add_data = data_info["ADD"] 22 del_data =data_info["DEL"] 23 choose_date = request.POST.get("choose_date") 24 25 book_list = [] 26 for rid,add_tid_list in add_data.items(): 27 for tid in add_tid_list: 28 book=models.Book(user=request.user,date=choose_date or date,room_id=rid,time_id=tid) 29 book_list.append(book) 30 if book_list: 31 models.Book.objects.bulk_create(book_list) #############采用批量添加提高运行效率,逼格稍微好一点 32 33 34 ###################删除要取消的数据################ 35 # {'DEL': {'1': ['5', '6', '7']}, 'ADD': {}} 36 remove_booking = Q() 37 for rid,del_tid_list in del_data.items(): 38 for tid in del_tid_list: 39 temp=Q() 40 temp.connector="AND" 41 temp.children.append(("user_id",request.user.pk,)) 42 temp.children.append(("room_id", rid)) 43 temp.children.append(("time_id", tid)) 44 temp.children.append(("date", choose_date or date)) 45 remove_booking.add(temp,"OR") 46 if remove_booking: 47 models.Book.objects.filter(remove_booking).delete() 48 ''' 49 同样是为了增加运行效率,减少与数据的的撞库, 50 先用Q语句将关系构建好,房间与时间,用户id,日期保持且的关系,每个td之间保持或的关系 51 ''' 52 53 54 return JsonResponse(res) 55 56 57 time_list = models.time_choices 58 room_list = models.Room.objects.all() 59 book_list = list(models.Book.objects.filter(date=date).values("time_id","user__username","room_id")) 60 61 return render(request,"index.html",locals()) 62 63 64 65 66 def login(request): 67 if request.method =="POST": 68 username=request.POST.get("user") 69 pwd=request.POST.get("pwd") 70 user = auth.authenticate(username=username,password=pwd) ##验证用户名和密码 71 72 if user: 73 auth.login(request,user) ##注入session信息 74 return redirect("/index/") 75 else: 76 return render(request,"login.html",locals())
models
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from django.db import models 2 from django.contrib.auth.models import AbstractUser 3 # Create your models here. 4 5 time_choices = ( 6 (1, '8:00'), 7 (2, '9:00'), 8 (3, '10:00'), 9 (4, '11:00'), 10 (5, '12:00'), 11 (6, '13:00'), 12 (7, '14:00'), 13 (8, '15:00'), 14 (9, '16:00'), 15 (10, '17:00'), 16 (11, '18:00'), 17 (12, '19:00'), 18 (13, '20:00'), 19 ) 20 21 22 class UserInfo(AbstractUser): 23 pass 24 ''' 25 注意若继承django自带的auth.User表格,需要到settings中更改配置参数为: 26 AUTH_USER_MODEL="book.UserInfo" 27 ''' 28 29 30 class Room(models.Model): 31 caption = models.CharField(max_length=32) 32 num = models.IntegerField() 33 def __str__(self): #__str__ 的作用,在调用显示该类时,返回一个友好的,用户可读的字符串作为对象的str(自己命名) 34 return self.caption 35 36 class Book(models.Model): 37 ''' 38 预定记录表 39 ''' 40 room = models.ForeignKey(to=Room,on_delete=models.CASCADE) 41 user = models.ForeignKey(to=UserInfo,on_delete=models.CASCADE) 42 date = models.DateField() 43 time_id = models.IntegerField(choices=time_choices) 44 class meta(): 45 unique_together = ( 46 ('room', 'date', 'time_id'), 47 ) 48 ''' 49 unique_together会将以下三个字段关联,防止下面三个字段同时出现重复 50 51 ''' 52 53 def __str__(self): 54 return str(self.user)+"已预定"+str(self.room)
login.html
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="post"> {% csrf_token %} <input type="text" name="user"> <input type="password" name="pwd"> <input type="submit" value="提交"> </form> </body> </html>
index.html
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> 7 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> 8 <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script> 9 <script src="/static/datetimepicker/bootstrap-datetimepicker.min.js"></script> 10 <script src="/static/datetimepicker/bootstrap-datetimepicker.zh-CN.js"></script> 11 12 13 <style> 14 .active{ 15 background-color: darkseagreen!important; 16 color: white; 17 text-align: center; 18 } 19 .other_active{ 20 background-color: burlywood; 21 color: white; 22 text-align: center; 23 } 24 .td_active{ 25 background-color: deepskyblue; 26 } 27 </style> 28 </head> 29 30 <body> 31 <h3>会议室预定</h3> 32 33 {#日历插件#} 34 <div class="clearfix"> 35 <div class="calender pull-right"> 36 <div class='input-group' style="width: 230px;"> 37 <input type='text' class="form-control" id='datetimepicker11' placeholder="请选择日期"/> 38 <span class="input-group-addon"> 39 <span class="glyphicon glyphicon-calendar"> 40 </span> 41 </span> 42 43 </div> 44 </div> 45 </div> 46 47 48 <div class="row"> 49 <div class="col-md-9 col-md-offset-2"> 50 <table class="table table-hover table-bordered"> 51 <thead> 52 <tr> 53 <th>会议室/时间</th> 54 {% for time in time_list %} 55 <th>{{ time.1 }}</th> 56 {% endfor %} 57 </tr> 58 </thead> 59 <tbody> 60 61 {% for room in room_list %} 62 <tr> 63 <td> 64 {{ room.caption }}({{ room.num }}) 65 </td> 66 {% for time in time_list %} 67 <td class="item" rid="{{ room.pk }}" tid="{{ time.0 }}"></td> 68 {% endfor %} 69 70 </tr> 71 {% endfor %} 72 73 </tbody> 74 </table> 75 <button class="btn btn-primary pull-right keep">保存</button> 76 </div> 77 </div> 78 79 80 <script> 81 book_list= {{ book_list|safe }} 82 83 84 //显示已经预定的消息 85 $.each(book_list,function (i,book_info) { 86 let rid = book_info["room_id"]; 87 let tid = book_info["time_id"]; 88 let name = book_info["user__username"]; 89 90 var c=`[rid=${rid}][tid=${tid}]` ; //取得同时具备rid和tid与循环所得的td 91 if ("{{ request.user.username }}"===name){ 92 $(c).addClass("active").html(name).removeClass("item");//添加active标签并且注意要移去item属性 93 } 94 else{ 95 $(c).addClass("other_active").html(name).removeClass("item"); 96 } 97 }) 98 // 显示选中的td标签 99 //采用时间委派,是为了防止取消预订是点击生成新的item无法出发事件 100 $("body").on("click",".item",function () { 101 $(this).toggleClass("td_active") //toggleClass 用法 当存在td_active属性时去掉,不存在该属性时添加 102 103 }); 104 105 // 不能预定其他人已经预定房间 106 $(".other_active").click(function () { 107 alert("该房间已被预订") 108 }) 109 110 // 取消预定 111 $(".active").click(function (e) { 112 $(this).removeClass("active").addClass("cancel item").html(""); 113 $(this).unbind("click"); //防止事件绑定溢出,取消绑定暂时 114 e.stopPropagation(); 115 }) 116 117 118 //提交选中标签 119 var POST_DATA = { 120 DEL: { 121 // 2:[2,3,4] 122 }, 123 ADD: { 124 // 1:[1,2,3,4,5] 125 }, 126 }; 127 128 $(".keep").click(function () { 129 130 //处理添加的数据 131 $(".td_active").each(function () { 132 ///此处是为了防止客户,本来点击取消,而后又撤销而导致重复添加数据,导致报错 133 if($(this).hasClass("cancel")){ 134 return 135 } 136 137 let tid = $(this).attr("tid") 138 let rid = $(this).attr("rid") 139 140 if (POST_DATA.ADD[rid]) { ///js取字典的形式需要去了解下,不熟悉 141 POST_DATA.ADD[rid].push(tid) 142 } 143 else { 144 POST_DATA.ADD[rid] = [tid] 145 } 146 }) 147 148 //处理提交取消的数据 149 $(".cancel").each(function () { 150 ///此处是为了防止客户,本来点击取消,而后又撤销而导致提交时把不想删掉的删除掉 151 if($(this).hasClass("td_active")){ 152 return 153 } 154 155 let tid = $(this).attr("tid") 156 let rid = $(this).attr("rid") 157 158 if(POST_DATA.DEL[rid]){ ///js取字典的形式需要去了解下,不熟悉 159 POST_DATA.DEL[rid].push(tid) 160 } 161 else{ 162 POST_DATA.DEL[rid]=[tid] 163 } 164 }) 165 166 //ajax将数据打包付出 167 $.ajax({ 168 url:"/index/", 169 type:"post", 170 data:{post_data:JSON.stringify(POST_DATA), 171 choose_date: location.search.slice(6), 172 }, 173 success:function (res) { 174 if (res["status"]){ 175 location.href="/index/" 176 } 177 } 178 }) 179 180 181 }) 182 183 ///添加事件插件 184 $('#datetimepicker11').datetimepicker({ 185 minView: "month", 186 language: "zh-CN", 187 sideBySide: true, 188 format: 'yyyy-mm-dd', 189 startDate: new Date(), 190 bootcssVer: 3, 191 autoclose: true, 192 }).on('changeDate', book_query); 193 function book_query(ev) { 194 console.log(ev.date); 195 CHOSEN_DATE = ev.date.Format('yyyy-MM-dd'); 196 location.href = "?date=" + CHOSEN_DATE 197 198 } 199 200 // 1 构建日期类型 201 // Date.prototype.Format 用于自己构建类方法 202 Date.prototype.Format = function (fmt) { //author: meizz 203 var o = { 204 "M+": this.getMonth() + 1, //月份 205 "d+": this.getDate(), //日 206 "h+": this.getHours(), //小时 207 "m+": this.getMinutes(), //分 208 "s+": this.getSeconds(), //秒 209 "q+": Math.floor((this.getMonth() + 3) / 3), //季度 210 "S": this.getMilliseconds() //毫秒 211 }; 212 if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); 213 for (var k in o) 214 if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 215 return fmt; 216 }; 217 218 219 220 </script> 221 222 </body> 223 </html>