likes
comments
collection
share

给自己编写一个批量填写日报的工具

作者站长头像
站长
· 阅读数 19

背景

公司要求我们每天填写工时,每天的时间都花在了哪些地方,干了什么。平时没顾得上填,欠下了一屁股工时债。收到邮件催填通知后,发现要补两个月的工时,填了一会儿,感觉变化的只是日期和工作内容,其它的内容项都是固定内容。一天一天填着实费劲,于是决定写一个填写日报的小工具,只要在js文件中,补充一下每天的工作内容,然后执行node命令,批量完成工时的填写。

思路

  1. 先根据设置的起始结束时间,查询一下当月有多少个工作日,要补多少天的工时。要排除当月每周周末,法定节假日的日期,加上调休补班的日期。
  2. 根据计算出来的需要补充工时的天数,编辑好要补填的工作内容条数,然后批量发送网络请求,完成工时的填写。

工作日查询实现

发现了一个叫蛙蛙工具的网站,免费提供接口给第三方使用,可以用来查询工作日。每分钟限制查10次。下图是抓取的响应数据:重点说一下要用到的weekend_date_listholiday_date_list字段;

  • weekend_date_list 周末日期
  • holiday_date_list 法定节假日

只要排除这两个数组中的日期,剩下的就是查询日期时间段工作日。

给自己编写一个批量填写日报的工具

思路有了,来看看实现。首先要写好发送查询请求的逻辑,要知道请求地址,请求参数,请求参数格式,响应数据内容。其次,拿到响应结果后,生成一个从开始日期到结束日期,格式为YYYY-MM-DD的数组,从这个数组中剔除周末和法定节假日,剩余的日期就是工作日,知道工作日的天数后,就知道要写几天的工作日报。代码如下:

import axios from "axios";
import { startDate, endDate } from "./config.js";

// 查询从本月的工作日
export const queryWorkingDay = () => {
  return new Promise((resolve, reject) => {
    const url = "https://www.iamwawa.cn/home/workingday/ajax";
    const params = {
      start_date: startDate.format("YYYY-MM-DD"),
      end_date: endDate.format("YYYY-MM-DD"),
    };

    axios
      .post(url, params, { headers: { "Content-Type": "application/x-www-form-urlencoded" } })
      .then(({ data: res }) => {
        const { status, data, info } = res;
        const {
          // 平常的周末
          weekend_date_list = [],
          // 法定节假日
          holiday_date_list = [],
          // 法定节假日补班
          tune_date_list = [],
          // 工作日天数
          working_date_count,
        } = data;

        // 生成从开始时间到结束时间的日期
        const dayOfMonth = [];
        for (let day = startDate; day.valueOf() <= endDate.valueOf(); day = day.add(1, "day")) {
          dayOfMonth.push(day.format("YYYY-MM-DD"));
        }

        // 需要排除的法定节假日和周末
        const excludeDays = [
          weekend_date_list.map((item) => item.date),
          holiday_date_list.map((item) => item.date),
        ].flat();

        // 工作日
        const workDays = dayOfMonth.filter((day) => !excludeDays.includes(day));

        //   console.log(status,data,info);
        console.log(`本月你需要补充${working_date_count}天日报`);
        console.log(`需要填写的日期:`);
        workDays.forEach((day) => {
          console.log(day);
        });

        console.log(`需要排除的日期:`);
        excludeDays.forEach((day) => {
          console.log(day);
        });

        resolve(workDays);
      });
  });
};

提交工时实现

先登录填报工时网站, 手动填写一条,在调试模式下查看一下请求地址和请求参数。 给自己编写一个批量填写日报的工具 请求地址我就不贴出来了,这里只提供思路,请求数据为:

{
    "workDate": "2023-03-14", 
    "tapdId": null, 
    "groupId": 12, 
    "projectId": 159, 
    "lineId": 2, 
    "taskId": 16, 
    "workContent": "xxxxxx", 
    "workHours": 8
}

如法炮制查询工作日的方法,发起工时提交请求,结果吃了闭门羹。提示没有权限。

给自己编写一个批量填写日报的工具

后面经过排查,发现网络请求的请求头,需要带一个authorization的参数,服务器根据这个参数判断有没有提交权限。这个参数你必须登录原网站才能拿到,把这个参数复制出来,配置到代码中,再发请求,这次很顺利的提交了。

给自己编写一个批量填写日报的工具

提交数据跑通之后,要实现批量提交数据就很Easy了,循环调用提交单条数据的接口就可以了。有个细节需要注意一下,提交请求太快,服务器会返回错误,所以每个请求之间加了一个500ms的延时。提交工时的代码如下:

    import axios from "axios";
    import { queryWorkingDay } from "./queryDay.js";
    import { authorization, workContentList } from "./config.js";

    // 提交每月的工时
    export const submitMonthWorkHour = async () => {
      const workDays = await queryWorkingDay();

      for (let index = 0, len = workContentList.length; index < len; index++) {
        await submitEachDayData(workDays[index], workContentList[index]);
      }
    };

    /**
     * 提交每天的工时数据
     * @param {*} workDate    工作日期
     * @param {*} workContent 工作内容
     */
    const submitEachDayData = (workDate, workContent) => {
      return new Promise((resolve, reject) => {
        const url = "https://xxx/xxx",
          authorization,
          "Content-Type": "application/json",
        };

        const params = {
          workDate,
          workContent,
          tapdId: null,
          groupId: 12,
          projectId: 159,
          lineId: 2,
          taskId: 16,
          workHours: 8,
        };

        setTimeout(() => {
          axios
            .post(url, params, { headers })
            .then(({ data }) => {
              const { ret, retdata, retmsg } = data;
              //   if (ret === 0) {
              console.log(`${workDate}--${retmsg}`);
              resolve("ok");
              //   }
            })
            .catch((err) => reject(err));
        }, 500);
      });
    };

主流程实现

在package.json中配置两条指令,一条用于查询设置的起始结束时间有多少个工作日,需要补充多少天的工作日报,接着在上面的submitMonthWorkHour方法中,手动编辑,给工作内容列表workContentList填充数据,一条数据对应一天的工作日报。填写完之后,执行提交命令。

{
  "license":"MIT",
  "scripts": {
    "query": "node main.js query",
    "submit": "node main.js submit"
  },
  "dependencies": {
    "axios": "^1.3.4",
    "dayjs": "^1.11.7"
  },
  "type": "module",
  "devDependencies": {}
}

顺便说一下,node v9+版本,若要使用import/export语法, 需要在package.json中指定 "type": "module"

在主函数中, 根据不同的指令执行不同的操作。实际使用时, 肯定是要先调用yarn query查询补充多少天日报才行。

import { queryWorkingDay } from "./queryDay.js";
import { submitMonthWorkHour } from "./submitData.js";

main();
// 主流程
function main() {
  const argv = process.argv;
  // 先查询需要补充多少天日报
  if (argv.includes("query")) {
    queryWorkingDay();
  } else if (argv.includes("submit")) {
    submitMonthWorkHour();
  } else {
    console.log('指令错误');
    process.exit(1);
  }
}

把配置数据放到config.js中, 查询的开始时间和结束时间,可根据实际情况手动配置。需要注意一下dayjs().set('month',num), num的取值是0-11,对应的月份是1-12。

    import dayjs from "dayjs";
    // 设置查询工作日的开始时间
    // 设置查询工作日的开始时间,注意月份的取值是0-11
    export const startDate = dayjs().set('month',2).set("date", 6);
    export const endDate = dayjs().set('month',2).set("date", 31);
    // 每次先登录一下填报工时的网站,把http请求头中的authorization复制出来
    export const authorization = "";
      // 手动填写需要补充的工时
    export const workContentList = [""];

结语

至此,批量提交日报的小工具就开发完了。爱因斯坦说, 比知识更重要的是想象力。文中列举的知识点大家可能都懂,但是要把这些知识串接起来,开发一个有实用价值的工具,是需要一点灵动和想象力的。而灵动来源于优化意识,需要一个善于发现问题的心灵,洞悉生活中,工作中的痛点,寻找改进之法。 这个小工具已上传至码云,感兴趣的朋友可点击这里下载

本文正在参加「金石计划」