员工在系统点击签到时,系统会从是否工作日、是否请假、签到时间和地点是否正确上进行判断,确定是否计入考勤。其中,考勤状态分为'正常'、'地区异常'、'早退异常'、'迟到异常'、'旷工异常'。此外,除了通过逻辑判断以外,系统还需要自动查询全天未签到且未请假的员工,后端设置系统自动处理数据,前端自动延时并刷新信息。
逻辑设计
字段名称 | 描述 |
标识符 | UC003 |
测试项 | 用户签到管理功能测试 |
测试环境要求 | 1.用户100002/100002为有效登陆用户 |
输入标准 | 1.用户在正确的时间范围内点击签到,且系统定位在考勤地点范围内 2.用户在正确的时间范围内点击签到,且系统定位在考勤地点范围外 3.用户若在某日的上午/下午/全天未签到 4.用户在请假时间内点击签到 5.用户上午签到时间晚于正常考勤时间,且系统定位在考勤地点范围内 6.用户下午签到时间早于正常考勤时间,且系统定位在考勤地点范围内 7.用户上午签到时间晚于正常考勤时间,且系统定位在考勤地点范围外 8.用户下午签到时间早于正常考勤时间,且系统定位在考勤地点范围外 |
输出标准 | 1.显示的签到状态为正常 2.显示的签到状态为地点异常 3.显示的签到状态为旷工异常 4.显示的签到状态为正常 5.显示的签到状态为迟到异常 6.显示的签到状态为早退异常 7.显示的签到状态为地点异常 8.显示的签到状态为地点异常 |
场景描述 | 签到状态 | ||||
是否工作日 | 是否签到 | 是否在指定时间 | 是否在指定地区 | 是否请假 | |
× | √ | 签到无效 | |||
√ | √ | √ | √ | × | 正常 |
√ | √ | √ | 正常 | ||
√ | √ | × | × | 地点异常 | |
√ | × | × | 旷工异常 | ||
√ | √ | × | √ | × | 早退/迟到异常 |
代码实现
1.在截止时间提醒签到
后端
public void signSelPerson() throws ParseException {//查询个人在某月的正常出勤、异常出勤次数、每天的签到信息
String year=this.getPara("year");
int month=Integer.parseInt(this.getPara("month"));
String time=year+"-"+month+"-01";
String etime=year+"-"+(month+1)+"-01";
// 获取查询的截止时间
SimpleDateFormat ft=new SimpleDateFormat("yyyy-MM-dd");
Date start = ft.parse(etime);
Calendar c=Calendar.getInstance();
c.setTime(start);
c.add(Calendar.YEAR, 0);
c.add(Calendar.MONTH, 0);
c.add(Calendar.DAY_OF_YEAR, -1);
String s=ft.format(c.getTime());
List<Record> covers=Db.find("select * from sign where time>='"+time+"' and time<='"+s+"' and workId='"+getSessionAttr("id")+"'");
int flag=0;
String re="[";
int i=covers.size()-1;
for(int j=0;j<covers.size();j++) {
flag++;
if(covers.get(j).get("signMorning")==null) covers.get(j).set("signMorning","");
if(covers.get(j).get("signAfter")==null) covers.get(j).set("signAfter","");
re+="{"+
"\"workId\":\""+covers.get(j).get("workId")+"\","+"\"id\":\""+covers.get(j).get("workId")+"\","
+"\"signMorning\":\""+covers.get(j).get("signMorning")+"\","+"\"signAfter\":\""+covers.get(j).get("signAfter")+"\","
+"\"state\":\""+covers.get(j).get("state")
+"\"}";
if(flag<=i) re+=",";
}
List<Record> covers1=Db.find("select * from sign where time>='"+time+"' and time<='"+s+"' and workId='"+getSessionAttr("id")+"' and state='正常'");
List<Record> covers2=Db.find("select * from sign where time>='"+time+"' and time<='"+s+"' and workId='"+getSessionAttr("id")+"' and state in('异常'"
+ ",'地区异常','早退异常','迟到异常','旷工异常')");
re+="]";
//设置json数组,向前台发送数据
Map map=new HashMap();
map.put("json", re);
map.put("normalNum", covers1.size());
map.put("abnormalNum", covers2.size());
renderJson(map);
}
前端
getMessage(){//在签到截止时提醒签到,获取后端请求信息
this.getRequest('/sal/sign').then(resp=>{
if(resp.json){
Message.error({message:resp.json});
}
})
}
2.进行签到
后端
public void signSubmit() throws ParseException {//进行签到
String time=new Rule().getDateRealTimeFormat();
String dateR=new Rule().getDateReal();
String place=this.getPara("site");
Calendar c=Calendar.getInstance();
List<Record> c1=Db.find("select * from agreement where workId='"+getSessionAttr("id")+"'");
List<Record> c2=Db.find("select * from signRule");
List<Record> c5=Db.find("select * from sign where workId='"+getSessionAttr("id")+"' and time='"+new Rule().getDateReal()+"' and signMorning is not null");
List<Record> c6=Db.find("select * from sign where workId='"+getSessionAttr("id")+"' and time='"+new Rule().getDateReal()+"' and signAfter is not null");
List<Record> c7=Db.find("select * from apply where applyTime='"+dateR+"' and userId=(select userId from userm where name='"+getSessionAttr("name")+"')"
+ " and state='审核通过' and mark='2'");
String mt=c2.get(0).get("startT")+"";
String at=c2.get(0).get("endT")+"";
String site=c2.get(0).get("site");
String[] sitearr=site.split(";");
String date=c2.get(0).get("signDate");
String[] dateArray=date.split(",");
boolean dBool=false;
for(int i=0;i<dateArray.length;i++) {
if(dateArray[i].equals(dateR))
dBool=true;
}
if(!dBool) {
Map map=new HashMap();
map.put("error", "非工作日不需签到");
renderJson(map);
}
else if(c.get(Calendar.HOUR_OF_DAY)<12) {
// 上午签到
// 查询当天是否请假
List<Record> c3=Db.find("select * from apply where applyTime='"+dateR+"' and userId=(select userId from userm where name='"+getSessionAttr("name")+"') and state='审核通过'");
SimpleDateFormat ft=new SimpleDateFormat("HH:mm:ss");
Date t = ft.parse(mt);
Calendar mtime=Calendar.getInstance();
mtime.setTime(t);
int mh=mtime.get(Calendar.HOUR_OF_DAY)-8;
Record userm;
if(c3.size()>0) {
String s=c3.get(0).getStr("mark");
if(s.equals("0")) {
// 上午请假
userm=new Record().set("state", "正常");
//
Db.save("sign", userm);
}else if(s.equals("2")) {
userm=new Record().set("state", "正常");
Db.save("sign", userm);
}
}else {//未请假site.equals(place)
if(!new Rule().area(sitearr, place)) {
// 判断地区
userm=new Record().set("state", "地区异常");
}else {
System.out.print(mh+" "+c.get(Calendar.HOUR_OF_DAY));
// 判断时间
if(((mh==c.get(Calendar.HOUR_OF_DAY))&&(mtime.get(Calendar.MINUTE)>c.get(Calendar.MINUTE))) || (mh>c.get(Calendar.HOUR_OF_DAY))) {
userm=new Record().set("state", "正常");
}else {
userm=new Record().set("name", getSessionAttr("name")).set("state", "迟到异常");
}
}
Db.save("sign", userm);
}
Map map=new HashMap();
map.put("message", "签到成功");
renderJson(map);
}else {
// 下午签到
SimpleDateFormat ft=new SimpleDateFormat("HH:mm:ss");
Date t = ft.parse(at);
Calendar atime=Calendar.getInstance();
atime.setTime(t);
int ah=atime.get(Calendar.HOUR_OF_DAY)-8;
List<Record> covers=Db.find("select * from sign where workId='"+getSessionAttr("id")+"' and time='"+new Rule().getDateReal()+"'");
List<Record> c3=Db.find("select * from apply where applyTime='"+dateR+"' and userId=(select userId from userm where name='"+getSessionAttr("name")+"') and state='审核通过'");
if(covers.size()>0) {
// 如果上午已经签到
Record pos1=new Record();
if(c3.size()>0) {
String s=c3.get(0).getStr("mark");
if(s.equals("1")) {
// 下午请假
pos1=Db.findById("sign", covers.get(0).getInt("id")).set("state", "正常");
}else if(s.equals("2")) {
pos1=Db.findById("sign", covers.get(0).getInt("id")).set("state", "正常");
}
}else {
if(!new Rule().area(sitearr, place)) {
// 判断地区
pos1=Db.findById("sign", covers.get(0).getInt("id")).set("state", "地区异常");
}else {
System.out.print(ah+" "+c.get(Calendar.HOUR_OF_DAY));
if(((ah==c.get(Calendar.HOUR_OF_DAY))&&(atime.get(Calendar.MINUTE)<c.get(Calendar.MINUTE))) || (ah<c.get(Calendar.HOUR_OF_DAY))) {
// 判断时间是否异常
if(!covers.get(0).get("state").equals("正常"))
pos1=Db.findById("sign", covers.get(0).getInt("id")).set("state", "异常");
else
pos1=Db.findById("sign", covers.get(0).getInt("id")).set("state", "正常");
}else
pos1=Db.findById("sign", covers.get(0).getInt("id")).set("state", "早退异常");
}
}
Db.update("sign",pos1);
}else {
// 上午未签到
Record userm;
if(c3.size()>0) {
String s=c3.get(0).getStr("mark");
if(s.equals("1")) {
// 下午请假但上午未签到
userm=new Record().set("state", "旷工异常").set("time", new Rule().getDateReal());
Db.save("sign", userm);
}
if(s.equals("2")) {
userm=new Record().set("state", "正常").set("time", new Rule().getDateReal());
Db.save("sign", userm);
}
if(s.equals("0")) {
// 上午请假
if(!new Rule().area(sitearr, place)) {
// 判断地区
userm=new Record().set("state", "地区异常").set("time", new Rule().getDateReal());
Db.save("sign", userm);
}else {
if((ah<c.get(Calendar.HOUR_OF_DAY))&&(atime.get(Calendar.MINUTE)<c.get(Calendar.MINUTE))) {
// 判断时间是否异常
userm=new Record().set("state", "正常").set("time", new Rule().getDateReal());
Db.save("sign", userm);
}else {
userm=new Record().set("state", "早退异常").set("time", new Rule().getDateReal());
Db.save("sign", userm);
}
}
}
}
else {
// 未请假
userm=new Record().set("state", "旷工异常").set("time", new Rule().getDateReal());
Db.save("sign", userm);
}
}
Map map=new HashMap();
map.put("message", "签到成功");
renderJson(map);
}
}
系统自动处理全天未签的情况
try {
List<Record> c=Db.find("select workId from agreement a where a.state in ('在职','实习','试用') order by workId asc");
List<String> l=new ArrayList();
List<String> l1=new ArrayList();
List<String> finalL=new ArrayList();
for(int i=0;i<c.size();i++) {
// 全部需要处理的工号
l.add(c.get(i).getStr("workId"));
}
// 处理签到日期
String st = null;
try {
st = new Rule().getDateReal();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SimpleDateFormat ft=new SimpleDateFormat("yyyy-MM-dd");
Date start = null;
try {
start = ft.parse(st);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Calendar cc=Calendar.getInstance();
cc.setTime(start);
cc.add(Calendar.YEAR, 0);
cc.add(Calendar.MONTH, 0);
cc.add(Calendar.DAY_OF_YEAR, -1);
String t=ft.format(cc.getTime());
// 查询已签到的工号
List<Record> c1=Db.find("select workId from sign where time='"+t+"' order by workId asc");
// 查询请假的工号
List<Record> c2=Db.find("select workId from apply a,userm u,agreement ag where applyTime='"+t+"' and a.state='审核通过'"
+ " and a.userId=u.id and u.id=ag.userId order by workId asc");
int a=0,b=0;
for(int i=0;i<c1.size();i++) {
l1.add(c1.get(i).getStr("workId"));
}
for(int i=0;i<c2.size();i++) {
if(!l1.contains(c2.get(i).getStr("workId")))
l1.add(c2.get(i).getStr("workId"));
}
// 对不需操作的工号进行排序
l1.sort((t1,t2)->t1.toString().compareTo(t2.toString()));
int flag=0;
for(int i=0;i<l.size();i++) {
flag=0;
for(int j=0;j<l1.size();j++) {
if(l.get(i).equals(l1.get(j)))
{flag=1;break;}
}
if(flag==0) finalL.add(l.get(i));
}
// 处理全天未签到的情况
for(int i=0;i<finalL.size();i++) {
c1=Db.find("select name,a.id as aid from agreement a,userm u where workId='"+finalL.get(i)+"' and a.userId=u.id");
Record userm=new Record().set("name",c1.get(0).get("name")).set("state","旷工异常");
Db.save("sign", userm);
}
前端
sign(){//进行签到并添加参数
this.getRequest('/sign/signSubmit?site='+window.sessionStorage.getItem('place')).then(resp=>{
if(resp.message)
Message.success({message:resp.message});
if(resp.error)
Message.error({message:resp.error});
})
}
系统自动延时并刷新信息
created(){
//设置自动延时并刷新界面
window.setInterval(()=>{
setTimeout(this.getMessage(),0);
},20000);
}
3.查询考勤数据
界面设计
<el-table v-if="(myrole=='admin')||(myrole=='userHuman')||(role=='admin2')" :data="tableDataW" style="width:60%;margin-top:10px" stripe border size="small">
<el-table-column type='selection' width="55"></el-table-column>
<el-table-column prop="id" label="工号" width="65"></el-table-column>
<el-table-column prop="name" label="姓名" width="70"></el-table-column>
<el-table-column prop="pos" label="职位" width="100"></el-table-column>
<el-table-column prop="state" label="签到状态" width="100">
<template slot-scope="scope">
<el-tag type="success" v-if="scope.row.state=='正常'" >{{scope.row.state}}</el-tag>
<el-tag type="danger" v-else >{{scope.row.state}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="signM" label="上午签到时间" width="150"></el-table-column>
<el-table-column prop="signY" label="下午签到时间"></el-table-column>
</el-table>
前端处理
workSearch(){//查询签到情况
if(this.wdate&&(this.userDep!='选择部门')){
this.getRequest('/apply/selApplyStatus?wdate='+this.wdate+'&dept='+this.userDep).then(resp=>{
if(resp){
this.tableDataW=JSON.parse(resp.json);
}
})
}else if(this.wdate&&(this.userDep=='选择部门')){
this.getRequest('/apply/selApplyStatus?wdate='+this.wdate+'&dept='+this.userDep).then(resp=>{
if(resp){
this.tableDataW=JSON.parse(resp.json);
}
})
}
}
后端代码
public void selApplyStatus() {//查询各部门在某天的考勤情况
String date=this.getPara("wdate");
String myrole=this.getPara("myrole");
String dept=this.getPara("dept");
List<Record> covers = null;
List<Record> c;
if(dept.equals("选择部门"))
c=Db.find("select id from department where pName='"+getSessionAttr("dept")+"'");
else c=Db.find("select id from department where pName='"+dept+"'");
if(dept.equals("选择部门"))
{covers=Db.find("select s.*,a.workId as i,p.name,u.name as n,a.userId from agreement a left join sign s on a.id=s.agreeId left join position p on a.posId=p.id left join userm u on a.userId=u.id where a.deptId="+c.get(0).getStr("id")+" "
+ "and s.time='"+date+"' and a.posRole='user' order by field(s.state,'正常','迟到异常','早退异常','旷工异常','地点异常'),a.workId");}
else {
covers=Db.find("select s.*,a.workId as i,p.name,u.name as n,a.userId from agreement a left join sign s on a.id=s.agreeId left join position p on a.posId=p.id left join userm u on a.userId=u.id where a.deptId="+c.get(0).getStr("id")+" "
+ "and s.time='"+date+"' order by field(s.state,'正常','迟到异常','早退异常','旷工异常','地点异常'),a.workId");
}
String re="[";
for(int i=0;i<covers.size();i++) {
re+="{"+"\"id\":\""+covers.get(i).get("i")+"\","+
"\"name\":\""+covers.get(i).get("n")+"\","+
"\"pos\":\""+covers.get(i).get("name")+"\","+"\"signM\":\""+covers.get(i).getStr("signMorning")+"\","+
"\"signY\":\""+covers.get(i).get("signAfter")+"\","+"\"state\":\""+covers.get(i).get("state")+"\"}";
if(i!=(covers.size()-1)) re+=",";
}
Map map=new HashMap();
map.put("json", re+"]");
renderJson(map);
}
.