在上一篇博客中,我们完成了请假系统的数据库部分设计,现在让我们来实现后端和前端的功能。

十三 填写假单

我们打开base_nav.html,在其中添加新的展开栏,用于放置请假相关功能:

<!--base_nav.html-->
<!--之前代码略,总之就是左侧导航栏继续往下加就是--><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>
<!--之后代码略-->

我们在这里实现三个功能:填写假单、查看假单和审批假单。填写假单顾名思义是让用户可以提交假单;查看假单可以让用户查看已经填写的假单;而审批假单可以让用户的上级领导对所有下属的假单进行审批。

首先让我们来看看填写假单的前端实现,再复习一下填写假单的界面:

在这个页面中,我们提供一个下拉框用于选择假别,两个calendar和上下午的选择框用于选择假期的起止日期,在选完开始时间和结束时间后,会将假期总天数计算出来。可见,我们假期的最小单位是半天。

在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">开始时间</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">结束时间</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">时间合计</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">请假原因</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">创建</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考勤系统</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>
<!--后面略-->

这个表单值得注意的有以下几点:

  1. 假期类别从之前的考勤事件中来;
  2. 我们使用type="date"来生成日历控件,其id分别为startdate和enddate,并且指定了οnchange="getTimeSum()",表明当这个元素变化时要触发getTimeSum函数来计算假期总天数;
  3. 在id为startdateMorning和enddateMorning的两个下拉框中,onchange也为getTimeSum(),因为我们需要上下午改变时也计算假期总天数;
  4. 在最后,我们补了一块<script>块,这是因为如果一个页面是继承的其他模板,则所有代码都必须放进某个block中才能生效,因此我们就把这个函数一并放入了content块。

现在再让我们来看看这个getTimeSum函数。在这个函数开头,我们通过document.getElementById拿到了startdate、enddate、startdateMorning和enddateMorning的值,并且把startdate和enddate转换成了javascript的Date类型以便之后的计算;之后就是对这几个值进行分类讨论,得到正确的timesum的值;最后,再将计算好的值赋给timesum控件。

下面让我们看一下对应的后端代码,还是先写util函数:打开timesheetutil.py,建立createvacationapply函数:

# 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 = '当前日期已有假单申请'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

这个函数没什么说的,就是根据输入参数在Vacation表里建立一笔数据。要注意的就是如果timesum是0的话返回fail,并且在建立数据之前先查一下相同日期是否已经有了假单申请。

打开timesheet_app.py,实现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),# ...
]

这个的handler的get方法中,会从TimeSheetEvent中获得所有category是Vacation的事件传入前端,以便用户选择假期种类;post方法则是简单的从表单中拿到数据后丢入createvacationapply函数,创建假单。

十四 查看假单

我们已经实现了填写假单功能,下面让我们来看一下查看假单。这个功能比较简单,就是把当前用户提过的所有假单都列出来。

我们依然打开timesheetutil.py,实现viewvacationapply函数:

# 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根据True和False分别转换为9:00和13:00,即如果start/enddateMorning是True的话,在页面会显示为9:00,如果为False,会显示为13:00。我们会把每个记录转换为一个字典,再把这些字典放进一个list中返回出去。

在timesheet_app.py中实现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),# ...
]

它所对应的前端页面也很简单,就是把后端传出的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">总计 {{ escape(vacation['timesum']) }} 天</label><label class="col-md-12">状态: {{ 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考勤系统</footer><!-- ============================================================== --><!-- End footer --><!-- ============================================================== --></div>{% end %}

最后的效果如下:

在这期博客中,我们实现了假单系统中的两个功能:填写假单和查看假单。在下篇博客中,将继续实现假单系统的第三个功能:审批假单,希望大家继续关注~

Tornado笔记——用Tornado搭建假单统计考勤系统(十)相关推荐

  1. Tornado笔记——用Tornado搭建假单统计考勤系统(九)

    在上一篇博客中,我们完成了考勤系统的基本功能.现在,让我们继续开发请假系统. 十一 构建事件种类 还记得我们之前建立的考勤事件么?在当前的设计中,考勤事件有两个字段:事件代码和事件名称,现在我们决定给 ...

  2. Tornado笔记——用Tornado搭建假单统计考勤系统(六)

    这篇和上一篇博文隔的时间有点远了,希望大家还记得我们这个系统之前都做了什么.在上一篇博客中,我们构造了一个复杂的表单和calendar类来实现填写考勤的功能.现在,我们要实现查看考勤以及审批考勤的功能 ...

  3. Tornado笔记——用Tornado搭建假单统计考勤系统(八)

    在上一篇博客中,我们补全了一些用户系统的相关功能,这期让我们来实现用户的上下级关系以及考勤审批 十 用户上下级和考勤审批 在我们的系统中,每个用户只有一个上级,但每个用户可以有多个下级.因此,我们需要 ...

  4. 吴恩达神经网络和深度学习-学习笔记-23-快速搭建你的第一个系统原型,然后迭代

    如果你正在开发全新的机器学习应用,你应该尽快建立你的第一个系统原型 (quick and dirty),然后快速迭代. 下面以语音识别系统为例: 一开始,我们有许多选择,不同的方向向前推进,而且每个方 ...

  5. 最新的统计机器翻译系统教程(不定期更新)

    本文目标: 基于moses,Giza++和IRSTLM搭建自己的统计机器翻译系统 简单了解统计机器翻译的基本知识原理 提供前人已总结的优质资源和资料 ps:为了保证内容质量以及简单易懂性,我将分多次更 ...

  6. linux 预览md文件_利用Tornado搭建文档预览系统

    在平时的工作或学习中,我们经常会接触不同格式的文档类型,比如txt,log,Offices文档,编程代码脚本,图片,视频等.本文将会介绍笔者的一个朴素想法,即把不同格式的文档都放在同一个平台中进行预览 ...

  7. Unity笔记-25-简单的商城系统数据库操作

    Unity笔记-25-简单的商城系统&数据库操作 要求与分析 英雄属性界面 展示英雄头像,英雄名称,英雄属性(AD,AP,AR,SR,自左向右,自上向下),金币数量 商店界面 展示可购买的物品 ...

  8. 『中级篇』Minikube快速搭建K8S单节点环境(61)

    原创文章,欢迎转载.转载请注明:转载自IT人故事会,谢谢! 原文链接地址:『中级篇』Minikube快速搭建K8S单节点环境(61) 去介绍k8s的集群安装,本地搭建一个k8s的集群. 不会科学上网的 ...

  9. 数据结构源码笔记(C语言):统计字符串中出现的字符及其次数

    //统计一个字符串中出现的字符及其次数 #include<stdio.h> #include<malloc.h> #include<string.h>#define ...

最新文章

  1. 添加lombok插件
  2. php300类库,扩展类库 · PHP300FrameWork · 看云
  3. 贝叶斯数据分析_周末说说数据分析(2)
  4. nullnullGet previous business day
  5. android使用桢布局,Android 常用布局
  6. js的字符串和变量拼接
  7. React前端格式化时间
  8. beta分布_常用概率分布总结(2)
  9. 仿照小米官网项目具体操作与细节
  10. igs无法分配驱动器映射表_左神算法基础:哈希函数和哈希表
  11. MySQL创建新连接时,不能成功连接的问题
  12. [引]SQL帮助文档:使用 WAITFOR 使SQL语句停顿后执行
  13. linux ida和idr分配机制
  14. 注意力机制的直观理解
  15. 【Python异常处理】:如何处理异常报错?
  16. MacBook M1 Flutter环境搭建
  17. 互联网再升级,蓝汛CEO谈IPv6发展历程
  18. Python实例——身体质量指数BMI
  19. 【学习笔记】明哥聊求职第二季
  20. hdmi转双mipi转接_视频转换 HDMI 转 MIPI ADV7480

热门文章

  1. Attention 与Hierarchical Attention Networks 原理
  2. 中值滤波和均值滤波(转)
  3. 循黑线程序c语言,51单片机舵机循黑线小车程序
  4. 鸿蒙测试机型微博,华为多款机型开启鸿蒙尝鲜:微博已适配小尾巴
  5. 浮云E绘图之多点连线源码
  6. 令人惊艳的文章开头,建议【收藏】
  7. 递推计算小白兔拔萝卜问题的最有矩阵
  8. Robomaster:大风车识别可视化(记录一下)
  9. 一滴水泛起行业波纹,惠民保给保险业带来的启示录
  10. 我爱粟裕--与针式PKM的注册用户的QQ对话系列[2]