背景介绍

团队使用禅道记录开发过程已经有些年时间了,最近领导突然在会议上提出要求每天必须按时的点击任务的开始和结束按钮来更新任务状态。记得当时在会议上我不理智的提出人是不能做到这种程度的。紧接着又立马意识到不应该在这种场合说这样的话。同时被领导质问为什么做不到。

所以会议结束后我就在开始考虑怎么来做到这种程度,经过几天实际尝试后我证明了我自己无法做到在任务开始的时候点击开始,完成的时候点击完成并填上真实的用时。

既然我无法做到,那就想办法来做到,于是就想到了注入 JavaScript 脚本来刷自己名下的任务,自动进入 地盘-> 待处理 -> 任务页面判断是不是有任务需要完成。

实际上最终实现的功能是在中午和下班后检查今天以及今天以前是否有任务可以更新为完成状态。

实现过程

要实现网页一直刷新检查的功能首先需要装一个可以注入 JavaScript 的浏览器扩展,这里我使用的是“暴力猴”,工具有很多种,选择适合自己的。

1.找到需要结束的任务,并新开页面

首先我需要自动进入到“地盘-> 待处理 -> 任务”页面,来看看当前登录的账号下是否有需要结束的任务,下面是找到未完成任务的方法

// 自动完成任务1 - 在我的地盘进入的我的任务页面,找到未完成任务
var completeFlag = false;
var autoCompleteTaskMyPage = function() {var currentHours = date.getHours();if (!((currentHours >= 12 && currentHours < 14) || (currentHours >= 18 && currentHours <= 19))) return; // 只在中午或下午下班才操作if(!isIn('mode=task')) return; // 当前不在我的地盘页面不响应if (completeFlag) return;let completeStatus = ['已完成', '已关闭']; // 已完成的任务状态var myTaskList = $('#myTaskList tr');var name = $('.user-profile-name').text();var id = $('#mainContent .label-id').text(); // 完成任务编辑框上的数据idvar tr = $(`tr[data-id=${id}]`);// 倒序查找,从最早的日期开始找$(myTaskList.toArray().reverse()).each(function (item) {// console.log($(item).find('td.c-user').text());if (completeFlag) return;var td = $(this);var user = td.find('.c-user').text(); // 任务拥有者var status = td.find('.c-status span').text().trim(); // 任务状态if(name == user && !completeStatus.includes(status)) { // 只匹配当前登录用户下的任务,与不等于已完成的任务var dealline = td.find('.text-center').text(); // 任务截止时间// console.log(date.getFullYear()  + '-' +  dealline);var taskDate = date.getFullYear() + '-' + dealline; // 完整截止时间// 只处理小于等于今天的任务if(new Date(taskDate) <= date) {completeFlag = true;// td.find('.icon-task-finish').click(); // 点击完成按钮var dataId = td.attr('data-id'); // 任务编号var hours = td.find('.c-hours').text(); // 任务工时if (hours.indexOf('h')) {hours = hours.split('h')[0];}console.log(status + ' - ' + dealline + ' - ' + hours);window.location.href = `/index.php?m=task&f=finish&taskID=${dataId}&hours=${hours}&taskDate=${taskDate}`;}}});
};

这里顺便提下,在很多年以前那时还没有区分前端和后端的时候,我们都是从数据库一直写到按钮事件的,前端页面对于 JavaScript “框架”主要用的 jQuery,所以发现禅道可以注入 jQuery 代码的时候还是有点感概的,我们和禅道的时间线多少还是有些交集的~~~~

所以整个 JavaScript 代码中元素查找主要使用 jQuery 实现。

第一个方法我们找到需要结束的任务,并自动点击完成按钮。这里可以看到方法的最后是跳转到一个新页面。其实这里是一卡点,因为点击完成时有一个弹窗,这个在弹窗中填写任务工时信息,如果只是弹窗也没什么问题,就是这个弹窗时使用 iframe 加载的内容,但是现在的浏览器对于 iframe 的操作被浏览器出于安全考虑给阻断了。

所以这里采用新开页面来解决填任务的详细信息来绕过 iframe 因为浏览器安全阻断的流程。

2.根据任务工时计算并填写工时信息

前面找到了任务下面就来根据任务的信息自动计算任务工时,把“本次消耗”、“实际开始”、“实际完成”以及“备注”四个输入框填上对应的内容(因为这些是必填项),再点“完成”按钮禅道就会把任务状态更新为“已完成”。

这样这个任务就算完成了,最后如果前面的操作都没出问题(进几个星期看起来没有出过问题)就再次回到“地盘-> 待处理 -> 任务”页面继续寻找下一个可以完成的任务。

// 自动完成任务2 - 在完成任务详情页面,只能通过前面1从程序跳转过来
var autoCompleteTaskFinish = function() {if(!isIn('m=task')) return; // 当前不在完成任务详情页面不响应var hours = queryString('hours'); // 从 url 中获取工时var taskDate = queryString('taskDate'); // 从 url 中获取任务的日期var isAm = date.getHours() < 13; // 是否上午var time = isAm ? '09:05' : '13:05'; // 13点以前任务开始时间设置为9点,以后的设置为13点var taskDateTime = new Date(`${taskDate} ${time}`);var realStarted = `${taskDate} ${time}`;var newHours = parseInt(taskDateTime.getHours()) + parseInt(hours);newHours += (isAm && newHours > 12) ? 1 : 0;var finishedDate = `${taskDate} ${newHours}:05`;$('#currentConsumed').click().focus().val(hours).keyup(); // 设置本次消耗时间$('#realStarted').val(realStarted); // 设置开始时间$('#finishedDate').val(finishedDate); // 设置结束时间$('iframe.ke-edit-iframe').contents().find('body.article-content').html(hours); // 设置 iframe 中富文本内容$('#comment').text(hours); // 设置隐藏 comment 多行文本内容$('button#submit').click();setTimeout(function() { window.location.href = myTaskUrl; }, 3000); // 延时3秒跳转回我的地盘
};

到这里自动完成任务的功能就算完成了。然后在实际使用中发现一个新问题,在一段时间后会话状态会过期,就会自动退到登录页面提示登录。

这个问题也好办,当判断页面来到了登录页面,就尝试自动填写登录信息并完成点击登录,然后再回去接着工作。完美的形成了闭环。

// 自动登录
// const myTaskUrl = '/index.php?m=my&f=work&mode=task&type=assignedTo&orderBy=deadline_desc&recTotal=0&recPerPage=20&pageID=1'; // 我的地盘地址,按日期排倒序
const myTaskUrl = '/index.php?m=my&f=work&mode=task&tid='; // 我的地盘地址
var login = function () {if(!isIn('f=login')) return;$('#account').val('johan'); // 账号 <-------------------------$('input[name=password]').val('123456'); // 密码 <------------$('#submit').click(); // 点击登录if(isIn('mode=task')) return; // 进入我的地盘var tid = queryString('tid');window.location.href = myTaskUrl + tid;
};

前面几次提到的判断当前是在哪个页面的功能是通过 window.location.href 获取当前的浏览器地址来实现的。前面三个方法的前面使用到的 isIn 方法下面贴出来,只有一行代码。

// 判断当前是否在指定服务器或页面
var isIn = function(str) {return window.location.href.indexOf(str) != -1;
};

3.如何让代码自动刷新页面检查任务呢?

这个就是 setInterval 的功劳了,在注入页面的时候,使用 setInterval 将前面的两个方法加到里面去,这样就实现了自动检查的功能。

然后再来一个 count 变量记录当前检查了多少次,并且在一定次数的时候刷新一次页面,并重新注入。这是 Web 系统的特性需要不断的刷新页面来获取数据最新的状态。这里也有考虑到不给浏览器以及服务器太大的压力,刷新的频率被设置为 5 秒执行一次,这种频率对服务器来说可以算得上是无感了。

最后再留个作业:

这里用到的是 Edge 浏览器,在某一个版本的时候贴心的加入了不常用选项卡休眠以提升性能同时延长电池寿命的功能。但是这个功能和机器人冲突了,选项卡休眠后 JavaScript 代码就不会继续执行了。遇到机器人失效的小伙伴可以朝着这个方向去寻找线索。


写在最后

在思考实现功能的时候,最开始是有考虑过使用 .NET6 来实现的,因为这是我工作中主要使用的平台语言。但是这样就需要有一台服务器或自己电脑分出一部分资源来部署运行这个服务,不过这个事情本身又不能拿到台面上来说,所以没有理由申请资源,单独为这个事情挥霍几百兆内存也不是很划得来。而通过浏览器注入的方式就在平时使用的浏览器就顺便做了,权衡下来这种方式最节约资源。

贴上完整的代码压缩包下载地址,里面还附赠了一个自动统计“地盘 -> 贡献 -> 任务”页面每个月任务总数以及工时的功能,0积分免费下:JavaScript 实现自动完成禅道任务

这就是我请的机器人,正在为我工作的机器人。放在你的浏览器中,也可以为你工作。

我请了一个机器人帮我把禅道任务状态改为“已完成”相关推荐

  1. 问题 B: 给苹果分级  直径达到15cm及以上的苹果定为A级,直径达到10cm及以上的苹果定为B级,其他苹果定为C级。请写一个程序帮华逢春实现苹果分级。

    问题 B: 给苹果分级 时间限制: 1 Sec 内存限制: 128 MB 提交: 2421 解决: 1772 [提交] [状态] [讨论版] [命题人:admin] 题目描述 华逢春种的苹果获得了大丰 ...

  2. 搞事 | 5分钟部署一个机器人帮你告别 “信息焦虑”

    次搞事用服务器搭建了一套监控系统,包含 Bug 追踪.数据监控以及可视化仪表盘等功能. 感兴趣的可以点击下面蓝字学习一波~ 搞事 | 这个周末我对落灰的云服务器做了什么? 这次搞事是想部署一个 Tel ...

  3. 我有一台计算机的英语作文,我想拥有一个机器人英语作文

    我想拥有一个机器人英语作文 导语:在电影中,机器人在人们的日常生活很普遍.下面是yuwenmi小编为大家整理的优秀作文,欢迎阅读与借鉴,谢谢! 我想拥有一个机器人 I Want a Robot In ...

  4. 手把手教你作者python机器人,自己训练一个机器人助手

    目录 创建项目 首先我们需要一个py文件用来获取用户输入,我的示例代码如下:Poli.py 下载 RandomKey 下载FastDataTime 其他文件 Hello.py 效果 . python机 ...

  5. 为了追到小姐姐,我用 Python 制作了一个机器人

    阅读文本大概需要 15 分钟. 1 目 标 场 景 最近发现有一个微信好友,我的每一条朋友圈动态,无论什么时候发布,发布的什么内容,点赞列表总有它的身影. 这不禁让我陷入一种沉思,是否我也能做一个机器 ...

  6. 这有一个机器人,粉刷本领强

    铜灵 编译自 Medium 量子位 出品 | 公众号 QbitAI 这有一个机器人,粉刷本领强,它能把那新房子,刷得更漂亮. 刷墙,这件危险.重复.对身体有害的工作,可能要被解放了.有能力解放刷墙工的 ...

  7. 实现一个机器人陪女友自动聊天(不用写一行代码),终于可以安心“打农药”啦

    有女朋友真的很麻烦,没有女朋友又万万不能.现在机器人大行其道,为啥咱们就不能搞个机器人陪下女朋友呢,撸起袖子,说干就干.为了让广大没有编程经验的网友安心"打农药",这次我特意选择了 ...

  8. 收到一个机器人txt微盘_robots . txt是什么?

    txt文本文件网站管理员创建指导网络机器人(通常是搜索引擎机器人)如何在网站上抓取页面. 机器人. txt文件是机器人排除协议的一部分(代表),一组web标准调节机器人抓取网页,如何访问和索引内容,服 ...

  9. c语言 单词变复数_DEV-C++中编写了一段C程序,其中设置了用文件进行... 请编一个程序,可以将英语规则名词由单数变成复数......

    导航:网站首页 > DEV-C++中编写了一段C程序,其中设置了用文件进行... 请编一个程序,可以将英语规则名词由单数变成复数... DEV-C++中编写了一段C程序,其中设置了用文件进行.. ...

最新文章

  1. shell脚本实现C程序日志分流和多Terminal显示
  2. 佛山市禅城区计算机培训机构排名前十,佛山名气大的机器人编程教育品牌排名...
  3. LeanCloud学习笔记(1)
  4. flowable对比
  5. 举例分析private的作用【c/c++学习】
  6. AppList.json文件为空,主界面清缓存后加载后还正常显示
  7. Apache配置问题
  8. 什么是dos及常见命令详解
  9. SylixOS 操作系统Makefile 简介
  10. JavaWeb学习 第7章 Session 会话编程
  11. 服务器雷达信号处理,雷达信号处理的信息几何方法
  12. RBF神经网络-高斯核函数
  13. 了解算法交易,此篇足矣
  14. 一步一步使用webpack+react+scss脚手架重构项目
  15. C#拾遗补阙【01】:字符串
  16. 2021年中国互联网行业发展现状及未来发展趋势分析[图]
  17. 淘宝 生成 图片二维码分享
  18. 职场Word使用技巧大全,教你成为职场高手!
  19. 计算机领域中的token的意思
  20. 抖音直播前需要准备什么,抖音直播带货详细流程步骤丨国仁网络资讯

热门文章

  1. 复材铺层机器人_航空工业复材自动铺丝技术
  2. html论坛原理,html图片轮播原理
  3. Oracle从入门到精通-郑彬彬 郑秋生
  4. android精品源码,下拉刷新效果高德地图五子棋游戏定制日历全民TV源码
  5. Vue 实例之数据绑定,事件,组件,生命周期!!!
  6. 普林斯顿10分钟剧本创作比赛
  7. 良心安利企业内部管理设计模板素材网站
  8. 无聊又看了_好想好想谈恋爱
  9. 自考计算机应用学哪几科先,计算机科学与技术自考本科科目有哪些要考
  10. TR-FS00会计科目创建GL_ACCT_MASTER_SAVE