让打卡小工具"智能一点”:添加请假过滤、Token自动刷新

开发 前端
本篇介绍了钉钉打卡小工具两个方面的优化,还有配置部分的代码我也做了精简,可以更快的接入自己的钉钉应用。

大家好,我是杨成功。

前面写了一篇文章,介绍了如何用 Node.js + 钉钉 API 实现考勤打卡连续提醒的小工具。

有的同学留言说为什么不直接调用钉钉 API 自动打卡(这个我也想过)。可惜我翻遍了钉钉的文档都没有找到这个 API。

再说了,怎么可能有这个 API 呢?想啥呢?

还有的同学严厉的指出了问题:“我请假了你还一直提醒?token 用几个小时就过期!”。

针对这两个问题,我们在上次实现代码的基础上进行优化,添加两个逻辑:

  1. 获取未打卡的人员时,过滤已请假人员。
  2. 当 token 过期时,自动刷新 token。

接下来我们一起实现新增的需求,优化打卡功能。

过滤已请假人员

使用钉钉 API 可以获取一些人员的打卡状态。

目前我们的做法是,将需要检测打卡状态的人员(我们全组人员)的 userid 维护在一个列表中,然后获取到这些人的打卡数据,从而筛选出未打卡的人员。

特殊情况是,假设我们组的一个组员今天请假了,他会被当作未打卡人员不断地被提醒,这是不合理的。

其实我们应该将已请假的人员排除在外。要实现这个,第一步是要获取今日已请假的人员。

获取请假状态的 API 如下:

API 地址:${baseURL}/topapi/attendance/getleavestatus。

请求方法:POST。

这个 API 的请求体是一个对象,对象的属性如下:

  • userid_list:查询请假状态的 userid 列表。
  • start_time:查询开始时间(当天上班时间)。
  • end_time:查询结束时间(当天下班时间)。
  • size:返回条数,最大 20。
  • offset:分页,从 0 开始。

将获取请假状态写为一个单独的方法,代码如下:

const dayjs = require('dayjs');
const access_token = new DingToken().get();
// 获取请假状态
const getLeaveStatus = async (userid_list) => {
let params = {
access_token,
};
let body = {
start_time: dayjs().startOf('day').valueOf(),
end_time: dayjs().endOf('day').valueOf(),
userid_list: userid_list.join(), // userid 列表
offset: 0,
size: 20,
};
let res = await axios.post(`${baseURL}/topapi/attendance/getleavestatus`, body, { params });
if (res.errcode != 0) {
return res;
} else {
return res.result.leave_status.map((row) => row.userid);
}
};

执行以上方法后,就可以获取到当天已请假的用户。接着在所有需要检测打卡状态的用户列表中,过滤掉已请假的用户:

// 需要检测打卡的 userid 数组
let alluids = ['xxx', 'xxxx'];
// 获取请假状态
let leaveRes = await getLeaveStatus(alluids);
if (leaveRes.errcode) {
return leaveRes;
}
alluids = alluids.filter((uid) => !leaveRes.includes(uid));
console.log(alluids); // 过滤后的 userid 数组

这样就不会对已请假的用户发出提醒了。

钉钉 token 自动刷新

在获取钉钉 API 时,首先要获取接口调用凭证(也就是 access_token),每个 API 调用时都要携带这个凭证。但这个凭证是有期限的,有效期一过 API 就会被禁止调用。

因此,这里非常重要的一个优化点,就是自动刷新 access_token。

怎么做呢?其实和在前端项目中实现一样,在 axios 的拦截器中判断 access_token 是否过期,如果过期则重新获取,然后继续执行请求。

首先,将获取凭证写成一个单独的方法,如下:

const fetchToken = async () => {
try {
let params = {
appkey: 'xxx',
appsecret: 'xxx',
};
let url = 'https://oapi.dingtalk.com/gettoken';
let result = await axios.get(url, { params });
if (result.data.errcode != 0) {
throw result.data;
} else {
let token_str = JSON.stringify({
token: result.data.access_token,
expire: Date.now() + result.data.expires_in * 1000,
});
new DingToken().set(token_str);
return token_str;
}
} catch (error) {
console.log(error);
}
};

这个方法主要是调用获取凭证的 API,调用成功后会返回 access_token 和有效时间。这里我们要设置一个过期时间,就是当前时间+有效时间,生成一个过期时间的时间戳:

Date.now() + result.data.expires_in * 1000,

这里还有一个 DingToken 类是用于获取和存储 access_token 的,代码如下:

var fs = require('fs');
var catch_dir = path.resolve(__dirname, '../', 'catch');
class DingToken {
get() {
let res = fs.readFileSync(`${catch_dir}/ding_token.json`);
return res.toString() || null;
}
set(token) {
fs.writeFileSync(`${catch_dir}/ding_token.json`, token);
}
}

将 access_token 和过期时间组成一个 JSON 字符串存储到文件中,接下来就可以在 axios 的请求拦截器中获取到这个 JSON 数据,然后判断当前时间是否大于过期时间。

如果是,则重新调用 fetchToken() 方法生成新 token,并继续执行请求。拦截器代码如下:

const axios = require('axios');
const instance = axios.create({
baseURL: 'https://oapi.dingtalk.com',
timeout: 5000,
});
const dingToken = new DingToken();
// 请求拦截器
instance.interceptors.request.use(async (config) => {
if (!config.params.access_token) {
let catoken = {};
if (dingToken.get()) {
catoken = JSON.parse(dingToken.get());
// 判断是否过期
if (Date.now() - catoken.expire >= 0) {
console.log('钉钉 token 过期');
await fetchToken();
catoken = JSON.parse(dingToken.get());
}
} else {
// 第一次获取token
await fetchToken();
catoken = JSON.parse(dingToken.get());
}
// 将 token 携带至请求头
config.params.access_token = catoken.token;
}
return config;
});

通过上面在拦截器中编写的逻辑,我们就不需要关心 access_token 过期了。并且我们是在 token 过期之后才会重新请求,因此也不会触发调用频率限制。

总结

本篇介绍了钉钉打卡小工具两个方面的优化,还有配置部分的代码我也做了精简,可以更快的接入自己的钉钉应用。

责任编辑:姜华 来源: 程序员成功
相关推荐

2009-12-08 14:02:25

Windows 7小工

2022-06-08 12:10:56

canvasvue.js

2009-11-19 08:48:10

Windows 7桌面工具

2016-09-01 08:36:27

Windows 10离线小工具

2022-09-01 09:56:14

工具通讯软件API

2022-12-28 12:29:45

duf命令

2017-07-25 14:20:13

戴尔配置功耗

2019-01-27 22:09:33

智能海滩物联网工具物联网

2024-04-03 15:27:31

Python接口自动化开发

2010-07-01 10:24:30

UML小工具

2023-04-26 01:21:34

工具URL地址

2021-11-05 06:57:50

架构工具代码

2011-11-30 16:31:00

TimZon

2023-12-20 07:41:41

2011-03-10 09:03:35

Python

2012-03-15 10:32:05

Windows系统网络故障

2016-04-05 10:12:58

HiveSQLHadoop

2022-03-30 15:11:26

Python房价工具

2022-01-17 06:27:28

Windows 11操作系统微软

2013-03-29 14:46:33

App开发小工具辅助工具
点赞
收藏

51CTO技术栈公众号