今天小编为大家带来的是社区作者杨成功的文章,看看他开发的这款有意思的打卡小工具。
你好,我是杨成功。
我们公司用钉钉考勤打卡,人员要求严格。如果我们两次打卡失败,我们将缺席一天。但是我们组太执着于工作了,上班总是忘记打卡,每个月的工资都被扣的很疼。
刚开始的时候,我们都设置了打卡闹钟,提醒我们下班要准时,但是有时候我们加班,下班忘了打卡。有时候很自信以为自己打卡了,第二天看考勤发现没打卡。
为了彻底解决这个问题,保住我们的钱袋子,我开发了打卡提醒工具,让全组连续三个月全职!
下面是这个小工具是如何实现的。
小工具实现思路
首先想一想:为什么报警提醒不能百分百有用?
机械的提醒
报警提醒很机械。每天一个点固定提醒,时间久了人就免疫了。就像起床闹铃响了很久,渐渐的声音对你不起作用了,你就要换铃了。
不能重复提醒
闹钟只会在固定时间提醒一次,没有办法判断是否打卡,发现自己没有打卡也不会很明智,所以再次提醒。
既然报警做不到,那就用程序来实现吧。根据以上两个原因,我们要实现的提醒工具必须包含两个功能:
检测用户是否打卡,未打卡则提醒,已打卡不提醒。对未打卡用户循环检测,重复提醒,直到打卡为止。
如果能实现这两个功能,忘记打卡的问题就解决了大部分。
打孔数据需要从钉钉获取,钉钉有推送功能。所以我们的方案是:使用node . js+钉钉API实现打卡状态检测和精准提醒推送。
认识钉钉 API
钉钉是一款企业版的即时通讯软件。与微信最大的区别是提供了开放性,可以使用API创建群、发送消息等功能,这意味着用钉钉可以实现高度定制化的沟通能力。
我们这里使用的钉钉API主要包括以下几种:
获取凭证获取用户 ID检查打卡状态群内消息推送@某人推送
在使用钉钉API之前,首先要确认自己有公司级的钉钉账号(一般使用过钉钉打卡功能的都有公司账号),下面的步骤都是在这个账号下实现的。
申请开放平台应用
钉钉开发的第一步是在钉钉开放平台申请应用,获得appKey和appSecret。
钉钉开放平台地址:https://open.dingtalk.com/developer
进入平台后,点击“开发者后台”,如下图:
开发者后台是管理自己开发的美甲应用的地方。进入后,选择“应用开发->;企业内部发展”,如下所示:
进入这个页面可能会提示暂时没有权限。这是因为开发企业钉钉应用需要开发者的权限,这个权限需要管理员在后台添加。
管理员加开发者权限:
进入OA管理后台,选择设置-权限管理-管理组-在开发者权限下增加相应的权限。
进入后,选择[创建应用-& gt;H5微应用],根据提示创建应用。创建后,您可以在应用程序信息中看到两个关键字段:
AppKeyAppSecret
这两个字段非常重要,在获取接口调用凭证时需要作为参数传递。AppKey是企业内部应用的唯一标识,AppSecret是对应的调用键。
搭建服务端应用
钉钉API需要在服务器端调用。换句话说,我们需要构建一个服务器应用程序来请求nail API。
记住不能在客户端直接调用钉钉API,因为AppKey和AppSecret都是保密的,永远不能直接暴露给客户端。
我们使用Node.js的Express框架搭建一个简单的服务器应用,并在这个应用上与钉钉API进行交互。构建的Express目录结构如下:
|-app.js//portal文件
|-catch//缓存目录
|-路由器//路由目录
|-ding . js//钉钉路由
|-utils//工具
App.js是入口文件,是应用的核心逻辑。代码简单地编写如下:
const express = require(& # 39;快递& # 39;);const app = express();const body parser = require(& # 39;正文解析器& # 39;);const CORS = require(& # 39;科尔斯& # 39;);app . use(body parser . JSON());app . use(CORS());//路由配置app . use(& # 39;/丁& # 39;,要求(& # 39;。/路由器/丁& # 39;));//Capture 404app.use((req,res,next)= & gt;{资源状态(404)。发送(& # 39;没找到& # 39;);});//捕捉异常app.use((err,req,res,next)= & gt;{ console . error(err);资源状态(错误状态|| 500)。send(err . inner | | err . stack);});app.listen(8080,()= & gt{ console.log(`侦听http://localhost:8080 `);});另一个router/ding.js文件是Express标准的路由文件,钉钉API的相关逻辑写在这里。代码基础结构如下:
//router/ding . jsvar express = require(& # 39;快递& # 39;);var路由器= express。路由器();router . get(& # 39;/',(req,res,next) = >{ RES . send(& # 39;钉钉API & # 39);});module.exports =路由器;现在运行应用程序:
$ node app.js然后访问http://localhost:8080/ding,浏览器页面显示“钉钉API”字样,表示操作成功。
对接钉钉应用
在构建了一个简单的服务器应用之后,就可以准备访问nail API了。
访问步骤参见开发文档,其地址为https://open.dingtalk.com/document/org/application-types.
1. 获取 API 调用凭证
钉钉API需要验证权限才能被调用。验证权限的方式是根据上一步得到的AppKey和AppSecret得到一个access_token,这个access_token就是钉钉API的调用证书。
以后调用其他API时,只需要携带access_token验证权限即可。
钉钉API分为两个版本:新版本和旧版本。为了兼容,我们使用旧版本。旧API的URL根路径是https://oapi.dingtalk.com,它被下面的变量baseURL所取代。
根据文档,获取access_token的接口是${baseURL}/gettoken。在utils/ding.js文件中定义一个获取token的方法,使用GET request获取access_token。代码如下:
const fetchToken = async()= & gt;{ try { let params = { appkey:& # 39;xxx & # 39,app secret:& # 39;xxx & # 39, };let URL = ` $ { base URL }/gettoken `;let result = await axios.get(url,{ params });if (result.data.errcode!= 0){ throw result . data;} else { return result.data} } catch(错误){ console.log(错误);}};上面的代码写好之后,就可以调用fetchToken函数来获取access_token了。
获取access_token后,需要永久保存以备后用。在浏览器端,我们可以保存在localStorage中,而在Node.js端,最简单的方法就是直接保存在文件中。
编写一个可读的类,将access_token保存为一个文件。代码如下:
var fs = require(& # 39;fs & # 39);var path = require(& # 39;路径& # 39;);var catch _ dir = path . resolve(_ _ dirname,& # 39;../', 'catch & # 39);class ding token { get(){ let RES = fs . read file sync(` $ { catch _ dir }/ding _ token . JSON `);return RES . tostring()| | null;} set(token){ fs . write file sync(` $ { catch _ dir }/ding _ token . JSON `,token);}}写完之后,现在我们获取access_token并存储它:
var RES = await fetchToken();if (res) { new DingToken()。set(RES . access _ token);}调用以下接口时,可以通过new DingToken()获取access_token。获取()。
2. 查找组员 ID
使用access_token,首先调用的钉钉API是获取员工的userid。Userid是钉钉内部员工的唯一标识。
有了userid,我们就可以得到团队成员对应的打卡状态。最简单的方法是通过手机号获取员工的userid,直接在钉钉上就可以找到。
根据手机号查询用户文档:https://open . ding talk . com/document/org app-server/query-users-by-phone-number。
接口调用代码如下:
让access_token = new DingToken()。get();设params = { access_token,};axios。post(` $ { base URL }/topapi/v2/user/getbymobile `),{ mobile:& # 39;xxx & # 39、//用户的手机号码}、{params }、)。然后((RES)= & gt;{ console . log(RES);});通过上面的请求方法,逐个获取所有团队成员的userid并保存,我们将在下一步中使用它们。
3. 获取打卡状态
获取团队成员的userid列表,我们可以得到所有团队成员的打卡状态。
要获得打孔状态,您需要在H5应用程序中申请许可。打开之前创建的应用程序,单击[权限管理->;考勤],批量添加所有权限:
然后进入【开发管理】,配置服务器出口IP。这个IP指的是我们调用钉钉API的服务器的IP地址,开发时可以填为127.0.0.1,部署后替换为真实的IP地址。
有了这些准备,我们就可以得到打卡的状态了。获取打卡状态的API如下:
API地址:$ { base URL }/attention/list
请求方式:POST。
此API的请求主体是一个对象,该对象必须包含以下属性:
workDateFrom:查询考勤打卡记录的起始工作日。workDateTo:查询考勤打卡记录的结束工作日。userIdList:查询用户的用户 ID 列表。offset:数据起始点,用于分页,传 0 即可。limit:获取考勤条数,最大 50 条。
解释这里的字段。工作日期From和工作日期To表示考勤的时间范围,因为我们只需要查看当天的数据,所以事件范围是当天的0: 00到24: 00。
userIdList是我们在上一步中获得的所有团队成员的userid列表。
用下面的代码将打卡的状态写成一个单独的方法:
const day js = require(& # 39;dayjs & # 39);const access_token = new DingToken()。get();//Get打卡状态const getattendstatus =(userid list)= > { let params = { access _ token,};let body = { workDateFrom: dayjs()。start of(& # 39;天& # 39;).格式(& # 39;YYYY-MM-DD HH:MM:ss & # 39;),工作日期To: dayjs()。endOf(& # 39;天& # 39;).格式(& # 39;YYYY-MM-DD HH:MM:ss & # 39;),useridlist,//useridlist offset: 0,limit: 40,};return axios . post(` $ { baseURL }/attendance/list`,body,{ params });};考勤返回的结果是一个列表,列表项的关键字段如下:
userId:打卡人的用户 ID。userCheckTime:用户实际打卡时间。timeResult:用户打卡结果。Normal:正常,NotSigned:未打卡。checkType:考勤类型。OnDuty:上班,OffDuty:下班。
其他字段的含义请参考:https://open . ding talk . com/document/org app-server/open-attention-clock-in-data。
以上四个字段可以很容易的判断出哪些人应该打卡,是否正常,这样我们就可以筛选出没有打卡的用户,进行准确的提醒。
有两种筛选打孔状态:
上班打卡下班打卡
上下班打卡时要过滤不同的返回数据。假设获取的打卡数据存储在变量attendList中,获取方法如下:
//获取打卡记录const geton UIDs =()= & gt;出席者名单。过滤器((行)= & gtrow.checkType = = & # 39OnDuty & # 39) .map((row)= & gt;row . userid);//获取考勤记录constgetoffids =()= > attended list。过滤器((行)= & gtrow.checkType = = & # 39OffDut & # 39) .map((row)= & gt;row . userid);获取已打卡的用户,再找到未打卡的用户,就可以发送通知提醒了。
4. 发送提醒通知
钉钉最常见的消息推送方式是在群聊中添加一个机器人,向机器人的webhook地址发送消息,可以实现自定义推送。
或者进入前面创建的H5应用,找到【应用功能->;消息推送-& gt;机器人],根据提示配置机器人。
机器人创建完成后,打开团队成员所在的钉钉群(现有群或新群均可)。单击[组设置-& gt;智能群组助手->;添加机器人],选择刚创建的机器人,就可以在组里绑定机器人了。
绑定机器人后,点击机器人设置,会看到一个Webhook地址。请求此地址向群聊发送消息。对应的API如下:
API地址:${baseURL}/robot/send?Access_token=xxx
请求方式:POST。
现在发一个“我是打孔机器人”,实现代码如下:
const sendNotify = (msg,at UIDs =[])= & gt;{ let access _ token = & # 39xxx & # 39;webhook地址上的Access _ token消息模板配置let infos = { msgtype:& # 39;正文& # 39;,text: { content: msg,},at: { atUserIds: atuids,},};API发送消息axios . post(` $ { base URL }/robot/send `,infos,{params: {access _ token},});};send notify(& # 39;我是一个拳击机器人& # 39;);解释:代码中的atUserIds属性表示想要@的用户,其值是一个userid的数组,可以@群中的一些成员,这样消息推送会更准确。
发送后会在钉钉群里收到一条消息,效果如下:
综合代码实现
在前面的步骤中,创建钉钉应用,获取打卡状态,机器人发送群组通知。现在把这些功能结合起来,写一个界面,查看考勤情况,给没有打卡的用户发送提醒。
在路由文件router/ding.js中创建一个路由方法来实现这个功能:
var day js = require(& # 39;dayjs & # 39);router . post(& # 39;/出席-发送& # 39;,async (req,res,next)= & gt;{try {// userid数组检测打孔=[& # 34;xxx & # 34, "xxxx & # 34];//获取打卡状态LetAttendedList = Await GetAttendedStatus(all UIDs);//无论是9点之前(上班时间)咱们儿子值班= dayjs()。是在(dayjs()之前。小时(9)。分钟(0));//不管是不是18点以后(下班)咱们平等日js()。isafter(日js()。小时(18)。分钟(0));if(ison duty){//punched user let UIDs = getOnUids(attended list);if(all UIDs . length & gt;Uids.length) {//未打卡的用户让tx UIDs = UIDs。过滤器((r) = >!UIDs . includes(r));send notify(& # 34;上班没打卡,小心扣钱!",txuids);} } else if(isoffduty){//打孔用户信guides = get offguides(出席列表);if(all UIDs . length & gt;Uids.length) {//未打卡的用户让tx UIDs = UIDs。过滤器((r) = >!UIDs . includes(r));send notify(& # 34;下班不要打卡,小心扣钱!",txuids);} } else { return RES . send(& # 34;不在打卡时间& # 34;);} RES . send(& # 34;没有不打卡的学生。);} catch(error){ RES . status(error . status | | 500)。发送(错误);}});上面的接口写好之后,我们只需要调用这个接口就可以实现打卡或下班的自动检测。如果有团队成员没有打卡,机器人会在群里发通知提醒,并@那些没有打卡的。
#调用接口
$ curl-x post http://localhost:8080/ding/attend-send
打卡状态检查和提醒功能已经实现,现在还有“循环提醒”功能。
循环提醒的思路是在一定时间内每隔几分钟调用一次接口。如果检测到未打卡状态,会进行循环提醒。
假设通勤时间分别为上午9: 00和下午18: 00,检测时间段可分为:
上班:8:30-9:00 之间,每 5 分钟检测一次;下班:18:00-19:00 之间,每 10 分钟检测一次;
上班打卡比较急,所以检测时间短,频率高。下班打卡比较松,下班时间不固定,所以检测时间长,频率较低。
在确定检测规则后,我们使用Linux的定时任务crontab来实现上述功能。
首先把上面写的Node.js代码部署到Linux服务器上,部署好之后就可以调用Linux内部的接口了。
crontab 配置解析
简单说说如何配置crontab定时任务。其配置模式为每行一个任务,每行的配置字段如下:
//分别是:分、小时、日、月、周、要执行的命令
分钟小时日月工作日cmd。
每个字段由一个特定的数字表示,如果所有字段都要匹配,则用*表示。打卡检测的配置如下:
29-59/5 8 * * 1-5 curl-X POST http://localhost:8080/ding/attend-send
上面的29-59/5 8表示在8:29到8:59之间每5分钟执行一次;1-5表示周一到周五,所以配置。
同样,打卡检测的配置如下:
*/10 18-19 * * 1-5 curl-X POST http://localhost:8080/ding/attend-send
在Linux中执行crontab -e打开编辑页面,写下上面两个配置并保存,然后看是否生效:
$ crontab-l
29-59/5 8 * * 1-5 curl-X POST http://localhost:8080/ding/attend-send
*/10 18-19 * * 1-5 curl-X POST http://localhost:8080/ding/attend-send
看到上面的输出表明定时任务已成功创建。
现在每天下班前后,小工具会自动检测队员的打卡状态,循环提醒。最终效果如下:
总结
这个小工具基于钉钉API+Node.js,有有趣的想法,解决了实际问题。而且这个小项目非常适合学习Node.js代码简洁干净,容易理解和阅读。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。