// ==UserScript==
// @name WorkTile交互优化
// @namespace http://fulicat.com
// @version 1.1.5
// @description 优化愚蠢的交互方式和样式,让操作更便捷更人性!
// @author Jack.Chan
// @homepage https://greasyfork.org/zh-CN/scripts/436038
// @license MIT
// @url https://greasyfork.org/zh-CN/scripts/436038-worktile%E4%BA%A4%E4%BA%92%E4%BC%98%E5%8C%96
// @match https://*.worktile.com/*
// @icon https://cdn.pingcode.com/static/portal/favicon.ico
// @grant none
// ==/UserScript==
(function() {
'use strict';
var $style = document.createElement('style');
$style.type = 'text/css';
$style.innerHTML = `
.app-nav-new-area-x,
.thy-header-self-adaption-x,
.shortcut-tray-content{
z-index: 3000 !important;
}
.dialog-max-lg{
width: 90% !important;
}
.task-table-next{
padding: 16px 16px 46px 16px !important;
}
.shortcut-main{
position: relative;
}
.shortcut-main shortcut-tray-list{
box-shadow: 5px 0 10px 0 rgb(0 0 0 / 20%);
background: #fafafa;
position: fixed;
right: 0;
left: 108px;
bottom: 0;
}
.shortcut-main .shortcut-list-content{
justify-content: center;
}
.toc-section.thy-menu{
padding-bottom: 80px;
}
mission-work-addon-group.thy-layout{
padding-bottom: 50px;
}
mission-work-addon-group .addon-task-table-body.addon-task-table-scroll{
bottom: 50px;
}
/* 左侧 */
.cdk-overlay-connected-position-bounding-box{
bottom: 40px !important;
}
/* 右侧抽屉 */
.view-filter .view-filter-body{
height: auto !important;
}
.view-filter .view-filter-footer{
position: static !important;
}
/* 需求、任务描述 */
.textarea-show-wrapper .textarea-show-footer{
text-align: center;
background: #eee;
padding: 10px;
}
.textarea-show-wrapper .textarea-show-footer a{
padding: 10px 20px;
}
.textarea-show-body{
position: relative;
}
.markdown-body{
visibility: hidden;
}
.markdown-body-new{
visibility: visible;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
background: rgba(255 ,255, 255, 1);
}
.x-link{
width: auto !important;
}
.app-nav-new-area{
padding-top: 35px;
}
.x-menus{
position: absolute;
top: 0;
left: 0;
z-index: 99911;
}
.x-manhour{
position: absolute;
top: 0;
left: 0;
background: rgba(255 ,255, 255, 0.95);
color: #333;
padding: 13px 25px;
text-align: center;
word-break: keep-all;
white-space: nowrap;
box-shadow: 1px 0px 0px 0px #333;
width: 0;
opacity: 0;
transition: all 0.25s;
transform: translateX(-500%);
}
.x-menus:hover .x-manhour{
left: 100%;
width: auto;
opacity: 1;
transform: translateX(0);
display: block;
box-shadow: 1px 0px 5px 1px #ccc;
}
.x-link-open-new-window{
position: relative;
z-index: 99966;
color: #fff;
font-weight: bold;
padding: 13px 0;
display: block;
width: 60px;
text-align: center;
background: #358fe4;
box-shadow: -2px 2px 5px 1px #3e4963;
}
.x-link-open-new-window:hover{
color: #fff;
background: #ff9f73;
background: #4caf50;
background: #ff894e;
}
`;
function init() {
document.createElement('shortcut-tray-list');
document.head.appendChild($style);
}
function xhr(options) {
var defaultOptions = {
method: 'GET',
url: '',
data: null,
success: function(data) {},
error: function(data) {},
};
options = Object.assign({}, defaultOptions, options);
if (options.url) {
var xhr = new XMLHttpRequest();
xhr.open(options.method, options.url, false);
xhr.onerror = function(errorThrow) {
options.error.apply(xhr, [`出错了,${errorThrow}`]);
}
xhr.onload = function() {
var response = xhr.responseText || xhr.response;
if (response) {
try{
response = JSON.parse(response);
if (response.code === 200 && response.data) {
if (typeof(options.success) === 'function') {
options.success.apply(xhr, [response.data || response, response]);
}
} else {
options.error.apply(xhr, [`出错了,${response.message}, 错误码: ${response.code}`]);
}
} catch (ex) {
console.warn('--WARNING-', ex);
}
} else {
options.error.apply(xhr, [`返回数据异常, ${response}`]);
}
}
xhr.send(options.data);
} else {
options.error.apply(xhr, [`出错了,请求地址不能为空`]);
}
}
function getTaskInfo(identifier, callback) {
if (identifier) {
xhr({
url: `/api/mission-vnext/tasks/no/${identifier}?t=${Date.now()}`,
success: function(data) {
data = data.value;
if (data && data.project_id && data._id) {
if (typeof(callback) === 'function') {
callback(data);
}
}
}
});
}
}
var workload_groups = [];
function getWorkloadGroups(callback) {
if (workload_groups && workload_groups.length) {
if (typeof(callback) === 'function') {
callback(workload_groups);
}
} else {
xhr({
url: `api/mission-vnext/work-addons/work-workload/groups?t=${Date.now()}`,
success: function(data) {
data = data.value;
if (data && data.length) {
workload_groups = data;
if (typeof(callback) === 'function') {
callback(data);
}
}
}
});
}
}
function getManHour(callback) {
getWorkloadGroups(function(data) {
data = data.slice(-1);
data = data && data.length ? data[0] : null;
if (data && typeof(data) === 'object' && data._id) {
xhr({
url: `/api/mission-vnext/work/work-workload/${data._id}/workload-day-member-statistics/content?t=${Date.now()}`,
success: function(data) {
data = data.value ? data.value.items : null;
if (data && data.length) {
if (typeof(callback) === 'function') {
callback(data);
}
}
}
});
}
});
}
function syncCurrentHref() {
if ($linkOpenNewWindow) {
$linkOpenNewWindow.href = window.location.href;
}
}
var $manhour;
var $linkOpenNewWindow;
function run(delay) {
delay = delay || 0;
setTimeout(function() {
// 增加新开窗口
syncCurrentHref();
var $xmenus = document.querySelector('.x-menus');
if (!$xmenus ) {
$xmenus = document.createElement('div');
$xmenus.className = 'x-menus';
$xmenus.dataset.manhour = '今日工时:...,昨日工时:...';
$xmenus.innerHTML = `<a target="_blank" rel="opener" class="x-link-open-new-window" title="打开新窗口" href="${window.location.href}">新窗口</a><div class="x-manhour">今日工时:...,昨日工时:...</div>`;
$linkOpenNewWindow = $xmenus.querySelector('.x-link-open-new-window');
var $manhour = $xmenus.querySelector('.x-manhour');
document.body.appendChild($xmenus);
window.addEventListener('hashchange', function(e){
syncCurrentHref();
}, false);
}
// 查询工时
var $avatar = document.querySelector('.thy-avatar .avatar-default');
if ($avatar && $avatar.innerText) {
var userName = $avatar.innerText.trim();
getManHour(function(data) {
data = data.filter(function(item) {
return item[0] === userName
});
if (data.length) {
data = data[0];
var manhour = {
today: data.pop(),
yestoday: data.pop()
};
if ($manhour) {
$manhour.innerText = `今日工时:${manhour.today},昨日工时:${manhour.yestoday}`;
}
}
});
}
// 弹框
var $dialogs = document.querySelectorAll('.thy-dialog-container');
if ($dialogs && $dialogs.length) {
$dialogs.forEach(function($dialog) {
var $identifier = $dialog.querySelector('.task-identifier');
var identifier = $identifier ? ($identifier.innerText || '').trim() : '';
var $dialogNavSecondary = $dialog.querySelector('.thy-icon-nav-secondary');
if ($dialogNavSecondary) {
// 弹框: 在新窗口打开、复制链接
var $linkOpen = $dialogNavSecondary.querySelector('.x-link-open-new');
var $linkCopy = $dialogNavSecondary.querySelector('.x-link-copy');
if (!$linkOpen) {
$linkOpen = document.createElement('a');
$linkOpen.className = 'thy-icon-nav-link x-link x-link-open-new';
$linkOpen.target = '_blank';
$linkOpen.innerText = '新窗口打开';
$linkOpen.title = '在新窗口中打开';
$linkOpen.href = window.location.href;
$dialogNavSecondary.appendChild($linkOpen);
$linkCopy = document.createElement('a');
$linkCopy.className = 'thy-icon-nav-link x-link x-link-copy';
$linkCopy.innerText = '复制链接';
$linkCopy.title = '复制链接';
$linkCopy.href = window.location.href;
$linkCopy.addEventListener('click', function(event) {
event.preventDefault();
event.stopPropagation();
var $textarea = document.createElement('textarea');
$textarea.style.cssText = 'position:fixed;top:0;left:-500px;z-index:9999;';
document.body.appendChild($textarea);
var $projectName = $dialog.querySelector('.project-name');
var projectName = $projectName ? $projectName.innerText : ''
var $taskTitle = $dialog.querySelector('.task-title');
var taskTitle = $taskTitle ? $taskTitle.innerText : '';
var value = `【${projectName}】 ${identifier ? '#'+ identifier : ''} - ${taskTitle}\r\n${this.href}`;
$textarea.value = value;
$textarea.select();
document.execCommand('Copy');
$linkCopy.innerText = '复制成功';
setTimeout(function() {
$linkCopy.innerText = '复制链接';
document.body.removeChild($textarea);
}, 1500);
return false;
}, false);
$dialogNavSecondary.appendChild($linkCopy);
// 当前页面是非需求/任务页面时 查询任务信息
var pattern = /(.*)\/projects\/(\w+)\/tasks\/(\w+)([^\w].*)?/;
if (identifier && !pattern.test(window.location.href)) {
getTaskInfo(identifier, function(data) {
var task_url = `${window.location.origin}/mission/projects/${data.project_id}/tasks/${data._id}`;
$linkCopy.href = $linkOpen.href = task_url;
});
}
}
// 弹框:需求/任务 描述 编辑、复制
if (!$dialog.querySelector('.markdown-body-new')) {
var $markdownBody = $dialog.querySelector('.markdown-body');
if ($markdownBody && $markdownBody.parentNode) {
var $markdownBodyParent = $markdownBody.parentNode;
var $newMarkdownBody = $markdownBody.cloneNode(true);
$newMarkdownBody.classList.add('markdown-body-new');
$markdownBodyParent.appendChild($newMarkdownBody, $markdownBody);
var syncDescHandler = function(event) {
setTimeout(function() {
$newMarkdownBody.innerHTML = $markdownBody.innerHTML;
}, 300);
}
$dialog.addEventListener('mousedown', function(event) {
var $btns = $dialog.querySelectorAll('field-item-textarea-show-edit .thy-btn')
$btns.forEach(function($btn) {
$btn.removeEventListener('mouseup', syncDescHandler, false);
$btn.addEventListener('mouseup', syncDescHandler, false);
});
}, false);
$newMarkdownBody.addEventListener('dblclick', function(event) {
$markdownBodyParent.classList.toggle('textarea-show-body-collapse');
return false
}, false);
}
}
}
})
}
}, delay);
}
// if (!window.location.pathname.startsWith('/api/')) {
if (document.contentType.startsWith('text/html')) {
init();
document.body.addEventListener('mousedown', function(e) {
run(500);
}, false);
run(1500);
}
})();