Tornado笔记——用Tornado搭建假单统计考勤系统(十)
在上一篇博客中,我們完成了請(qǐng)假系統(tǒng)的數(shù)據(jù)庫(kù)部分設(shè)計(jì),現(xiàn)在讓我們來實(shí)現(xiàn)后端和前端的功能。
十三 填寫假單
我們打開base_nav.html,在其中添加新的展開欄,用于放置請(qǐng)假相關(guān)功能:
<!--base_nav.html--> <!--之前代碼略,總之就是左側(cè)導(dǎo)航欄繼續(xù)往下加就是--><li><a href="#" data-toggle="collapse" data-target="#vacationmanage"><i class="fa fa-calendar m-r-10" aria-hidden="true"></i>假期管理</a><ul id="vacationmanage" class="collapse"><li><a href="/createvacationapply" class="waves-effect"><i class="fa fa-child m-r-10" aria-hidden="true"></i>填寫假單</a></li><li><a href="/viewvacationapply" class="waves-effect"><i class="fa fa-eye m-r-10" aria-hidden="true"></i>查看假單</a></li><li><a href="/approvevacationapply" class="waves-effect"><i class="fa fa-check m-r-10" aria-hidden="true"></i>審批假單</a></li></ul></li> <!--之后代碼略-->我們?cè)谶@里實(shí)現(xiàn)三個(gè)功能:填寫假單、查看假單和審批假單。填寫假單顧名思義是讓用戶可以提交假單;查看假單可以讓用戶查看已經(jīng)填寫的假單;而審批假單可以讓用戶的上級(jí)領(lǐng)導(dǎo)對(duì)所有下屬的假單進(jìn)行審批。
首先讓我們來看看填寫假單的前端實(shí)現(xiàn),再?gòu)?fù)習(xí)一下填寫假單的界面:
在這個(gè)頁(yè)面中,我們提供一個(gè)下拉框用于選擇假別,兩個(gè)calendar和上下午的選擇框用于選擇假期的起止日期,在選完開始時(shí)間和結(jié)束時(shí)間后,會(huì)將假期總天數(shù)計(jì)算出來。可見,我們假期的最小單位是半天。?
在template目錄下新建createvacationapply.html,輸入以下代碼:
<!--createvacationapply.html--> <!--content塊部分--><div class="page-wrapper"><!-- ============================================================== --><!-- Container fluid --><!-- ============================================================== --><div class="container-fluid"><!-- ============================================================== --><!-- Bread crumb and right sidebar toggle --><!-- ============================================================== --><div class="row page-titles"><div class="col-md-6 col-8 align-self-center"><h3 class="text-themecolor m-b-0 m-t-0">填寫假單</h3><ol class="breadcrumb"><li class="breadcrumb-item"><a href="/">Home</a></li><li class="breadcrumb-item active">填寫假單</li></ol></div></div><!-- ============================================================== --><!-- End Bread crumb and right sidebar toggle --><!-- ============================================================== --><!-- ============================================================== --><!-- Start Page Content --><!-- ============================================================== --><!-- Row --><div class="row"><!-- Column --><div class="col-lg-8 col-xlg-9 col-md-7"><div class="card"><div class="card-block"><form class="form-horizontal form-material" action="/createvacationapply" method="post" ><div class="form-group"><label class="col-md-12">假別</label><div class="col-md-12"><select class="form-control form-control-line" name="vacationcategory" id="vacationcategory">{% for category in vacationcategory %}<option value="{{ category.eventcode }}">{{ category.nickname }}</option>{% end %}</select></div></div><div class="form-group"><label class="col-md-12">開始時(shí)間</label><div class="col-md-12"><input type="date" name="startdate" id="startdate" onchange="getTimeSum()" required=true /> <select class="form-control form-control-line" name="startdateMorning" id="startdateMorning" onchange="getTimeSum()"><option value="Morning">上午</option><option value="Afternoon">下午</option></select></div></div><div class="form-group"><label class="col-md-12">結(jié)束時(shí)間</label><div class="col-md-12"><input type="date" name="enddate" id="enddate" onchange="getTimeSum()" required=true /> <select class="form-control form-control-line" name="enddateMorning" id="enddateMorning" onchange="getTimeSum()"><option value="Afternoon">下午</option><option value="Morning">上午</option></select></div></div><div class="form-group"><label class="col-md-12">時(shí)間合計(jì)</label><div class="col-md-12"><input type="text" readonly=true id="timesum" name="timesum" ></input> 天</div></div><div class="form-group"><label class="col-md-12">請(qǐng)假原因</label><div class="col-md-12"><textarea rows=10 class="form-control" required=true name="reason" id="reason"></textarea></div></div><div class="form-group"><div class="col-sm-12"><button type="submit" class="btn btn-success">創(chuàng)建</button></div></div></form></div></div></div><!-- Column --></div><!-- Row --><!-- ============================================================== --><!-- End PAge Content --><!-- ============================================================== --></div><!-- ============================================================== --><!-- End Container fluid --><!-- ============================================================== --><!-- ============================================================== --><!-- footer --><!-- ============================================================== --><footer class="footer text-center">? 2020 Tornado考勤系統(tǒng)</footer><!-- ============================================================== --><!-- End footer --><!-- ============================================================== --></div><script>function getTimeSum(){var strstartdate = document.getElementById("startdate").value;var strenddate = document.getElementById("enddate").value;var startdateMorning = document.getElementById("startdateMorning").value;var enddateMorning = document.getElementById("enddateMorning").value;var startdate = new Date(strstartdate.split('-')[0],strstartdate.split('-')[1],strstartdate.split('-')[2]);var enddate = new Date(strenddate.split('-')[0],strenddate.split('-')[1],strenddate.split('-')[2]);var timesum;if (startdate != "" && enddate != ""){if (startdate == enddate){if (startdateMorning == "Morning" && enddateMorning == "Morning"){timesum = 0.5;}else if (startdateMorning == "Afternoon" && enddateMorning == "Morning"){timesum = 0;}else if (startdateMorning == "Afternoon" && enddateMorning == "Afternoon"){timesum = 0.5;}else{timesum = 1;}}else if (startdate > enddate){timesum = 0;}else{timesum = (enddate - startdate) / 86400000;if (startdateMorning == "Morning" && enddateMorning == "Morning"){timesum += 0.5;}else if (startdateMorning == "Afternoon" && enddateMorning == "Morning"){;}else if (startdateMorning == "Afternoon" && enddateMorning == "Afternoon"){timesum += 0.5;}else{timesum += 1;}}}document.getElementById("timesum").value = timesum;}</script> <!--后面略-->這個(gè)表單值得注意的有以下幾點(diǎn):
現(xiàn)在再讓我們來看看這個(gè)getTimeSum函數(shù)。在這個(gè)函數(shù)開頭,我們通過document.getElementById拿到了startdate、enddate、startdateMorning和enddateMorning的值,并且把startdate和enddate轉(zhuǎn)換成了javascript的Date類型以便之后的計(jì)算;之后就是對(duì)這幾個(gè)值進(jìn)行分類討論,得到正確的timesum的值;最后,再將計(jì)算好的值賦給timesum控件。
下面讓我們看一下對(duì)應(yīng)的后端代碼,還是先寫util函數(shù):打開timesheetutil.py,建立createvacationapply函數(shù):
# util/timesheet/timesheetutil.py # ... from database.tblvacation import Vacation def createvacationapply(username,category,startdate,startdateMorning,enddate,enddateMorning,reason,timesum,approveuser,approvedate,state):result = 'Fail'if timesum == 0:result = 'Fail'return resultif startdateMorning == 'Morning':startdateMorning = Trueelse:startdateMorning = Falseif enddateMorning == 'Morning':enddateMorning = Trueelse:enddateMorning = Falseif startdate == '':result = 'Fail'return resultif enddate == '':result = 'Fail'return resultstartdateinfo = startdate.split('-')startdate_date = datetime.date(int(startdateinfo[0]),int(startdateinfo[1]),int(startdateinfo[2]))enddateinfo = enddate.split('-')enddate_date = datetime.date(int(enddateinfo[0]), int(enddateinfo[1]), int(enddateinfo[2]))check_vacation = session.query(Vacation).filter(and_(Vacation.username==username,Vacation.startdate==startdate_date,Vacation.enddate==enddate_date)).first()if type(check_vacation) is Vacation:result = '當(dāng)前日期已有假單申請(qǐng)'else:newvacationapply = Vacation(username=username,vacationcategory=category,startdate=startdate_date,startdateMorning=startdateMorning,enddate=enddate_date,enddateMorning=enddateMorning,reason=reason,timesum=timesum,approveuser=approveuser,approvedate=approvedate,state=state,applydate=datetime.date.today())result = insertdata(newvacationapply)return result這個(gè)函數(shù)沒什么說的,就是根據(jù)輸入?yún)?shù)在Vacation表里建立一筆數(shù)據(jù)。要注意的就是如果timesum是0的話返回fail,并且在建立數(shù)據(jù)之前先查一下相同日期是否已經(jīng)有了假單申請(qǐng)。
打開timesheet_app.py,實(shí)現(xiàn)CreateVacationApply的handler:
# timesheet_app.py from util.timesheet.timesheetutil import createvacationapplyclass CreateVacationApply(BaseHandler):def get(self):createvacationapplypath = gettemplatepath('createvacationapply.html')vacationcategory = session.query(TimeSheetEvent).filter(TimeSheetEvent.eventcategory == 'Vacation')self.render(createvacationapplypath, vacationcategory=vacationcategory)def post(self):username = ''bytes_user = self.get_secure_cookie('currentuser')if type(bytes_user) is bytes:username = str(bytes_user, encoding='utf-8')category = self.get_argument('vacationcategory')startdate = self.get_argument('startdate')startdateMorning = self.get_argument('startdateMorning')enddate = self.get_argument('enddate')enddateMorning = self.get_argument('enddateMorning')timesum = self.get_argument('timesum')reason = self.get_argument('reason')currentuser = session.query(User).filter(User.username == username).first()approveuser = currentuser.supervisorresult = createvacationapply(username,category,startdate,startdateMorning,enddate,enddateMorning,reason,timesum,approveuser,datetime.date.today(),'WaitForApprove')resultpath = gettemplatepath('result.html')self.render(resultpath, result=result)# main.py routelist = [# ...(r"/createvacationapply", CreateVacationApply),# ... ]這個(gè)的handler的get方法中,會(huì)從TimeSheetEvent中獲得所有category是Vacation的事件傳入前端,以便用戶選擇假期種類;post方法則是簡(jiǎn)單的從表單中拿到數(shù)據(jù)后丟入createvacationapply函數(shù),創(chuàng)建假單。
十四 查看假單
我們已經(jīng)實(shí)現(xiàn)了填寫假單功能,下面讓我們來看一下查看假單。這個(gè)功能比較簡(jiǎn)單,就是把當(dāng)前用戶提過的所有假單都列出來。
我們依然打開timesheetutil.py,實(shí)現(xiàn)viewvacationapply函數(shù):
# timesheetutil.pydef viewvacationapply(username):vacationlist = []vacationapplys = session.query(Vacation).filter(Vacation.username == username)for vacationapply in vacationapplys:vacationdict = {}vacationdict['id'] = vacationapply.idevent = session.query(TimeSheetEvent).filter(TimeSheetEvent.eventcode == vacationapply.vacationcategory).first()if type(event) is TimeSheetEvent:vacationdict['category'] = event.nicknameelse:vacationdict['category'] = vacationapply.vacationcategoryvacationdict['state'] = vacationapply.statevacationdict['startdate'] = vacationapply.startdateif vacationapply.startdateMorning == True:vacationdict['starttime'] = '9:00'else:vacationdict['starttime'] = '13:00'vacationdict['enddate'] = vacationapply.enddateif vacationapply.enddateMorning == True:vacationdict['endtime'] = '9:00'else:vacationdict['endtime'] = '13:00'vacationdict['timesum'] = vacationapply.timesumvacationdict['username'] = usernamevacationlist.append(vacationdict)return vacationlist這里我們把Vacation表中的startdateMorning和enddateMorning根據(jù)True和False分別轉(zhuǎn)換為9:00和13:00,即如果start/enddateMorning是True的話,在頁(yè)面會(huì)顯示為9:00,如果為False,會(huì)顯示為13:00。我們會(huì)把每個(gè)記錄轉(zhuǎn)換為一個(gè)字典,再把這些字典放進(jìn)一個(gè)list中返回出去。
在timesheet_app.py中實(shí)現(xiàn)ViewVacationApply:
# timesheet_app.py from util.timesheet.timesheetutil import viewvacationapplyclass ViewVacationApply(BaseHandler):def get(self):username = ''bytes_user = self.get_secure_cookie('currentuser')if type(bytes_user) is bytes:username = str(bytes_user, encoding='utf-8')vacationlist = viewvacationapply(username)viewvacationapplypath = gettemplatepath('viewvacationapply.html')self.render(viewvacationapplypath,vacationlist=vacationlist)# main.py routelist = [# ...(r"/viewvacationapply",ViewVacationApply),# ... ]它所對(duì)應(yīng)的前端頁(yè)面也很簡(jiǎn)單,就是把后端傳出的vacationlist渲染出來即可:
<!--viewvacationapply.html--> {% block content %}<div class="page-wrapper"><!-- ============================================================== --><!-- Container fluid --><!-- ============================================================== --><div class="container-fluid"><!-- ============================================================== --><!-- Bread crumb and right sidebar toggle --><!-- ============================================================== --><div class="row page-titles"><div class="col-md-6 col-8 align-self-center"><h3 class="text-themecolor m-b-0 m-t-0">查看假單</h3><ol class="breadcrumb"><li class="breadcrumb-item"><a href="/">Home</a></li><li class="breadcrumb-item active">查看假單</li></ol></div></div><!-- ============================================================== --><!-- End Bread crumb and right sidebar toggle --><!-- ============================================================== --><!-- ============================================================== --><!-- Start Page Content --><!-- ============================================================== --><!-- Row --><div class="row"><!-- Column --><div class="col-lg-8 col-xlg-9 col-md-7">{% for vacation in vacationlist %}<div class="card"><div class="card-block"><div class="form-group"><label class="col-md-12">假單ID: {{ vacation['id'] }}</label><label class="col-md-12">假別: {{ escape(vacation['category']) }}</label><label class="col-md-12">{{ vacation['startdate'] }} {{ vacation['starttime'] }} - {{ vacation['enddate'] }} {{ vacation['endtime'] }}</label><label class="col-md-12">總計(jì) {{ escape(vacation['timesum']) }} 天</label><label class="col-md-12">狀態(tài): {{ escape(vacation['state']) }}</label></div></div></div>{% end %}</div><!-- Column --></div><!-- Row --><!-- ============================================================== --><!-- End PAge Content --><!-- ============================================================== --></div><!-- ============================================================== --><!-- End Container fluid --><!-- ============================================================== --><!-- ============================================================== --><!-- footer --><!-- ============================================================== --><footer class="footer text-center">? 2020 Tornado考勤系統(tǒng)</footer><!-- ============================================================== --><!-- End footer --><!-- ============================================================== --></div>{% end %}最后的效果如下:
?
在這期博客中,我們實(shí)現(xiàn)了假單系統(tǒng)中的兩個(gè)功能:填寫假單和查看假單。在下篇博客中,將繼續(xù)實(shí)現(xiàn)假單系統(tǒng)的第三個(gè)功能:審批假單,希望大家繼續(xù)關(guān)注~?
?
總結(jié)
以上是生活随笔為你收集整理的Tornado笔记——用Tornado搭建假单统计考勤系统(十)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL学习笔记(05)_JOIN的类型与
- 下一篇: Vertus fluid mask中文版