Jira看板,自动统计工作量
// ==UserScript==
// @name Jira Tools
// @namespace http://www.akuvox.com/
// @version 1.6
// @description Jira看板,自动统计工作量
// @author minjie.chen
// @match http://192.168.10.2:82/secure/RapidBoard.jspa?rapidView=11*
// @icon https://www.google.com/s2/favicons?sz=64&domain=10.2
// @grant none
// @license minjie.chen
// ==/UserScript==
(function() {
/*库方法*/
HTMLElement.prototype.appendHTML = function(html) {
var divTemp = document.createElement("div"), nodes = null
, fragment = document.createDocumentFragment();
divTemp.innerHTML = html;
nodes = divTemp.childNodes;
for (var i=0, length=nodes.length; i<length; i+=1) {
fragment.appendChild(nodes[i].cloneNode(true));
}
this.appendChild(fragment);
nodes = null;
fragment = null;
};
setInterval(doGetDataAndShowWorkload, 1000);
function doGetDataAndShowWorkload(){
// 页面及所有资源加载完成后执行的代码
$.get('http://192.168.10.2:82/rest/greenhopper/1.0/xboard/work/allData.json?rapidViewId=11&selectedProjectKey=ANDROID', function(data) {
// 请求成功,打印响应数据
showWorkload(data);
}).fail(function() {
// 请求失败,打印错误信息
showWorkload("");
});
}
var loadButton = true;
var isFirst = true;
function showWorkload(data){
//var element = document.getElementsByClassName("subnav-container")[0].parentNode;
var element = document.getElementById("ghx-operations");
if(loadButton){
loadButton = false;
document.getElementById('ghx-header').setAttribute('isshow',0);
element.appendHTML("<a class=\"aui-button aui-button-primary aui-style\" onclick=\"document.getElementById('LastMonthPBX').style.display = '';document.getElementById('ghx-header').setAttribute('isshow',1);\" >上月PBC</a><a class=\"aui-button aui-button-primary aui-style \" onclick=\"document.getElementById('CurMonthPBX').style.display = '';document.getElementById('ghx-header').setAttribute('isshow',1);\">本月PBC</a><a class=\"aui-button aui-button-primary aui-style \" onclick=\"document.getElementById('NextMonthPBX').style.display = '';document.getElementById('ghx-header').setAttribute('isshow',1);\" >下月PBC</a></br>");
}
if(document.getElementById("AkuvoxWorkload") !== null){
document.getElementById("AkuvoxWorkload").innerHTML = "";
element = document.getElementById("AkuvoxWorkload");
}
if(data == ""){
element.appendHTML("<span id=\"AkuvoxWorkload\" style=\"color: red;font-size: 20px;\">工作量统计错误,请刷新界面</span>");
return;
}
var allData = data.issuesData.issues;
var timeData = getMyWorkLoad(allData);
var displayName = getDisplayName();
console.log(timeData);
element.appendHTML("<span id=\"AkuvoxWorkload\" style=\"font-size: 20px;\">"+displayName+":本周工作量:<span style=\"color:red;\">"+hoursToDaysAndHours(timeData.thisWeekWorkload)+"</span>; 下周工作量:<span style=\"color:red;\">"+hoursToDaysAndHours(timeData.netWeekWorkload)+"</span><br>"+displayName+":本月工作量:<span style=\"color:red;\">"+hoursToDaysAndHours(timeData.thisMonthWorkload)+"</span>; 下月工作量:<span style=\"color:red;\">"+hoursToDaysAndHours(timeData.nextMonthWorkload)+"</span></span>");
var body = document.getElementById("jira");
var lastPbc = "";
for(var i = 0;i<timeData.lastMonthResult.length;i++){
var dueDate = ""
var worktime = ""
for(var j = 0;j<timeData.lastMonthResult[i].extraFields.length;j++){
if(timeData.lastMonthResult[i].extraFields[j].label == "到期日" || timeData.lastMonthResult[i].extraFields[j].label == "Due Date" || allData[i].extraFields[j].label == "Target end"){
dueDate = timeData.lastMonthResult[i].extraFields[j].html;
var regex = /<time[^>]*>([^<]*)<\/time>/;
var match = dueDate.match(regex);
if (match && match[1]) {
dueDate = match[1];
}
}
if(timeData.lastMonthResult[i].extraFields[j].label == "初始预估" || timeData.lastMonthResult[i].extraFields[j].label == "Original Estimate"){
worktime = timeData.lastMonthResult[i].extraFields[j].html;
}
}
lastPbc = lastPbc + ("<tr><td>" + timeData.lastMonthResult[i].summary + "</td><td>" + dueDate + "</td><td>" + dueDate+ "</td><td>" + worktime+ "</td><td>" + 0 + "</td><td>"+ 0+ "</td><td>" + 0 + "</td>");
}
var curPbc = "";
for(var i = 0;i<timeData.thisMonthResult.length;i++){
var dueDate = ""
var worktime = ""
for(var j = 0;j<timeData.thisMonthResult[i].extraFields.length;j++){
if(timeData.thisMonthResult[i].extraFields[j].label == "到期日" || timeData.thisMonthResult[i].extraFields[j].label == "Due Date" || allData[i].extraFields[j].label == "Target end"){
dueDate = timeData.thisMonthResult[i].extraFields[j].html;
var regex = /<time[^>]*>([^<]*)<\/time>/;
var match = dueDate.match(regex);
if (match && match[1]) {
dueDate = match[1];
}
}
if(timeData.thisMonthResult[i].extraFields[j].label == "初始预估" || timeData.thisMonthResult[i].extraFields[j].label == "Original Estimate"){
worktime = timeData.thisMonthResult[i].extraFields[j].html;
}
}
curPbc = curPbc + ("<tr><td>" + timeData.thisMonthResult[i].summary + "</td><td>" + dueDate + "</td><td>" + dueDate+ "</td><td>" + worktime+ "</td><td>" + 0 + "</td><td>"+ 0+ "</td><td>" + 0 + "</td>");
}
var nextPbc = "";
for(var i = 0;i<timeData.nextMonthResult.length;i++){
var dueDate = ""
var worktime = ""
for(var j = 0;j<timeData.nextMonthResult[i].extraFields.length;j++){
if(timeData.nextMonthResult[i].extraFields[j].label == "到期日" || timeData.nextMonthResult[i].extraFields[j].label == "Due Date" || allData[i].extraFields[j].label == "Target end"){
dueDate = timeData.nextMonthResult[i].extraFields[j].html;
var regex = /<time[^>]*>([^<]*)<\/time>/;
var match = dueDate.match(regex);
if (match && match[1]) {
dueDate = match[1];
}
}
if(timeData.nextMonthResult[i].extraFields[j].label == "初始预估" || timeData.nextMonthResult[i].extraFields[j].label == "Original Estimate"){
worktime = timeData.nextMonthResult[i].extraFields[j].html;
}
}
nextPbc = nextPbc + ("<tr><td>" + timeData.nextMonthResult[i].summary + "</td><td>" + dueDate + "</td><td>" + dueDate+ "</td><td>" + worktime+ "</td><td>" + 0 + "</td><td>"+ 0+ "</td><td>" + 0 + "</td>");
}
var last = body;
var cur = body;
var next = body;
var isShow = document.getElementById('ghx-header').getAttribute('isShow');
console.log("isShow:",isShow);
if(isShow == 0){
if(document.getElementById("LastMonthPBX") !== null){
console.log("dlaksjdlasjkl!!!!!!!!!!!!!!!!!!!!");
document.getElementById("LastMonthPBX").innerHTML = "";
document.getElementById("CurMonthPBX").innerHTML = "";
document.getElementById("NextMonthPBX").innerHTML = "";
//body.removeChild(document.getElementById("LastMonthPBX"));
//body.removeChild(document.getElementById("CurMonthPBX"));
//body.removeChild(document.getElementById("NextMonthPBX"));
last = document.getElementById("LastMonthPBX");
cur = document.getElementById("CurMonthPBX");
next = document.getElementById("NextMonthPBX");
}
last.appendHTML("<div id=\"LastMonthPBX\" class=\"jira-dialog box-shadow jira-dialog-open popup-width-custom jira-dialog-content-ready\" style=\"width: 810px; margin-left: -406px;top: 0%;"+(isFirst?"display:none":"")+"\">" +
"<span class=\"ghx-iconfont aui-icon aui-icon-small aui-iconfont-close-dialog\" onclick=\"document.getElementById('LastMonthPBX').style.display = 'none';document.getElementById('ghx-header').setAttribute('isshow',0);\" style=\"float: right;\"></span>" +
"<table border=\"1\"><tr><th>任务名称</th><th>计划完成时间</th><th>实际完成时间</th><th>工作量</th><th>已超期</th><th>未完成</th><th>难度系数</th></tr>"+lastPbc+"</table></div>");
cur.appendHTML("<div id=\"CurMonthPBX\" class=\"jira-dialog box-shadow jira-dialog-open popup-width-custom jira-dialog-content-ready\" style=\"width: 810px; margin-left: -406px;top: 0%;"+(isFirst?"display:none":"")+"\">" +
"<span class=\"ghx-iconfont aui-icon aui-icon-small aui-iconfont-close-dialog\" onclick=\"document.getElementById('CurMonthPBX').style.display = 'none';document.getElementById('ghx-header').setAttribute('isshow',0);\" style=\"float: right;\"></span>" +
"<table border=\"1\"><tr><th>任务名称</th><th>计划完成时间</th><th>实际完成时间</th><th>工作量</th><th>已超期</th><th>未完成</th><th>难度系数</th></tr>"+curPbc+"</table></div>");
next.appendHTML("<div id=\"NextMonthPBX\" class=\"jira-dialog box-shadow jira-dialog-open popup-width-custom jira-dialog-content-ready\" style=\"width: 810px; margin-left: -406px;top: 0%;"+(isFirst?"display:none":"")+"\">" +
"<span class=\"ghx-iconfont aui-icon aui-icon-small aui-iconfont-close-dialog\" onclick=\"document.getElementById('NextMonthPBX').style.display = 'none';document.getElementById('ghx-header').setAttribute('isshow',0);\" style=\"float: right;\"></span>" +
"<table border=\"1\"><tr><th>任务名称</th><th>计划完成时间</th><th>实际完成时间</th><th>工作量</th><th>已超期</th><th>未完成</th><th>难度系数</th></tr>"+nextPbc+"</table></div>");
}
isFirst=false;
}
function isDateInThisWeek(dateString) {
// 将日期字符串转换为 Date 对象
var date = new Date(dateString);
// 获取当前日期
var currentDate = new Date();
// 获取当前日期的星期几(0表示星期日,1表示星期一,以此类推)
var currentDayOfWeek = currentDate.getDay();
// 获取本周一的日期
var monday = new Date(currentDate);
monday.setDate(currentDate.getDate() - currentDayOfWeek + 1);
monday.setHours(0, 0, 0, 0);
// 获取本周日的日期
var sunday = new Date(currentDate);
sunday.setDate(currentDate.getDate() + (7 - currentDayOfWeek));
sunday.setHours(23, 59, 59, 999);
// 将待判断日期与本周一和本周日进行比较
return date >= monday && date <= sunday;
}
function isDateInNextWeek(dateString) {
// 将日期字符串转换为 Date 对象
var date = new Date(dateString);
// 获取当前日期
var currentDate = new Date();
// 获取当前日期的星期几(0表示星期日,1表示星期一,以此类推)
var currentDayOfWeek = currentDate.getDay();
// 计算下周一的日期
var nextMonday = new Date(currentDate);
nextMonday.setDate(currentDate.getDate() - currentDayOfWeek + 8);
nextMonday.setHours(0, 0, 0, 0);
// 计算下周日的日期
var nextSunday = new Date(currentDate);
nextSunday.setDate(currentDate.getDate() - currentDayOfWeek + 14);
nextSunday.setHours(23, 59, 59, 999);
// 将待判断日期与下周一和下周日进行比较
return date >= nextMonday && date <= nextSunday;
}
function isDateInThisMonth(dateString) {
// 将日期字符串转换为 Date 对象
var date = new Date(dateString);
// 获取当前日期
var currentDate = new Date();
// 获取当前日期的年份和月份
var currentYear = currentDate.getFullYear();
var currentMonth = currentDate.getMonth();
// 获取待判断日期的年份和月份
var targetYear = date.getFullYear();
var targetMonth = date.getMonth();
// 判断待判断日期是否属于本月
return currentYear === targetYear && currentMonth === targetMonth;
}
function isDateInLastMonth(dateString) {
// 将日期字符串转换为 Date 对象
var date = new Date(dateString);
// 获取当前日期
var currentDate = new Date();
// 获取当前日期的年份和月份
var currentYear = currentDate.getFullYear();
var currentMonth = currentDate.getMonth();
// 获取待判断日期的年份和月份
var targetYear = date.getFullYear();
var targetMonth = date.getMonth();
// 判断待判断日期是否是上个月
if (currentYear === (targetYear+1) && currentMonth === 0 && targetMonth === 11) {
return true; // 当前是1月,待判断日期是去年的12月
}
return currentYear === targetYear && currentMonth - 1 === targetMonth;
}
function isDateInNextMonth(dateString) {
// 将日期字符串转换为 Date 对象
var date = new Date(dateString);
// 获取当前日期
var currentDate = new Date();
// 获取当前日期的年份和月份
var currentYear = currentDate.getFullYear();
var currentMonth = currentDate.getMonth();
// 获取待判断日期的年份和月份
var targetYear = date.getFullYear();
var targetMonth = date.getMonth();
// 计算下个月的年份和月份
var nextMonthYear = currentYear;
var nextMonth = currentMonth + 1;
if (nextMonth === 12) {
nextMonthYear = currentYear + 1;
nextMonth = 0;
}
// 判断待判断日期是否属于下个月
return targetYear === nextMonthYear && targetMonth === nextMonth;
}
function timeToHours(time) {
// 定义时间单位与小时的换算关系
const weeksToHours = 5 * 8;
const daysToHours = 8;
let totalHours = 0;
var array = time.split(",");
for(var i = 0 ;i<array.length;i++){
const [amount, unit] = array[i].trim().split(' ');
// 根据单位进行换算,并累加到总小时数
if (unit === 'week' || unit === 'weeks') {
totalHours += parseInt(amount) * weeksToHours;
} else if (unit === 'day' || unit === 'days') {
totalHours += parseInt(amount) * daysToHours;
} else if (unit === 'hour' || unit === 'hours') {
totalHours += parseInt(amount);
}
}
return totalHours;
}
function getUserName(){
var currentURL = window.location.href;
if (currentURL.includes('quickFilter=')) {
// 提取quickFilter参数的值
const urlParams = new URLSearchParams(currentURL.split('?')[1]);
const quickFilterValue = urlParams.get('quickFilter');
if(quickFilterValue == 54){
return "minjie.chen"
}else if(quickFilterValue == 55){
return "guoyong.lin"
}else if(quickFilterValue == 59){
return "weijian.wang"
}else if(quickFilterValue == 57){
return "hao.jiang"
}else if(quickFilterValue == 56){
return "minghui.zhou"
}else if(quickFilterValue == 58){
return "kaijia.wu"
}else if(quickFilterValue == 60){
return "nairong.yang"
}else if(quickFilterValue == 127){
return "zhixian.yang"
}else if(quickFilterValue == 137){
return "shize.huang"
}else if(quickFilterValue == 138){
return "xianhong.zhang"
}else if(quickFilterValue == 179){
return "zixin.liu"
}else if(quickFilterValue == 190){
return "kai.xiong"
}else{
return document.getElementById("header-details-user-fullname").getAttribute('data-username');
}
} else {
return document.getElementById("header-details-user-fullname").getAttribute('data-username');
}
}
function getDisplayName(){
var currentURL = window.location.href;
if (currentURL.includes('quickFilter=')) {
// 提取quickFilter参数的值
const urlParams = new URLSearchParams(currentURL.split('?')[1]);
const quickFilterValue = urlParams.get('quickFilter');
if(quickFilterValue == 54){
return "陈敏杰"
}else if(quickFilterValue == 55){
return "林国勇"
}else if(quickFilterValue == 59){
return "王伟建"
}else if(quickFilterValue == 57){
return "江昊"
}else if(quickFilterValue == 56){
return "周明辉"
}else if(quickFilterValue == 58){
return "吴铠嘉"
}else if(quickFilterValue == 60){
return "杨乃容"
}else if(quickFilterValue == 127){
return "杨智贤"
}else if(quickFilterValue == 137){
return "黄世泽"
}else if(quickFilterValue == 138){
return "张显鸿"
}else if(quickFilterValue == 179){
return "刘紫馨"
}else if(quickFilterValue == 190){
return "熊凯"
}else{
return document.getElementById("header-details-user-fullname").getAttribute('data-displayname');
}
} else {
return document.getElementById("header-details-user-fullname").getAttribute('data-displayname');
}
}
function hoursToDaysAndHours(hours) {
// 计算天数和剩余小时数
var days = Math.floor(hours / 8);
var remainingHours = hours % 8;
// 构造结果字符串
var result = "";
if (days > 0) {
result += days + "天 ";
}
result += remainingHours + "小时";
return result;
}
function getMyWorkLoad(allData){
// 获得用户名
var userName = getUserName();
var thisWeekWorkload = 0;
var netWeekWorkload = 0;
var thisMonthWorkload = 0;
var nextMonthWorkload = 0;
var thisMonthResult = [];
var nextMonthResult = [];
var lastMonthResult = [];
for(var i = 0;i<allData.length;i++){
if(allData[i].assignee == userName){
var thisWeek = 0;
var nextWeek = 0;
var thisMonth = 0;
var nextMonth = 0;
var time = 0;
for(var j = 0;j<allData[i].extraFields.length;j++){
if(allData[i].extraFields[j].label == "初始预估" || allData[i].extraFields[j].label == "Original Estimate"){
time = timeToHours(allData[i].extraFields[j].html);
}else if(allData[i].extraFields[j].label == "到期日" || allData[i].extraFields[j].label == "Due Date" || allData[i].extraFields[j].label == "Target end"){
var targetTime = allData[i].extraFields[j].html;
var regex = /<time[^>]*>([^<]*)<\/time>/;
var match = targetTime.match(regex);
if (match && match[1]) {
targetTime = match[1];
}
if(isDateInThisWeek(targetTime)){
console.log("时间=",allData[i]);
thisWeek = time;
}
if(isDateInNextWeek(targetTime)){
nextWeek = time;
}
if(isDateInThisMonth(targetTime)){
thisMonth = time;
thisMonthResult.push(allData[i]);
break;
}
if(isDateInNextMonth(targetTime)){
nextMonth = time;
nextMonthResult.push(allData[i]);
break;
}
if(isDateInLastMonth(targetTime)){
lastMonthResult.push(allData[i]);
break;
}
}
}
thisWeekWorkload += thisWeek;
netWeekWorkload += nextWeek;
thisMonthWorkload += thisMonth;
nextMonthWorkload += nextMonth;
}
}
return {"thisWeekWorkload":thisWeekWorkload,"netWeekWorkload":netWeekWorkload,"thisMonthWorkload":thisMonthWorkload,"nextMonthWorkload":nextMonthWorkload,"thisMonthResult":thisMonthResult,"nextMonthResult":nextMonthResult,"lastMonthResult":lastMonthResult};
}
})();