Greasy Fork

来自缓存

Greasy Fork is available in English.

优化tapd故事墙

1. 在tapd故事墙中添加story预估时间 2. 在故事墙中增加【新需求】与【实现中】的时间统计 3.在故事墙中显示custom_field_one字段值。4.显示时间统计时增加高优先级高亮显示

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         优化tapd故事墙
// @namespace    https://github.com/Dcatfly/Tampermonkey.git
// @version      0.5
// @description  1. 在tapd故事墙中添加story预估时间 2. 在故事墙中增加【新需求】与【实现中】的时间统计 3.在故事墙中显示custom_field_one字段值。4.显示时间统计时增加高优先级高亮显示
// @author       Dcatfly
// @match        https://www.tapd.cn/*/storywalls*
// ==/UserScript==

(function () {
  "use strict";
  const timeCountArr = [
    { label: "新需求", key: "new" },
    { label: "实现中", key: "developing" },
  ];
  const reopenField = "custom_field_one";
  const high_priority = "High";
  const high_priority_color = "#fe5050";
  window.onload = function () {
    const observer = new IntersectionObserver(
      (entries) => {
        entries.forEach(({ target: tr, isIntersecting }) => {
          if (isIntersecting) {
            observer.unobserve(tr);
            const user = tr.querySelector("td.charge > div > ul");
            const stories = tr.querySelectorAll("li[story_id]");
            Promise.all(
              Array.from(stories).map((li) => {
                const storyId = li.getAttribute("story_id");
                const type = li.getAttribute("transition");
                const url = `https://www.tapd.cn/${_workspace_id}/prong/entity_preview/story_preview_data?id=${storyId}&from=iteration_storywall`;
                return fetch(url)
                  .then((rep) => rep.json())
                  .then((data) => {
                    if (data.code === 200) {
                      const title = li.querySelector(".note_head");
                      const effort = data.data.story.effort;
                      const reopen = data.data.story[reopenField];
                      const priority = data.data.story.priority;

                      const span = document.createElement("span");
                      span.append(`${effort}人时`);
                      if (Number(reopen)) {
                        const reopenSpan = document.createElement("span");
                        reopenSpan.style.color = "red";
                        span.append("|");
                        reopenSpan.append(`${reopen}次`);
                        span.append(reopenSpan);
                      }

                      title.style.display = "flex";
                      title.style.justifyContent = "space-between";
                      title.append(span);

                      return {
                        [type]: Number(effort),
                        [`${type}_${priority}`]: Number(effort),
                      };
                    }
                  });
              })
            ).then((times) => {
              const timeCounts = times.reduce((pre, next) => {
                Object.keys(next).forEach((key) => {
                  pre[key] = (pre[key] || 0) + next[key];
                });
                return pre;
              }, {});
              timeCountArr.forEach(({ label, key }) => {
                const timeCount = timeCounts[key];
                if (timeCount) {
                  const highPriorityCount =
                    timeCounts[`${key}_${high_priority}`];
                  const li = document.createElement("li");
                  li.style.overflow = "unset";
                  li.append(`${label}: `);
                  if (highPriorityCount) {
                    const highCountSpan = document.createElement("span");
                    highCountSpan.style.color = high_priority_color;
                    highCountSpan.append(highPriorityCount);
                    li.append(highCountSpan);
                    li.append("/");
                  }
                  li.append(`${timeCount}人时`);

                  user.append(li);
                }
              });
            });
          }
        });
      },
      { rootMargin: "200px 0px 200px 0px" }
    );
    document.querySelectorAll("#resource_table > tbody > tr").forEach((tr) => {
      observer.observe(tr);
    });
  };
})();