工作就要上下班打卡,月末想要查看自己的考勤情况,考勤系统通常会记录各工号下的打卡记录。
如果使用日历来展示考勤历史岂不是更直观形象。于是使用考勤系统页面里的API,由于考勤页面是后台生成的HTML,需要使用SOUP库解析为JSON。开发的考勤图表页面。支持原考勤登录验证,选择月份,日历显示上午未打卡或下午未打卡,以及周末加班打卡。
后台使用Python语言开发,requests库访问考勤系统API,flask作为Web框架。代码如下:
# -*- coding:utf-8 -*-
from flask import Flask,render_template,jsonify,request
from bs4 import BeautifulSoup as Soup
import requests
import calendar
import pandas as pd
url='考勤系统URL'
cookies={'SessionId':'登录验证'}
start=10
words=list(calendar.day_abbr)+list(calendar.month_name)[1:]
words2="一,二,三,四,五,六,日,一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月".split(',')
htmlCalendar=calendar.HTMLCalendar()
def getData(ID,year,month,cookies):
req=requests.get(url,params={'ID':ID},cookies=cookies)
text=req.text
soup=Soup(text)
table=soup.find('table')
trs=table.select('tr')[1:]
data=[[td.text.strip() for td in tr.findChildren('td',limit=2)] for tr in trs]
calHtml=htmlCalendar.formatmonth(int(year),int(month))
for i,word in enumerate(words):
calHtml=calHtml.replace(word,words2[i])
return jsonify(data=data,table=str(table),calHtml=calHtml)
app = Flask(__name__)
@app.route("/")
def index():
months=pd.period_range(start='2016-07',end=pd.Timestamp.now(),freq='M')
months=months.map(str).to_list()
months=list(zip(range(start,len(months)+start),months))
return render_template('index.html',months=reversed(months))
@app.route('/check/<param>',methods=["POST"])
def check(param):
sid=request.form.get('sid',None)
cookies0=cookies.copy()
print(sid)
if sid:
print(sid)
cookies0['SessionId']=sid
result=getData(*param.split('-'),cookies0)
return result
if __name__=='__main__':
app.run(host='0.0.0.0',port=8000,debug=True)
前端页面代码如下:
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>考勤日历</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="/static/libs/bootstrap-3.4.1-dist/css/bootstrap.min.css">
<style>
.center-block {
display: block;
margin-left: auto;
margin-right: auto;
}
table.salarybox th {
height: 41px;
line-height: 41px;
border-top: 2px #333333 solid;
border-bottom: 1px #333333 solid;
border-left: 1px #333333 solid;
border-right: 1px #333333 solid;
font-size: 16px;
text-align: center;
}
table.salarybox td {
text-align: center;
font-size: 14px;
border-bottom: 1px #cccccc solid;
line-height: 35px;
}
table.salarybox th.text_left,
table.salarybox td.text_left {
text-align: left;
}
#table {
margin-bottom: 50px;
}
#calendar {
display: inline-block;
}
table.month {
width: 600px;
}
table.month tr {
line-height: 50px;
}
table.month th,
td {
font-size: 20px;
border: 1px solid;
width: 80px;
text-align: center;
}
.sun,.sat{
background: lightgray;
}
td.blue {
background: lightblue;
color: blue;
border-color: black;
}
td.red {
color: red;
background: lightpink;
border-color: black;
}
sub,
sup {
color: gray;
font-size: 8px;
}
</style>
<!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
<!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
<!--[if lt IE 9]>
<script src="https://cdn.jsdelivr.cn/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
<script src="https://cdn.jsdelivr.cn/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="center-block text-center">
<h1>请选择月份!</h1>
<p class="bg-warning" style="display: inline-block;">使用时保持登录OA HR平台,日历显示红色表示上午或下午未打卡</p>
<form class="form-inline" role="search">
<div class="form-group">
<input id="sid" type="text" class="form-control" placeholder="请填写你的考勤SessionId">
</div>
<div class="form-group">
<select id="month" class="form-control" placeholder="">
{% for month in months%}
<option value="{{month[0]}}-{{month[1]}}">{{month[1]}}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-default">查询</button>
</form>
<div class="container">
<div class="row" id="calendar">
</div>
<div class="row" id="table">
</div>
<div class="row">
<img src="/static/imgs/help.png" class="img-responsive">
</div>
</div>
</div>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="/static/libs/jquery.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="/static/libs/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
<script>
$(function() {
$('select')[0].selectedIndex = 1;
$('form').submit(function(e) {
e.preventDefault();
var month = $('#month').val();
var params = {
sid: $('#sid').val()
};
$.post('/check/' + month, params, function(data) {
$('#calendar').html(data['calHtml']);
$('#table').html(data['table']);
$('table.month td').map((i, x) => {
var num = $(x).text().trim();
if (num == '') {
return
}
var now = new Date();
var year0 = month.split('-')[1];
var month0 = month.split('-')[2];
if (now.getFullYear() == year0 && (now.getMonth() + 1) == month0 && num >= now.getDate()) {
return
}
var items = data['data'].filter(y => {
return y[0].substr(8, 2) == parseInt(num);
})
var item1 = items.filter(z => {
return z[1] < '12:00'
})
var item2 = items.filter(z => {
return z[1] > '12:00'
})
if (item1.length > 0 && item2.length > 0) {
$(x).addClass('blue');
} else {
if (item1.length < 1) {
$(x).prepend($("<sup>AM</sup>"));
}
if (item2.length < 1) {
$(x).append($("<sub>PM</sub>"));
}
$(x).addClass('red');
}
});
$('table.month tr').each((i, x) => {
$(x).find('td:gt(4)').removeClass('red').children().remove();
});
window.scrollTo(0,0);
})
return false;
})
})
</script>
</body>
</html>
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。