diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js
index 914c0ce7c..1ecdba721 100644
--- a/config/webpack.config.dev.js
+++ b/config/webpack.config.dev.js
@@ -206,6 +206,12 @@ module.exports = {
{
loader: require.resolve("sass-loader"),
},
+ {
+ loader: 'sass-resources-loader',
+ options: {
+ resources: ['src/global.scss']
+ }
+ }
],
},
// "file" loader makes sure those assets get served by WebpackDevServer.
diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js
index 4a9d94652..5e3c1fdcc 100644
--- a/config/webpack.config.prod.js
+++ b/config/webpack.config.prod.js
@@ -208,6 +208,12 @@ module.exports = {
{
loader: require.resolve("sass-loader"),
},
+ {
+ loader: 'sass-resources-loader',
+ options: {
+ resources: ['src/global.scss']
+ }
+ }
],
},
// "file" loader makes sure assets end up in the `build` folder.
diff --git a/package-lock.json b/package-lock.json
index e7d231ebc..58f8442e7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14158,6 +14158,27 @@
"object-assign": "^4.1.1"
}
},
+ "react-copy-to-clipboard": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmmirror.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz",
+ "integrity": "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==",
+ "requires": {
+ "copy-to-clipboard": "^3.3.1",
+ "prop-types": "^15.8.1"
+ },
+ "dependencies": {
+ "prop-types": {
+ "version": "15.8.1",
+ "resolved": "https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+ "requires": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.13.1"
+ }
+ }
+ }
+ },
"react-countup": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/react-countup/-/react-countup-6.1.0.tgz",
@@ -15874,7 +15895,7 @@
},
"sass-loader": {
"version": "7.3.1",
- "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.3.1.tgz",
+ "resolved": "https://registry.npmmirror.com/sass-loader/-/sass-loader-7.3.1.tgz",
"integrity": "sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA==",
"requires": {
"clone-deep": "^4.0.1",
@@ -15890,9 +15911,85 @@
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
},
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ "version": "6.3.1",
+ "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
+ }
+ }
+ },
+ "sass-resources-loader": {
+ "version": "2.2.5",
+ "resolved": "https://registry.npmmirror.com/sass-resources-loader/-/sass-resources-loader-2.2.5.tgz",
+ "integrity": "sha512-po8rfETH9cOQACWxubT/1CCu77KjxwRtCDm6QAXZH99aUHBydwSoxdIjC40SGp/dcS/FkSNJl0j1VEojGZqlvQ==",
+ "requires": {
+ "async": "^3.2.3",
+ "chalk": "^4.1.0",
+ "glob": "^7.1.6",
+ "loader-utils": "^2.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "async": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmmirror.com/async/-/async-3.2.4.tgz",
+ "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ=="
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+ },
+ "json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="
+ },
+ "loader-utils": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.4.tgz",
+ "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
+ "requires": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^3.0.0",
+ "json5": "^2.1.2"
+ }
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
}
}
},
diff --git a/package.json b/package.json
index 3b421e973..005b45bf2 100644
--- a/package.json
+++ b/package.json
@@ -84,6 +84,7 @@
"react-color": "^2.18.0",
"react-content-loader": "^3.1.1",
"react-cookies": "^0.1.1",
+ "react-copy-to-clipboard": "^5.1.0",
"react-countup": "^6.1.0",
"react-cropper": "^2.1.8",
"react-datepicker": "^2.14.1",
@@ -105,7 +106,8 @@
"redux": "^4.0.5",
"redux-thunk": "2.3.0",
"rsuite": "^4.3.4",
- "sass-loader": "7.3.1",
+ "sass-loader": "^7.3.1",
+ "sass-resources-loader": "^2.2.5",
"save-dev": "0.0.1-security",
"scroll-into-view": "^1.14.2",
"showdown": "^1.9.1",
diff --git a/public/css/edu-purge.css b/public/css/edu-purge.css
index 4c467e53f..0f26bfe99 100644
--- a/public/css/edu-purge.css
+++ b/public/css/edu-purge.css
@@ -2466,7 +2466,7 @@ a.hoverLine:hover{
}
a:hover{
- color: #466AFF !important;
+ color: #466AFF;
}
.color-grey-98 {
diff --git a/public/css/iconfont.css b/public/css/iconfont.css
index 39ebe18fe..d63d65407 100644
--- a/public/css/iconfont.css
+++ b/public/css/iconfont.css
@@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 2340181 */
- src: url('iconfont.woff2?t=1653550272457') format('woff2'),
- url('iconfont.woff?t=1653550272457') format('woff'),
- url('iconfont.ttf?t=1653550272457') format('truetype');
+ src: url('iconfont.woff2?t=1693564942420') format('woff2'),
+ url('iconfont.woff?t=1693564942420') format('woff'),
+ url('iconfont.ttf?t=1693564942420') format('truetype');
}
.iconfont {
@@ -13,6 +13,230 @@
-moz-osx-font-smoothing: grayscale;
}
+.icon-liulan1:before {
+ content: "\e96e";
+}
+
+.icon-a-zu2044:before {
+ content: "\e96d";
+}
+
+.icon-cuo:before {
+ content: "\e96c";
+}
+
+.icon-dui:before {
+ content: "\e96b";
+}
+
+.icon-zanting:before {
+ content: "\e96a";
+}
+
+.icon-cangkuyuyanicon:before {
+ content: "\e962";
+}
+
+.icon-dongtaiicon1:before {
+ content: "\e963";
+}
+
+.icon-jingxuanxiangmu:before {
+ content: "\e964";
+}
+
+.icon-zuzhichengyuan1:before {
+ content: "\e965";
+}
+
+.icon-zuzhijieshao:before {
+ content: "\e966";
+}
+
+.icon-zuzhituandui:before {
+ content: "\e967";
+}
+
+.icon-shezhi6:before {
+ content: "\e968";
+}
+
+.icon-zidingyi:before {
+ content: "\e969";
+}
+
+.icon-a-zu37:before {
+ content: "\e961";
+}
+
+.icon-guanzhuicon:before {
+ content: "\e95b";
+}
+
+.icon-yidianzan_icon:before {
+ content: "\e95c";
+}
+
+.icon-morenfuke_icon1:before {
+ content: "\e95d";
+}
+
+.icon-yiguanzhuicon:before {
+ content: "\e95e";
+}
+
+.icon-yifuke_icon:before {
+ content: "\e95f";
+}
+
+.icon-xingzhuang:before {
+ content: "\e960";
+}
+
+.icon-kaiqi:before {
+ content: "\e95a";
+}
+
+.icon-a-31shijian:before {
+ content: "\e944";
+}
+
+.icon-chengyuan2:before {
+ content: "\e945";
+}
+
+.icon-a-bianji12:before {
+ content: "\e946";
+}
+
+.icon-fuzhi-shanchu:before {
+ content: "\e947";
+}
+
+.icon-chuangjianqianbao:before {
+ content: "\e948";
+}
+
+.icon-biaoji2:before {
+ content: "\e949";
+}
+
+.icon-lichengbeiicon1:before {
+ content: "\e94a";
+}
+
+.icon-biaoji:before {
+ content: "\e94b";
+}
+
+.icon-fenzhi3:before {
+ content: "\e94c";
+}
+
+.icon-riqi:before {
+ content: "\e94d";
+}
+
+.icon-ruliriqixiao:before {
+ content: "\e94e";
+}
+
+.icon-shanchu8:before {
+ content: "\e94f";
+}
+
+.icon-sousuo6:before {
+ content: "\e950";
+}
+
+.icon-quanxian:before {
+ content: "\e951";
+}
+
+.icon-lichengbeiicon2:before {
+ content: "\e952";
+}
+
+.icon-xinjian3:before {
+ content: "\e953";
+}
+
+.icon-xuanzhong4:before {
+ content: "\e954";
+}
+
+.icon-youxian:before {
+ content: "\e955";
+}
+
+.icon-a-xiaoxi1:before {
+ content: "\e956";
+}
+
+.icon-yixiuicon2:before {
+ content: "\e957";
+}
+
+.icon-xiugaibaobiaomoban:before {
+ content: "\e958";
+}
+
+.icon-a-zu1614:before {
+ content: "\e959";
+}
+
+.icon-BOTpeizhi:before {
+ content: "\e942";
+}
+
+.icon-kaifabot:before {
+ content: "\e943";
+}
+
+.icon-jiqiren:before {
+ content: "\e940";
+}
+
+.icon-a-jiqirenzhineng-02:before {
+ content: "\e941";
+}
+
+.icon-yuyue-lishi-shijian:before {
+ content: "\e93f";
+}
+
+.icon-a-duobianxing1:before {
+ content: "\e93c";
+}
+
+.icon-a-duobianxing2:before {
+ content: "\e93d";
+}
+
+.icon-sousuo5:before {
+ content: "\e93e";
+}
+
+.icon-baogaoppt:before {
+ content: "\e93b";
+}
+
+.icon-gailan2:before {
+ content: "\e93a";
+}
+
+.icon-bianji7:before {
+ content: "\e939";
+}
+
+.icon-ROBOT:before {
+ content: "\e937";
+}
+
+.icon-a-zu1404:before {
+ content: "\e938";
+}
+
.icon-tuichuicon:before {
content: "\e936";
}
diff --git a/public/css/iconfont.js b/public/css/iconfont.js
index 0b03f5640..ae98dc07b 100644
--- a/public/css/iconfont.js
+++ b/public/css/iconfont.js
@@ -1 +1 @@
-!function(a){var l,c,h,i,o,z='',t=(t=document.getElementsByTagName("script"))[t.length-1].getAttribute("data-injectcss"),p=function(a,l){l.parentNode.insertBefore(a,l)};if(t&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}function v(){o||(o=!0,h())}function m(){try{i.documentElement.doScroll("left")}catch(a){return void setTimeout(m,50)}v()}l=function(){var a,l=document.createElement("div");l.innerHTML=z,z=null,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(a=document.body).firstChild?p(l,a.firstChild):a.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(l,0):(c=function(){document.removeEventListener("DOMContentLoaded",c,!1),l()},document.addEventListener("DOMContentLoaded",c,!1)):document.attachEvent&&(h=l,i=a.document,o=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,v())})}(window);
\ No newline at end of file
+window._iconfont_svg_string_2340181='',function(c){var a=(a=document.getElementsByTagName("script"))[a.length-1],l=a.getAttribute("data-injectcss"),a=a.getAttribute("data-disable-injectsvg");if(!a){var h,i,o,z,t,p=function(a,l){l.parentNode.insertBefore(a,l)};if(l&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}h=function(){var a,l=document.createElement("div");l.innerHTML=c._iconfont_svg_string_2340181,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(a=document.body).firstChild?p(l,a.firstChild):a.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),h()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(o=h,z=c.document,t=!1,m(),z.onreadystatechange=function(){"complete"==z.readyState&&(z.onreadystatechange=null,v())})}function v(){t||(t=!0,o())}function m(){try{z.documentElement.doScroll("left")}catch(a){return void setTimeout(m,50)}v()}}(window);
\ No newline at end of file
diff --git a/public/css/iconfont.json b/public/css/iconfont.json
index 9dc3ea5e5..be2bdae45 100644
--- a/public/css/iconfont.json
+++ b/public/css/iconfont.json
@@ -5,6 +5,398 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
+ {
+ "icon_id": "36898536",
+ "name": "浏览",
+ "font_class": "liulan1",
+ "unicode": "e96e",
+ "unicode_decimal": 59758
+ },
+ {
+ "icon_id": "36020261",
+ "name": "组 2044",
+ "font_class": "a-zu2044",
+ "unicode": "e96d",
+ "unicode_decimal": 59757
+ },
+ {
+ "icon_id": "5287658",
+ "name": "错",
+ "font_class": "cuo",
+ "unicode": "e96c",
+ "unicode_decimal": 59756
+ },
+ {
+ "icon_id": "8802648",
+ "name": "对",
+ "font_class": "dui",
+ "unicode": "e96b",
+ "unicode_decimal": 59755
+ },
+ {
+ "icon_id": "887857",
+ "name": "暂停",
+ "font_class": "zanting",
+ "unicode": "e96a",
+ "unicode_decimal": 59754
+ },
+ {
+ "icon_id": "34965902",
+ "name": "仓库语言icon",
+ "font_class": "cangkuyuyanicon",
+ "unicode": "e962",
+ "unicode_decimal": 59746
+ },
+ {
+ "icon_id": "34965903",
+ "name": "动态icon",
+ "font_class": "dongtaiicon1",
+ "unicode": "e963",
+ "unicode_decimal": 59747
+ },
+ {
+ "icon_id": "34965904",
+ "name": "精选项目",
+ "font_class": "jingxuanxiangmu",
+ "unicode": "e964",
+ "unicode_decimal": 59748
+ },
+ {
+ "icon_id": "34965905",
+ "name": "组织成员",
+ "font_class": "zuzhichengyuan1",
+ "unicode": "e965",
+ "unicode_decimal": 59749
+ },
+ {
+ "icon_id": "34965906",
+ "name": "组织介绍",
+ "font_class": "zuzhijieshao",
+ "unicode": "e966",
+ "unicode_decimal": 59750
+ },
+ {
+ "icon_id": "34965907",
+ "name": "组织团队",
+ "font_class": "zuzhituandui",
+ "unicode": "e967",
+ "unicode_decimal": 59751
+ },
+ {
+ "icon_id": "34965908",
+ "name": "设置",
+ "font_class": "shezhi6",
+ "unicode": "e968",
+ "unicode_decimal": 59752
+ },
+ {
+ "icon_id": "34965909",
+ "name": "自定义",
+ "font_class": "zidingyi",
+ "unicode": "e969",
+ "unicode_decimal": 59753
+ },
+ {
+ "icon_id": "34875122",
+ "name": "组 37",
+ "font_class": "a-zu37",
+ "unicode": "e961",
+ "unicode_decimal": 59745
+ },
+ {
+ "icon_id": "34819652",
+ "name": "关注icon",
+ "font_class": "guanzhuicon",
+ "unicode": "e95b",
+ "unicode_decimal": 59739
+ },
+ {
+ "icon_id": "34819653",
+ "name": "已点赞_icon",
+ "font_class": "yidianzan_icon",
+ "unicode": "e95c",
+ "unicode_decimal": 59740
+ },
+ {
+ "icon_id": "34819654",
+ "name": "默认复刻_icon",
+ "font_class": "morenfuke_icon1",
+ "unicode": "e95d",
+ "unicode_decimal": 59741
+ },
+ {
+ "icon_id": "34819655",
+ "name": "已关注icon",
+ "font_class": "yiguanzhuicon",
+ "unicode": "e95e",
+ "unicode_decimal": 59742
+ },
+ {
+ "icon_id": "34819656",
+ "name": "已复刻_icon",
+ "font_class": "yifuke_icon",
+ "unicode": "e95f",
+ "unicode_decimal": 59743
+ },
+ {
+ "icon_id": "34820092",
+ "name": "形状",
+ "font_class": "xingzhuang",
+ "unicode": "e960",
+ "unicode_decimal": 59744
+ },
+ {
+ "icon_id": "34197190",
+ "name": "开启",
+ "font_class": "kaiqi",
+ "unicode": "e95a",
+ "unicode_decimal": 59738
+ },
+ {
+ "icon_id": "33949760",
+ "name": "3.1 时间",
+ "font_class": "a-31shijian",
+ "unicode": "e944",
+ "unicode_decimal": 59716
+ },
+ {
+ "icon_id": "33949761",
+ "name": "成员",
+ "font_class": "chengyuan2",
+ "unicode": "e945",
+ "unicode_decimal": 59717
+ },
+ {
+ "icon_id": "33949762",
+ "name": "编辑 (1)",
+ "font_class": "a-bianji12",
+ "unicode": "e946",
+ "unicode_decimal": 59718
+ },
+ {
+ "icon_id": "33949763",
+ "name": "复制-删除",
+ "font_class": "fuzhi-shanchu",
+ "unicode": "e947",
+ "unicode_decimal": 59719
+ },
+ {
+ "icon_id": "33949764",
+ "name": "创建钱包",
+ "font_class": "chuangjianqianbao",
+ "unicode": "e948",
+ "unicode_decimal": 59720
+ },
+ {
+ "icon_id": "33949765",
+ "name": "标记2",
+ "font_class": "biaoji2",
+ "unicode": "e949",
+ "unicode_decimal": 59721
+ },
+ {
+ "icon_id": "33949766",
+ "name": "里程碑icon",
+ "font_class": "lichengbeiicon1",
+ "unicode": "e94a",
+ "unicode_decimal": 59722
+ },
+ {
+ "icon_id": "33949767",
+ "name": "标记",
+ "font_class": "biaoji",
+ "unicode": "e94b",
+ "unicode_decimal": 59723
+ },
+ {
+ "icon_id": "33949768",
+ "name": "分支",
+ "font_class": "fenzhi3",
+ "unicode": "e94c",
+ "unicode_decimal": 59724
+ },
+ {
+ "icon_id": "33949769",
+ "name": "日期",
+ "font_class": "riqi",
+ "unicode": "e94d",
+ "unicode_decimal": 59725
+ },
+ {
+ "icon_id": "33949770",
+ "name": "入离日期小",
+ "font_class": "ruliriqixiao",
+ "unicode": "e94e",
+ "unicode_decimal": 59726
+ },
+ {
+ "icon_id": "33949771",
+ "name": "删除",
+ "font_class": "shanchu8",
+ "unicode": "e94f",
+ "unicode_decimal": 59727
+ },
+ {
+ "icon_id": "33949772",
+ "name": "搜索",
+ "font_class": "sousuo6",
+ "unicode": "e950",
+ "unicode_decimal": 59728
+ },
+ {
+ "icon_id": "33949773",
+ "name": "权限",
+ "font_class": "quanxian",
+ "unicode": "e951",
+ "unicode_decimal": 59729
+ },
+ {
+ "icon_id": "33949774",
+ "name": "里程碑icon2",
+ "font_class": "lichengbeiicon2",
+ "unicode": "e952",
+ "unicode_decimal": 59730
+ },
+ {
+ "icon_id": "33949775",
+ "name": "新建",
+ "font_class": "xinjian3",
+ "unicode": "e953",
+ "unicode_decimal": 59731
+ },
+ {
+ "icon_id": "33949776",
+ "name": "选中",
+ "font_class": "xuanzhong4",
+ "unicode": "e954",
+ "unicode_decimal": 59732
+ },
+ {
+ "icon_id": "33949777",
+ "name": "优先",
+ "font_class": "youxian",
+ "unicode": "e955",
+ "unicode_decimal": 59733
+ },
+ {
+ "icon_id": "33949778",
+ "name": "消息 (1)",
+ "font_class": "a-xiaoxi1",
+ "unicode": "e956",
+ "unicode_decimal": 59734
+ },
+ {
+ "icon_id": "33949779",
+ "name": "易修icon",
+ "font_class": "yixiuicon2",
+ "unicode": "e957",
+ "unicode_decimal": 59735
+ },
+ {
+ "icon_id": "33949780",
+ "name": "修改报表模版",
+ "font_class": "xiugaibaobiaomoban",
+ "unicode": "e958",
+ "unicode_decimal": 59736
+ },
+ {
+ "icon_id": "33949781",
+ "name": "组 1614",
+ "font_class": "a-zu1614",
+ "unicode": "e959",
+ "unicode_decimal": 59737
+ },
+ {
+ "icon_id": "33731642",
+ "name": "BOT配置",
+ "font_class": "BOTpeizhi",
+ "unicode": "e942",
+ "unicode_decimal": 59714
+ },
+ {
+ "icon_id": "33731643",
+ "name": "开发bot",
+ "font_class": "kaifabot",
+ "unicode": "e943",
+ "unicode_decimal": 59715
+ },
+ {
+ "icon_id": "19591156",
+ "name": "机器人",
+ "font_class": "jiqiren",
+ "unicode": "e940",
+ "unicode_decimal": 59712
+ },
+ {
+ "icon_id": "25885545",
+ "name": "机器人、智能-02",
+ "font_class": "a-jiqirenzhineng-02",
+ "unicode": "e941",
+ "unicode_decimal": 59713
+ },
+ {
+ "icon_id": "6978097",
+ "name": "预约-历史-时间",
+ "font_class": "yuyue-lishi-shijian",
+ "unicode": "e93f",
+ "unicode_decimal": 59711
+ },
+ {
+ "icon_id": "31659662",
+ "name": "多边形 1",
+ "font_class": "a-duobianxing1",
+ "unicode": "e93c",
+ "unicode_decimal": 59708
+ },
+ {
+ "icon_id": "31659664",
+ "name": "多边形 2",
+ "font_class": "a-duobianxing2",
+ "unicode": "e93d",
+ "unicode_decimal": 59709
+ },
+ {
+ "icon_id": "31659665",
+ "name": "搜索",
+ "font_class": "sousuo5",
+ "unicode": "e93e",
+ "unicode_decimal": 59710
+ },
+ {
+ "icon_id": "31424249",
+ "name": "报告ppt",
+ "font_class": "baogaoppt",
+ "unicode": "e93b",
+ "unicode_decimal": 59707
+ },
+ {
+ "icon_id": "31318120",
+ "name": "概览",
+ "font_class": "gailan2",
+ "unicode": "e93a",
+ "unicode_decimal": 59706
+ },
+ {
+ "icon_id": "31275425",
+ "name": "编辑",
+ "font_class": "bianji7",
+ "unicode": "e939",
+ "unicode_decimal": 59705
+ },
+ {
+ "icon_id": "30382389",
+ "name": "ROBOT",
+ "font_class": "ROBOT",
+ "unicode": "e937",
+ "unicode_decimal": 59703
+ },
+ {
+ "icon_id": "30382697",
+ "name": "组 1404",
+ "font_class": "a-zu1404",
+ "unicode": "e938",
+ "unicode_decimal": 59704
+ },
{
"icon_id": "29934961",
"name": "退出icon",
diff --git a/public/css/iconfont.ttf b/public/css/iconfont.ttf
index 5ea5e9206..b94d6dcee 100644
Binary files a/public/css/iconfont.ttf and b/public/css/iconfont.ttf differ
diff --git a/public/css/iconfont.woff b/public/css/iconfont.woff
index 6b8a4f2ee..cbcd0bb08 100644
Binary files a/public/css/iconfont.woff and b/public/css/iconfont.woff differ
diff --git a/public/css/iconfont.woff2 b/public/css/iconfont.woff2
index ce5758a2e..3b6d1ad48 100644
Binary files a/public/css/iconfont.woff2 and b/public/css/iconfont.woff2 differ
diff --git a/src/AppConfig.js b/src/AppConfig.js
index 1a241cead..190f9c411 100644
--- a/src/AppConfig.js
+++ b/src/AppConfig.js
@@ -32,7 +32,7 @@ export function initAxiosInterceptors(props) {
// 判断网络是否连接
initOnlineOfflineListener();
- var proxy = "https://testforgeplus.trustie.net";
+ var proxy = "https://testforgeplus.trustie.net/";
//响应前的设置
axios.interceptors.request.use(
config => {
diff --git a/src/Loading.js b/src/Loading.js
index 8175b7df8..fa9b2d155 100644
--- a/src/Loading.js
+++ b/src/Loading.js
@@ -2,14 +2,9 @@ import React, { Component } from 'react';
import { Spin } from 'antd';
class Loading extends Component {
- componentDidUpdate(prevProps, prevState) {
- if (!prevProps.error && this.props.error) {
- console.log(this.props.error)
- }
- }
render() {
- return ""
+ return
}
}
diff --git a/src/common/UrlTool.js b/src/common/UrlTool.js
index ee104fc81..0e092b7ad 100644
--- a/src/common/UrlTool.js
+++ b/src/common/UrlTool.js
@@ -10,14 +10,14 @@ export const TEST_HOST = window.location.hostname ==="testforgeplus.educoder.net
export function getImageUrl(path) {
const local = 'https://testforgeplus.educoder.net';
- const normal = TEST_HOST ? "https://new-testali-cdn.educoder.net/images" : 'https://ali-cdn.educoder.net/images';
- const normalend = TEST_HOST ? 'https://new-testali-cdn.educoder.net' :'https://ali-cdn.educoder.net';
+ // const normal = TEST_HOST ? "https://new-testali-cdn.educoder.net/images" : 'https://ali-cdn.educoder.net/images';
+ const normalend = TEST_HOST ? 'https://testforgeplus.educoder.net/' :'https://ali-cdn.educoder.net';
if (isDev) {
return `${local}/${path}`;
}
if(path.substr(0, 7) !== "/system"){
if(path.substr(0, 7) !== "/images"){
- return `${normal}${path}`;
+ return `/${path}`;
}else{
return `${normalend}${path}`;
}
diff --git a/src/forge/Component/AddMember.jsx b/src/forge/Component/AddMember.jsx
index 426088edc..097dc2080 100644
--- a/src/forge/Component/AddMember.jsx
+++ b/src/forge/Component/AddMember.jsx
@@ -140,7 +140,7 @@ import debounce from 'lodash/debounce';
import { Select, Spin , Button , Icon } from 'antd';
import axios from 'axios';
import { getImageUrl } from 'educoder';
-function DebounceSelect({ fetchOptions, debounceTimeout = 600, ...props }) {
+function DebounceSelect({ fetchOptions, debounceTimeout = 600,login, ...props }) {
const [fetching, setFetching] = useState(false);
const [options, setOptions] = useState([]);
const fetchRef = useRef(0);
@@ -182,7 +182,7 @@ function DebounceSelect({ fetchOptions, debounceTimeout = 600, ...props }) {
options && options.length >0 &&
options.map((i)=>{
return(
-
+
{/*
{
{
diff --git a/src/forge/Component/ProfileModal/Profile.jsx b/src/forge/Component/ProfileModal/Profile.jsx
index 2ae769ebe..5df2b39de 100644
--- a/src/forge/Component/ProfileModal/Profile.jsx
+++ b/src/forge/Component/ProfileModal/Profile.jsx
@@ -14,7 +14,7 @@ function Profile({
function checkProfile() {
if(checkIfLogin()){
- if(!current_user.has_gitea_user || (current_user.has_gitea_user && !current_user.is_sync_pwd)){
+ if(!current_user.has_gitea_user){
setGiteaVisible(true);
}else{
if(!completeProfile){
diff --git a/src/forge/Head/Header.js b/src/forge/Head/Header.js
index d09cad7d4..814c7b4b3 100644
--- a/src/forge/Head/Header.js
+++ b/src/forge/Head/Header.js
@@ -63,7 +63,7 @@ class NewHeader extends Component {
}
getEducoderSetting=()=>{
- const url = `https://data.educoder.net/api/setting.json`;
+ const url = `/setting.json`;
axios.get(url).then(result=>{
if(result && result.data){
this.setState({
diff --git a/src/forge/Issues/Component/addTagsBox.jsx b/src/forge/Issues/Component/addTagsBox.jsx
new file mode 100644
index 000000000..6b0c72108
--- /dev/null
+++ b/src/forge/Issues/Component/addTagsBox.jsx
@@ -0,0 +1,65 @@
+import React , { useState , useEffect } from 'react';
+import { Form , Input, Button } from 'antd';
+import ColorCard from './colorCard';
+import axios from 'axios';
+
+function AddTagsBox({onSuccess , form ,owner , projectsId,onCancel}){
+ const { getFieldDecorator , getFieldsValue , validateFields } = form;
+ const [ colors , setColors ] = useState(undefined);
+ const [ defaultColor , setDefaultColor ]= useState(undefined);
+
+ useEffect(()=>{
+ const c = Math.random().toString(16).substr(-6);
+ c && setDefaultColor(`#${c}`);
+ },[])
+
+ function saveFunc(){
+ validateFields((error,values)=>{
+ if(!error){
+ const { desc , name } = getFieldsValue();
+ const url = `/v1/${owner}/${projectsId}/issue_tags`;
+ axios.post(url,{
+ name,description:desc,color:colors || defaultColor
+ }).then(result=>{
+ result && onSuccess();
+ }).catch(error=>{})
+ }
+ })
+ }
+
+ function getColor(colors){
+ setColors(colors);
+ }
+
+ return(
+
+ {getFieldDecorator('desc',{rules:[],
+ validateTrigger:"onInput",
+ })()}
+
+
+
+
+
+
+ )
+}
+export default Form.create({ name: 'Bind' })(AddTagsBox);
\ No newline at end of file
diff --git a/src/forge/Issues/Component/allMenus.jsx b/src/forge/Issues/Component/allMenus.jsx
new file mode 100644
index 000000000..3a80aebb6
--- /dev/null
+++ b/src/forge/Issues/Component/allMenus.jsx
@@ -0,0 +1,255 @@
+import React,{ useState , useEffect , forwardRef ,useImperativeHandle , useRef } from 'react';
+import Menus from './menus';
+import axios from 'axios';
+
+const array =[
+ {id:1,name:"最新创建"},
+ {id:2,name:"最早创建"},
+ {id:3,name:"最新更新"},
+ {id:4,name:"最早更新"},
+ {id:5,name:"高优先级"},
+ {id:6,name:"低优先级"},
+ {id:7,name:"高悬赏金额"},
+ {id:8,name:"低悬赏金额"}
+]
+const array1 =[
+ {id:1,name:"最新创建"},
+ {id:2,name:"最早创建"},
+ {id:3,name:"最新更新"},
+ {id:4,name:"最早更新"},
+ {id:5,name:"高优先级"},
+ {id:6,name:"低优先级"},
+]
+
+function AllMenus({owner,projectsId,chooseFunc,update,defaultNames,defaultIds,open_blockchain},ref){
+ // 列表右侧所有筛选项的值
+ const [ authorList , setAuthorList ] = useState(undefined);
+ const [ author , setAuthor ] = useState(undefined);
+ const [ tagList , setTagList ] = useState(undefined);
+ const [ tag , setTag ] = useState(undefined);
+ const [ cases , setCases ] = useState(undefined);
+ const [ millstoneList , setMillstoneList ] = useState(undefined);
+ const [ millstone , setMillstone ] = useState(undefined);
+ const [ chargeList , setChargeList ] = useState(undefined);
+ const [ caseList , setCaseList ] = useState(undefined);
+ const [ charge , setCharge ] = useState(undefined);
+ const [ statusList , setStatusList ] = useState(undefined);
+ const [ prioritiesList , setPrioritiesList ] = useState(undefined);
+ const [ ids , setIds ] = useState({author_id:undefined,issue_priorities_id:undefined,issue_tag_ids:undefined,milestone_id:undefined,sort_by:undefined,status_id:undefined,assigner_id:undefined,test_case:undefined});
+ const [ names , setNames ] = useState({author_name:undefined,issue_priorities_name:undefined,issue_tag_name:undefined,milestone_name:undefined,sortby_name:undefined,status_name:undefined,assigner_name:undefined,test_case:undefined});
+
+ useEffect(()=>{
+ if(defaultNames){
+ setNames(defaultNames);
+ }
+ },[defaultNames])
+
+ useEffect(()=>{
+ if(defaultIds){
+ setIds(defaultIds);
+ }
+ },[defaultIds])
+
+ useImperativeHandle(ref, () => ({
+ clearChoose: () => {
+ // 父组件按钮:清除筛选条件,将Ids\names里的字段全部改为undefined
+ setIds({author_id:undefined,issue_tag_ids:undefined,issue_priorities_id:undefined,milestone_id:undefined,sort_by:undefined,status_id:undefined,assigner_id:undefined});
+ setNames({author_name:undefined,issue_tag_name:undefined,issue_priorities_name:undefined,milestone_name:undefined,sortby_name:undefined,status_name:undefined,assigner_name:undefined});
+ }
+ }))
+ // 获取发布人列表
+ useEffect(()=>{
+ getSendPerson();
+ },[author])
+
+ function getSendPerson(){
+ const url = `/v1/${owner}/${projectsId}/issue_authors`;
+ axios.get(url,{params:{keyword:author,only_name:true}}).then(result=>{
+ if(result && result.data){
+ setAuthorList(result.data.authors);
+ }
+ })
+ }
+ // 获取标记列表
+ useEffect(()=>{
+ getSign();
+ },[tag])
+ function getSign(){
+ const url = `/v1/${owner}/${projectsId}/issue_tags`;
+ axios.get(url,{params:{keyword:tag,only_name:true}}).then(result=>{
+ if(result && result.data){
+ setTagList(result.data.issue_tags);
+ }
+ })
+ }
+ // 获取测试用例
+ useEffect(()=>{
+ getCase();
+ },[cases])
+
+ function getCase(){
+ const url = `/v1/${owner}/${projectsId}/issues/test_cases`;
+ axios.get(url,{
+ params:{
+ keyword:cases
+ }
+ }).then(result=>{
+ if(result && result.data){
+ let menu = result.data.data;
+ if(menu && menu.length>0){
+ const l = menu.map(i=>{
+ return {name:i.test_case,id:i.test_case}
+ })
+ setCaseList(l);
+ }else{
+ setCaseList([]);
+ }
+ }
+ })
+ }
+ // 获取里程碑列表
+ useEffect(()=>{
+ getMillstone();
+ },[millstone])
+
+ function getMillstone(){
+ const url = `/v1/${owner}/${projectsId}/milestones`;
+ axios.get(url,{params:{keyword:millstone,only_name:true}}).then(result=>{
+ if(result && result.data){
+ setMillstoneList(result.data.milestones);
+ }
+ })
+ }
+
+ // 获取负责人列表
+ useEffect(()=>{
+ getCharge();
+ },[charge,update])
+
+ function getCharge(){
+ if(update){
+ const url = `/v1/${owner}/${projectsId}/collaborators`;
+ axios.get(url,{params:{keyword:charge,only_name:true}}).then(result=>{
+ if(result && result.data){
+ setChargeList(result.data.collaborators);
+ }
+ })
+ }else{
+ const url = `/v1/${owner}/${projectsId}/issue_assigners`;
+ axios.get(url,{params:{keyword:charge,only_name:true}}).then(result=>{
+ if(result && result.data){
+ setChargeList(result.data.assigners);
+ }
+ })
+ }
+ }
+ // 获取优先级列表
+ useEffect(()=>{
+ getPriorities();
+ },[])
+
+ function getPriorities(){
+ const url = `/v1/${owner}/${projectsId}/issue_priorities`;
+ axios.get(url).then(result=>{
+ if(result && result.data){
+ setPrioritiesList(result.data.priorities);
+ }
+ })
+ }
+ // 获取状态列表
+ useEffect(()=>{
+ getStatus();
+ },[])
+
+ function getStatus(){
+ const url = `/v1/${owner}/${projectsId}/issue_statues`;
+ axios.get(url).then(result=>{
+ if(result && result.data){
+ setStatusList(result.data.statues);
+ }
+ })
+ }
+
+ function choose(id,name){
+ let copy = {...ids,author_id:id && id.length>0 ? id.join(","):undefined};
+ let copyname = { ...names,author_name:name};
+ setIds(copy);setNames(copyname);
+ chooseFunc(copy,copyname);
+ }
+
+ return(
+
+ { !update && setAuthor(value)}
+ chooseFunc={(id,name)=>choose(id,name,'author_name')}
+ />
+ }
+ {update && {let copy = {...ids,issue_priorities_id:id && id.length>0 ? id.join(","):undefined};let copyname = { ...names,issue_priorities_name:name};setNames(copyname);setIds(copy);chooseFunc(copy,copyname)}}
+ />
+ }
+ setTag(value)}
+ chooseFunc={(id,name)=>{let copy = {...ids,issue_tag_ids:id && id.length>0 ? id.join(","):undefined};let copyname = { ...names,issue_tag_name:name};setNames(copyname);setIds(copy);chooseFunc(copy,copyname)}}
+ />
+ setMillstone(value)}
+ chooseFunc={(id,name)=>{let copy = {...ids,milestone_id:id && id.length>0 ? id.join(","):undefined};let copyname = { ...names,milestone_name:name};setNames(copyname);setIds(copy);chooseFunc(copy,copyname)}}
+ />
+ setCases(value)}
+ double={false}
+ chooseFunc={(id,name)=>{let copy = {...ids,test_case:name};let copyname = { ...names,test_case:name};setNames(copyname);setIds(copy);chooseFunc(copy,copyname)}}
+ />
+ setCharge(value)}
+ double={update ? true : false }
+ chooseFunc={(id,name)=>{let copy = {...ids,assigner_id:id && id.length>0 ? id.join(","):undefined};let copyname = { ...names,assigner_name:name};setNames(copyname);setIds(copy);chooseFunc(copy,copyname)}}
+ />
+ {let copy = {...ids,status_id:id && id.length>0 ? id.join(","):undefined};let copyname = { ...names,status_name:name};setNames(copyname);setIds(copy);chooseFunc(copy,copyname)}}
+ />
+ { !update && {let copy = {...ids,sort_by:id && id.length>0 ? id.join(","):undefined};let copyname = { ...names,sortby_name:name};setNames(copyname);setIds(copy);chooseFunc(copy,copyname)}}
+ />
+ }
+
+ )
+}
+export default forwardRef(AllMenus);
\ No newline at end of file
diff --git a/src/forge/Issues/Component/caseDrop.jsx b/src/forge/Issues/Component/caseDrop.jsx
new file mode 100644
index 000000000..c88175d57
--- /dev/null
+++ b/src/forge/Issues/Component/caseDrop.jsx
@@ -0,0 +1,65 @@
+import React , { useEffect , useState } from 'react';
+import { AutoComplete } from 'antd';
+import axios from 'axios';
+import '../index.scss';
+
+const { Option } = AutoComplete;
+
+function CaseDrop({
+ name , owner , projectsId , changeValue , value , onBlur
+}){
+ const [ filterUnitList , setFilterUnitList ] = useState([]);
+ const [ v , setV ] = useState(value);
+
+ useEffect(()=>{
+ getCaseList(value);
+ },[])
+
+ useEffect(()=>{
+ setV(value);
+ },[value])
+
+ useEffect(()=>{
+ changeValue(v);
+ getCaseList(v);
+ },[v])
+
+ async function getCaseList(value){
+ setV(value);
+ const url = `/v1/${owner}/${projectsId}/issues/test_cases`;
+ await axios.get(url,{
+ params:{
+ keyword:value
+ }
+ }).then(response=>{
+ if(response && response.data){
+ setFilterUnitList(response.data.data);
+ }
+ }).catch(error=>{})
+ }
+
+ return(
+
+ {name}
+ {if(onBlur){onBlur(v)}}}
+ >
+ {
+ filterUnitList && filterUnitList.length > 0 &&
+ filterUnitList.map(i=>{
+ return(
+
+ )
+ })
+ }
+
+
+ )
+}
+export default CaseDrop;
\ No newline at end of file
diff --git a/src/forge/Issues/Component/chooseMenu.jsx b/src/forge/Issues/Component/chooseMenu.jsx
new file mode 100644
index 000000000..4da6c5e4d
--- /dev/null
+++ b/src/forge/Issues/Component/chooseMenu.jsx
@@ -0,0 +1,305 @@
+import React ,{ useState , useEffect , useRef , forwardRef } from 'react';
+import { findDOMNode } from 'react-dom';
+import { Dropdown , Menu , Input , Button, Form , Tooltip } from 'antd';
+import { getImageUrl } from 'educoder';
+import AddTagsBox from './addTagsBox';
+
+const { Search } = Input;
+/**
+ *
+ * @param {placeholder} placeholder:默认显示内容(为空时)
+ * @param {editFlag} editFlag:是否有编辑权限
+ * @param {searchFlag} searchFlag:是否显示搜索框
+ * @param {selectValueList} selectValueList:将选中的list保存
+ * @param {searchFunc} searchFunc:搜索方法
+ * @param {onAdd} onAdd:标记管理
+ * @param {headImg} headImg:是否显示头像
+ * @param {menus} menus:下拉列表
+ * @param {chooseFunc} chooseFunc:选择下拉列表
+ * @param {double} double:undefined为单选,有值就是最多选的数量
+ * @param {colorFlag} colorFlag:选中值需根据颜色显示背景
+ * @param {mustFlag} mustFlag:必须选择一个
+ * @param {removeFlag} removeFlag:移除按钮
+ * @returns
+ */
+function ChooseMenu({
+ placeholder ="未设置",
+ editFlag,
+ searchFlag,
+ selectValueList,
+ searchFunc,
+ onAdd,
+ headImg,
+ menus,
+ auto,
+ chooseFunc,double,colorFlag,mustFlag,removeFlag,owner,projectsId
+}){
+ const [ visible , setVisible ] = useState(false);
+ const [ searchValue , setSearchValue ]= useState(undefined);
+ const [ valuesId , setValuesId ] = useState([]);
+ const [ count , setCount ] = useState(double);
+ const [ content , setContent ] = useState(false);
+
+ const [ saveList , setSaveList ] = useState(undefined);
+
+ const refFa = useRef(null);
+ const refBox = useRef(null);
+
+ useEffect(() => {
+ document.addEventListener('mousedown', clickMe , false);
+ return () => {
+ window.removeEventListener("mousedown", clickMe, false);
+ }
+ }, [])
+
+ const clickMe = ({ target }) => {
+ // 查找父组件
+ const faComponent = findDOMNode(refFa.current);
+ const boxComponent = findDOMNode(refBox.current);
+ if (faComponent && boxComponent) {
+ const isChild = faComponent.contains(target);
+ const isBox = boxComponent.contains(target);
+ const arr = ["removeicon","iconfont icon-guanbi font-12 color-white","iconfont icon-guanbi font-12 color-blue","icon-a-bianji12","color-blue font-15 tagManage","iconfont icon-xiangzuojiantou font-15 color-grey mr5 cursor","cover","ant-btn cancelTags"];
+ const pointer = arr.includes(target.className);
+ if(!isChild && !isBox && !pointer){
+ setVisible(false);
+ setContent(false);
+ }
+ }
+ }
+
+ // 根据选中的列表循环出id数组
+ useEffect(()=>{
+ if(selectValueList && selectValueList.length > 0 && visible ){
+ renderSelectList(selectValueList);
+ setSaveList(selectValueList);
+ setCount(selectValueList.length);
+ }else{
+ setValuesId([]);
+ setCount(0);
+ setSaveList(undefined);
+ }
+ if(!visible){
+ setSearchValue(undefined);
+ searchFunc(undefined);
+ }
+ },[selectValueList,visible])
+
+ function renderSelectList(list){
+ let a = list && list.length > 0 && list.map((i,k)=>{
+ return i.id ? i.id.toString() : i.name
+ })
+ setValuesId(a);
+ }
+
+ // 搜索
+ function changeSearchvalue(e){
+ setSearchValue(e.target.value);
+ searchFunc(e.target.value);
+ }
+ function renderNames(nameArrs){
+ return
+ {
+ nameArrs && nameArrs.length>0?
+ nameArrs.map((i,k)=>{
+ return(
+
+ {i.image_url &&
}
+ {
+ colorFlag ?
+ (
+ colorFlag === "2" ?
+
+ {i.name}
+
+ :
+ {i.name}
+ )
+ :
+ {i.name}
+ }
+ { !colorFlag && removeFlag && removeValueFunc(i.id)}>}
+ { colorFlag && removeFlag && removeValueFunc(i.id)} style={{display:'block',right:"19px",position:"absolute"}}>}
+
+ )
+ })
+ :{placeholder}
+ }
+
+ }
+
+ // 选择项
+ function chooseMenu(i){
+ let list = saveList && saveList.length > 0 ? [...saveList]:[] ;
+ let relist = [];
+ relist = list && list.length > 0 ? list:[];
+ let filter = [];
+ if(i.id){
+ filter = list.filter(j=>j.id === i.id);
+ }else{
+ filter = list.filter(j=>j.name === i.name);
+ }
+ if(filter && filter.length > 0){
+ if(i.id){
+ relist = list.filter(j=>j.id !== i.id);
+ }else{
+ relist = list.filter(j=>j.name !== i.name);
+ }
+ }else{
+ if(double && (saveList && saveList.length >= double)){
+ setCount(-1);
+ return;
+ }
+ if(double){
+ relist.push(i);
+ }else{
+ relist = [i];
+ }
+ }
+ renderSelectList(relist);
+ setSaveList(relist);
+ setCount(relist ? relist.length :0);
+ if(!double){
+ setVisible(false);
+ setContent(false);
+ chooseFunc(relist);
+ }
+ }
+
+ // 确认按钮
+ function onSureFunc(){
+ setVisible(false);
+ setContent(false);
+ chooseFunc(saveList);
+ }
+ // 移除选择的项
+ function removeSaveFunc(id){
+ let list = [...saveList];
+ let filter = list.filter(j=>j.id !== id);
+ setSaveList(filter);
+ renderSelectList(filter);
+ setCount(filter ? filter.length :0);
+ }
+
+ // 移除后保存
+ function removeValueFunc(id){
+ let list = [...selectValueList];
+ let filter = list.filter(j=>j.id !== id);
+ setSaveList(filter);
+ renderSelectList(filter);
+ setCount(filter ? filter.length :0);
+ chooseFunc(filter);
+ }
+
+ function onSuccess(){
+ setContent(false);
+ onAdd();
+ }
+ return(
+
+
+ {placeholder}
+ {
+ !editFlag &&
+
+ {
+ !content ?
+
+ {
+ double && saveList && saveList.length>0?
+
+ {
+ saveList.map((i,k)=>{
+ return(
+ -
+ {i.name}
+ removeSaveFunc(i.id)}>
+
+ )
+ })
+ }
+
+ :""
+ }
+ { searchFunc &&
+
+
+
+ }
+ {
+ menus && menus.length >0?
+
+ :
+
+
{searchValue ? 暂无{placeholder}“{searchValue}”: `暂无${placeholder}`}
+
+ }
+
+
+ {
+ double && (count<0 ?
+
最多添加{double}个{placeholder}!
+ :
+
还可添加{double - count}个{placeholder}!
+ )
+ }
+
+ {
+ double &&
+
+
+
+
+ }
+
+ :
+ setContent(false)}
+ onSuccess={onSuccess} />
+ }
+
+ }>
+ setVisible(visible ? false : true)}>
+
+
+
+ }
+
+ 0 ? "operatevalue color-grey-3":"operatevalue"} style={{display:colorFlag?"flex":"block"}}>{renderNames(selectValueList)}
+
+ )
+}
+export default Form.create()(forwardRef(ChooseMenu));
\ No newline at end of file
diff --git a/src/forge/Issues/Component/colorCard.jsx b/src/forge/Issues/Component/colorCard.jsx
new file mode 100644
index 000000000..d63260035
--- /dev/null
+++ b/src/forge/Issues/Component/colorCard.jsx
@@ -0,0 +1,47 @@
+import React,{ useState , useEffect } from 'react';
+import { SketchPicker } from 'react-color';
+
+function ColorCard({getColor,defaultColor}){
+ const [ displayColorPicker , setDisplayColorPicker ] = useState(false);
+ const [ textcolor , setTextColor ] = useState("#F17013");
+
+
+ useEffect(()=>{
+ if(defaultColor){
+ setTextColor(defaultColor);
+ }
+ },[defaultColor])
+
+ // 切换色卡
+ function handleChange(color){
+ setTextColor(color.hex);
+ getColor(color ? color.hex : defaultColor);
+ }
+
+ // 隐藏色卡
+ function handleClick(){
+ setDisplayColorPicker(!displayColorPicker);
+ // reduction();
+ }
+
+ // 还原色卡
+ function reduction(){
+ setTextColor("#F17013");
+ // setColor({r: '241',g: '112',b: '19',a: '1',});
+ }
+ return(
+
+
+ {displayColorPicker ? (
+
+
{setDisplayColorPicker(false)}} />
+
+
+ ) : null}
+
+ )
+}
+export default ColorCard;
\ No newline at end of file
diff --git a/src/forge/Issues/Component/comments/editComment.jsx b/src/forge/Issues/Component/comments/editComment.jsx
new file mode 100644
index 000000000..a0083d2fb
--- /dev/null
+++ b/src/forge/Issues/Component/comments/editComment.jsx
@@ -0,0 +1,165 @@
+import React from 'react';
+import { Button, message } from 'antd';
+import { getImageUrl } from 'educoder';
+import MDEditor from "../../../../modules/tpm/challengesnew/tpm-md-editor";
+import Upload from "../../../../forge/Upload/Index";
+import Attachments from "../../../../forge/Upload/attachment";
+import UploadImg from "../../../../forge/Images/upload.png";
+import './list.scss';
+import '../../../../forge/Order/order.scss';
+import { useState } from 'react';
+import { Link } from 'react-router-dom';
+import axios from 'axios';
+
+function EditComment(props){
+ const {owner, projectsId, index} = props.match.params;
+ const {current_user, current_user:{login}, showLoginDialog, showNotification, reloadComment, cancelMd, parentId, replyId, updateId, showUserImg=true} = props;
+ const [content, setContent] = useState(props.content);
+ const [quillFlag, setQuillFlag] = useState(false);
+ // 确认评论按钮loading效果
+ const [journalSpin, setJournalSpin] = useState(false);
+ const [atWhoLoginList, setAtWhoLoginList] = useState(undefined);
+ const [fileList, setFileList] = useState(undefined);
+ const [attachmentClean, setAttachmentClean] = useState(true);
+ const [ save , setSave ] = useState(undefined);
+
+ useState(()=>{
+ setSave(props.defaultFileList);
+ },[props.defaultFileList])
+
+ // 评论点击函数
+ function addJournals(){
+ if(!content){
+ setQuillFlag(true);
+ return
+ }
+ setJournalSpin(true);
+ if(updateId){
+ // 修改评论
+ axios.patch(`/v1/${owner}/${projectsId}/issues/${index}/journals/${updateId}`,{
+ notes: content,
+ attachment_ids: fileList,
+ receivers_login:atWhoLoginList
+ }).then(res=>{
+ if(res && res.data){
+ // 刷新评论列表
+ reloadComment();
+ message.success('评论成功');
+ cancelMd();
+ setContent(undefined);
+ }
+ setJournalSpin(false);
+ })
+ }else{
+ // 新建评论
+ const params = {
+ parent_id: parentId,
+ reply_id: replyId,
+ notes: content,
+ attachment_ids: fileList,
+ receivers_login:atWhoLoginList
+ }
+ axios.post(`/v1/${owner}/${projectsId}/issues/${index}/journals`, params).then(res=>{
+ if(res && res.data){
+ // 刷新评论列表
+ reloadComment();
+ message.success('评论成功');
+ cancelMd();
+ setContent(undefined);
+ }
+ setJournalSpin(false);
+ })
+ }
+ };
+ function deleteLoad(id){
+ let arr = [];
+ let list = save;
+ if(list && list.length>0 ){
+ arr = list.filter(i=>i.id !== id);
+ }
+ setFileList(arr.map(i=>{return i.id}));
+ setSave(arr);
+ }
+ function UploadFunc(f){
+ let list = [];
+ let arr = [];
+ if(save && save.length>0 ){
+ arr = save.map(i=>{return i.id});
+ }
+ list = arr && arr.length>0 ? f.concat(arr) : f ;
+ setFileList(list);
+ };
+
+ return(
+
+
+

+
+
+
{setQuillFlag(false);setContent(value);}}
+ isCanAtme = {true}
+ isQuoteIssue={true}
+ changeAtWhoLoginList = {(loginList)=>{setAtWhoLoginList(loginList); setAttachmentClean(true)}}
+ owner = {owner}
+ projectsId = {projectsId}
+ >
+
+ {quillFlag && 请输入评论内容}
+
+
+ }
+ size={100}
+ showNotification={showNotification}
+ // defaultFileList={props.defaultFileList}
+ />
+ {props.defaultFileList && props.defaultFileList.length > 0 &&
+
+ }
+
+
+
+
+
+
+ )
+}
+export default EditComment;
\ No newline at end of file
diff --git a/src/forge/Issues/Component/comments/list.jsx b/src/forge/Issues/Component/comments/list.jsx
new file mode 100644
index 000000000..afabf21a2
--- /dev/null
+++ b/src/forge/Issues/Component/comments/list.jsx
@@ -0,0 +1,242 @@
+import React, { useEffect, useState } from 'react';
+import { Button, Popconfirm, Radio, Input, message, Tooltip, Spin, Pagination } from 'antd';
+import axios from 'axios';
+import { getImageUrl, timeAgo } from 'educoder';
+import RenderHtml from '../../../../components/render-html';
+import Attachment from '../../../Upload/attachment';
+import EditComment from './editComment';
+import Nodata from '../../../Nodata';
+import CheckProfile from '../../../Component/ProfileModal/Profile';
+import './list.scss';
+import { Link } from 'react-router-dom';
+
+function IssueCommentList(props){
+ const{history, history: {location}, reload, reloadComment, showNotification, current_user:{login, admin, image_url, user_id}, isManager, showLoginDialog, issueInfo:{author}} = props;
+ const {owner, projectsId, index} = props.match.params;
+ const [category, setCategory] = useState('comment');
+ const [journals, setJournals] = useState(undefined);
+ // 是否展示新建/编辑评论markdown部分新建评论1 编辑父级评论2 回复评论3 编辑回复内容4 回复子机评论5
+ const [showEdit, setShowEdit] = useState(false);
+ const [parentId, setParentId] = useState(undefined);
+ const [replyId, setReplyId] = useState(undefined);
+ // 修改评论id
+ const [updateId, setUpdateId] = useState(undefined);
+ // 操作日志展开效果
+ const [open, setOpen] = useState(undefined);
+ // 加载中效果(缓冲css 线条效果)
+ const [spin, setSpin] = useState(false);
+ // issue 评论总数
+ const [journalsCount, setJournalsCount] = useState(undefined);
+ // 分页
+ const limit = 50;
+ const [page, setPage] = useState(1);
+ const [totalCount, setTotalCount] = useState(undefined);
+ // 操作记录 icon
+ const journalsIcon ={
+ 'issue': 'icon-chuangjianqianbao',
+ 'branch_name': 'icon-fenzhi3',
+ 'assigner': 'icon-chengyuan2',
+ 'status_id': 'icon-xiugaibaobiaomoban',
+ 'fixed_version_id': 'icon-lichengbeiicon2',
+ 'due_date': 'icon-riqi',
+ 'issue_tag': 'icon-biaoji2',
+ 'description': 'icon-xiugaibaobiaomoban',
+ 'subject': 'icon-xiugaibaobiaomoban',
+ 'start_date': 'icon-riqi',
+ 'priority_id': 'icon-youxian',
+ 'attachment': 'icon-xiugaibaobiaomoban'
+ }
+
+ useEffect(()=>{
+ setSpin(true);
+ axios.get(`/v1/${owner}/${projectsId}/issues/${index}/journals`,{params:{
+ category,
+ page,
+ limit
+ }}).then(res=>{
+ if(res && res.data){
+ const {journals, total_comment_journals_count, total_count} = res.data;
+ if(category === 'all'){
+ const array = [];
+ let start = undefined;
+ let isJournalCount = 0;
+ journals.map((item, index)=>{
+ !isJournalCount && (start = index)
+ item.is_journal_detail && (isJournalCount++)
+ if(!item.is_journal_detail && isJournalCount < 10){
+ isJournalCount = 0;
+ return
+ }
+ if(isJournalCount >= 10 && (!item.is_journal_detail || journals.length-1 === index)){
+ array.push({start, count: isJournalCount});
+ isJournalCount = 0;
+ }
+ })
+ array.map((item, i)=>{
+ journals[item.start].numCount = item.count-1;
+ for (let index = 0; index < item.count; index++) {
+ journals[item.start+index].start = journals[item.start].id;
+ journals[item.start+index].closeAndSpan = true;
+ }
+ })
+ }
+ setTotalCount(total_count);
+ setJournalsCount(total_comment_journals_count);
+ setJournals(journals);
+ setSpin(false)
+ }
+ })
+ }, [reload, category, page])
+
+ function commentCtx(v){
+ return
;
+ };
+
+ // 删除评论内容
+ function deleteComment(id){
+ axios.delete(`/v1/${owner}/${projectsId}/issues/${index}/journals/${id}`).then(res=>{
+ if(res && res.data && !res.data.status){
+ reloadComment();
+ message.success('删除成功');
+ }
+ })
+ }
+
+ // markdown 取消操作
+ function cancelMd(){
+ setShowEdit(false);
+ }
+
+ return(
+
+ {/* 全部 / 评论 / 操作日志 */}
+
0 && 'pb15'}`}>
+
+ {setSpin(true);setPage(1);setCategory(e.target.value);history.push(history.pathname)}} value={category}>
+ 评论{journalsCount}
+ 操作日志
+ 全部
+
+
+
+ {/* 评论快速入口-仅有评论且登录时展示 */}
+ {login && category !== 'operate' && journalsCount > 0 &&
}
+ {/* 评论/操作日志 展示列表 */}
+
+
+ {journals && (journals.length > 0 && journals.map(item=>{return item.is_journal_detail ? (!item.closeAndSpan || item.id === item.start || open === item.start) ?
+
: '' :
+ {/* 评论 */}
+
+
})
+
+ {/* 判断是否是编辑状态 */}
+ {(showEdit === 2 && updateId === item.id) ?
:
+
+
+
+ {item.user.name}
+ {timeAgo(item.created_at)}
+
+ {login &&
+ {/* 平台管理员/仓库管理员/发布评论者/issue创建者 */}
+ {(admin || isManager || login === item.user.login || user_id === author.id) &&
0 ? '子评论也将被一起删除。' : ''}`}
+ okText="是"
+ cancelText="否"
+ onConfirm={() => deleteComment(item.id)}
+ >
+
+ }
+ {/* 仅评论者可修改 */}
+ {login === item.user.login &&
}
+
{setParentId(item.id); setReplyId(item.id); setShowEdit(3)}}>
+
}
+
+
{commentCtx(item.notes)}
+ {item && item.attachments && item.attachments.length > 0 &&
}
+
+
}
+ {showEdit === 3 && replyId === item.id &&
}
+ {/* 评论回复部分 */}
+ {item.children_journals.map(i =>{return
+ {(showEdit === 4 && updateId === i.id) ?
:
+
+
+
})
+
{i.user.name}
+ {i.reply_user &&
回复}
+
{i.reply_user && i.reply_user.name}
+
{timeAgo(i.created_at)}
+
+ {login &&
+ {/* 平台管理员/仓库管理员/发布评论者/回复评论者/issue创建者 */}
+ {(admin || isManager || login === i.user.login || (i.reply_user && login === i.reply_user.login) || user_id === author.id) &&
deleteComment(i.id)}
+ >
+
+ }
+ {/* 仅回复评论者可修改 */}
+ {login === i.user.login &&
}
+
{setParentId(item.id);setReplyId(i.id); setShowEdit(5)}}>
+
+
+
}
+
+
{commentCtx(i.notes)}
+ {i && i.attachments && i.attachments.length > 0 &&
}
+
}
+ {showEdit === 5 && replyId === i.id &&
}
+
})}
+
+
}))}
+
+
+ {totalCount>limit && }
+ {/* 添加评论 */}
+ {category !== 'operate' &&
+ {login ? showEdit === 1 ?
: : }
+ }
+
+ )
+}
+export default IssueCommentList;
\ No newline at end of file
diff --git a/src/forge/Issues/Component/comments/list.scss b/src/forge/Issues/Component/comments/list.scss
new file mode 100644
index 000000000..be95b6e3d
--- /dev/null
+++ b/src/forge/Issues/Component/comments/list.scss
@@ -0,0 +1,205 @@
+.typeActionBox{
+ padding: 10px 20px 4px;
+ background-color:rgba(241, 243, 252, 0.55);
+ border-radius:4px;
+ .typeActionRadio{
+ color: #333;
+ display: inline-flex;
+ align-items: center;
+ margin-right: 25px;
+ &.ant-radio-wrapper-checked{
+ color: $primary-color;
+ }
+ }
+ .journalsCount{
+ color:#5e6685;
+ background-color:rgba(70, 106, 255, 0.09);
+ border-radius:10px;
+ display: inline-block;
+ padding: 0px 6px;
+ }
+}
+.commentUserImg{
+ height: 28px;
+ width: 28px;
+ border-radius: 50%;
+ object-fit: cover;
+}
+.issueCommentsBox{
+ .iconBackBox{
+ display: inline-block;
+ width:24px;
+ height:24px;
+ border-radius: 50%;
+ line-height: 24px;
+ text-align: center;
+ background-color:#f2f3f5;
+ }
+ .operationLog, .commentContentBox{
+ position: relative;
+ min-height: 62px;
+ display: flex;
+ >.flexCenter, >a{
+ z-index: 2;
+ }
+ &::before, &::after{
+ content: '';
+ width: 1px;
+ height: 50%;
+ position: absolute;
+ background: #eee;
+ left: 12px;
+ z-index: 1;
+ }
+ &::after{
+ background: #eee;
+ top: 50%;
+ }
+ }
+ .commentContentBox+.operationLog .operationCommentBor, .operationLog+.commentContentBox .commentOperationBor{
+ border-top: 1px solid #eee;
+ width: 98.5%;
+ position: absolute;
+ left: 12px;
+ }
+ .operationLog+.commentContentBox{
+ &>a, &>.commentContentRight{
+ margin-top: 25px;
+ }
+ }
+ .timeAgo{
+ color:#acb0bf;
+ }
+ .operationLog:last-child::after, .operationLog:first-child::before, .commentContentBox:last-child::after, &.justComment .commentContentBox::before, &.justComment .commentContentBox::after{
+ display: none;
+ }
+ .operationLog:first-child, .commentContentBox+.operationLog{
+ margin-top: -15px;
+ }
+ .commentContentBox:last-child::before{
+ height: 35%;
+ }
+ .flexCenter{
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+ .commentRenderHtml.markdown-body p{
+ font-size: 14px !important;
+ }
+ .commentReply{
+ padding: 15px 0 0 20px;
+ background-color: rgba(238, 240, 246, 0.41);
+ &>div{
+ padding-bottom: 5px;
+ }
+ &+.commentReply>div{
+ margin-top: -15px;
+ padding-top: 15px;
+ border-top: 1px dashed #eee;
+ }
+ }
+ .opBox{
+ justify-content: flex-start;
+ // flex: 1;
+ // width: 100%;
+ }
+ .commentContentBox{
+ display: flex;
+ align-items: flex-start;
+ }
+ .commentContentRight{
+ flex: 1;
+ background-color:#fafafc;
+ border:1px solid rgba(42, 97, 255, 0.23);
+ border-radius:6px;
+ position: relative;
+ top: -6px;
+ padding: 10px 15px 16px;
+ width: 0;
+ &::before{
+ content: '';
+ display: block;
+ position: absolute;
+ top: 13px;
+ left: -14px;
+ width: 0;
+ height: 0;
+ overflow: hidden;
+ font-size: 0;
+ line-height: 0;
+ border: 7px;
+ border-style: solid;
+ border-color: transparent rgba(42, 97, 255, 0.23) transparent transparent;
+ }
+ &::after{
+ content: '';
+ display: block;
+ width: 0;
+ height: 0;
+ overflow: hidden;
+ font-size: 0;
+ line-height: 0;
+ border: 6px;
+ border-style: solid;
+ border-color: transparent #fafafc transparent transparent;
+ position: absolute;
+ top: 14px;
+ left: -11px;
+ }
+ }
+}
+.primaryColor, .primaryColor:link{
+ color: $primary-color;
+}
+.attachmentBox{
+ margin-top: -8px;
+}
+.color-grey-89{
+ color: #898d9d;
+}
+// 添加评论样式
+.unLoginComment{
+ height:58px;
+ line-height: 58px;
+ background-color:rgba(241, 243, 252, 0.55);
+ border-radius:4px;
+ color: rgba(84, 87, 103, 1);
+ .loginBtn{
+ color: $primary-color;
+ }
+}
+.quillFlagBox{
+ color: red;
+ margin-bottom: 5px !important;
+ height: 28px;
+}
+.addComments{
+ display: flex;
+ align-items: center;
+ background-color:rgba(241, 243, 252, 0.55);
+ border-radius:4px;
+ padding:7px 10px;
+ &>img{
+ height: 28px;
+ width: 28px;
+ border-radius: 50%;
+ margin-right: 13px;
+ }
+}
+.addCommentBox{
+ width: 100%;
+ height: 30px;
+ border: none;
+}
+.paginationIssueComment{
+ text-align: center;
+}
+.gotoComment{
+ background-color:rgba(241, 243, 252, 0.55);
+ border-radius:4px;
+ color: rgba(172, 176, 191, 1);
+ padding: 8px 20px;
+ margin-top: -10px;
+ &>a{color: rgba(70, 106, 255, 1);}
+}
\ No newline at end of file
diff --git a/src/forge/Issues/Component/copy.jsx b/src/forge/Issues/Component/copy.jsx
new file mode 100644
index 000000000..c10bf90e8
--- /dev/null
+++ b/src/forge/Issues/Component/copy.jsx
@@ -0,0 +1,22 @@
+import React ,{ useState } from 'react';
+import { Tooltip } from 'antd';
+import { CopyToClipboard } from 'react-copy-to-clipboard';
+
+
+function Copy({ children , value }){
+ const [ title , setTitle ] = useState("点击复制链接");
+ let host = window.location.hostname === "localhost" ? "testforgeplus.trustie.net" : window.location.hostname;
+ let protocol = window.location.protocol;
+ return(
+ setTitle("复制成功")}>
+
+ {children}
+
+
+ )
+}
+export default Copy;
\ No newline at end of file
diff --git a/src/forge/Issues/Component/datas.jsx b/src/forge/Issues/Component/datas.jsx
new file mode 100644
index 000000000..4a99aeafc
--- /dev/null
+++ b/src/forge/Issues/Component/datas.jsx
@@ -0,0 +1,97 @@
+import React from 'react';
+import { getImageUrl } from 'educoder';
+import gold from '../Img/gold.png';
+import { Link } from "react-router-dom";
+import Copy from '../Component/copy';
+import { Tooltip } from 'antd';
+
+
+// issue列表显示
+function Datas({checkbox ,item , projectsId,owner}){
+
+ function statusTag(name){
+ switch (name) {
+ case "低":
+ return "status low";
+ case "正常":
+ return "status normals";
+ case "高":
+ return "status hight";
+ default:
+ return "status urgent";
+ }
+ }
+
+ function renderName(list){
+ let l = list.map(i=>{return i.name});
+ return l.join(",");
+ }
+
+ return(
+
+
+ {checkbox}
+
+
+
{item.priority_name}
+ {/*

*/}
+
{item.subject}
+ {
+ item.tags && item.tags.length>0?
+ item.tags.map((i,k)=>{
+ return(
+
{i.name}
+ )
+ })
+ :""
+ }
+
+
+
+
+ { item.project_issues_index &&
+ #{item.project_issues_index}
+ }
+
+
+
{item.author && item.author.name}
+
{item.created_at} 发布
+
{item.updated_at}更新
+ {item.blockchain_token_num &&
{item.blockchain_token_num}}
+ {item.milestone_name &&
+
{window.scrollTo(0,0)}} style={{maxWidth:item.blockchain_token_num ? "261px":"340px",color:"#898d9d"}} title={item.milestone_name} className="task-hide mr20">
+
+ {item.milestone_name}
+
+ }
+
{item.test_case}
+
+
+
+
+
+ {
+ item.assigners && item.assigners.length > 0 ?
+
+ 1 ?"principal hovers":"principal"}>
+ {/* {
+ item.assigners.map((i,k)=>{
+ return(
+ k<5 &&
})
+ )
+ })
+ } */}
+
{renderName(item.assigners)}
+
+
+ :""
+ }
+
{item.status_name}
+
+ {item.comment_journals_count}
+
+
+
+ )
+}
+export default Datas;
\ No newline at end of file
diff --git a/src/forge/Issues/Component/date.jsx b/src/forge/Issues/Component/date.jsx
new file mode 100644
index 000000000..bd4f00a9a
--- /dev/null
+++ b/src/forge/Issues/Component/date.jsx
@@ -0,0 +1,149 @@
+import React,{useRef,useEffect, useState , forwardRef } from 'react';
+import { Dropdown , Calendar , Select, Radio, Col, Row } from 'antd';
+import { findDOMNode } from 'react-dom';
+import moment from 'moment';
+const { Group , Button } = Radio;
+
+function Date({name , today , setDate , editFlag},ref){
+ const [ visible , setVisible ] = useState(false);
+ const [ time , setTime ] = useState();
+
+ useEffect(()=>{
+ if(today){
+ setTime(today);
+ }
+ },[today])
+
+ const refFa = useRef(null);
+ const refBox = useRef(null);
+
+ useEffect(()=>{
+ if(!visible && !editFlag && (time && time !== today)){
+ setDate(time);
+ }
+ },[visible,editFlag,time])
+
+
+ useEffect(() => {
+ document.addEventListener('click', clickMe , false);
+ }, [])
+
+ const clickMe = ({ target }) => {
+ // 查找父组件
+ const faComponent = findDOMNode(refFa.current);
+ const boxComponent = findDOMNode(refBox.current);
+ if (faComponent && boxComponent) {
+ const isChild = faComponent.contains(target);
+ const isBox = boxComponent.contains(target);
+ let role = target.getAttribute("role");
+ if(!isChild && !isBox && !(role && role === "option")){
+ setVisible(false);
+ }
+ }
+ }
+ function onSelect(t){
+ setTime(moment(t).format('YYYY-MM-DD'));
+ setDate(moment(t).format('YYYY-MM-DD'));
+ setVisible(false);
+ }
+ const overlay=(
+
+
{
+ const start = 0;
+ const end = 12;
+ const monthOptions = [];
+ const current = value.clone();
+ const localeData = value.localeData();
+ const months = [];
+ for (let i = 0; i < 12; i++) {
+ current.month(i);
+ months.push(localeData.monthsShort(current));
+ }
+
+ for (let index = start; index < end; index++) {
+ monthOptions.push(
+
+ {months[index]}
+ ,
+ );
+ }
+ const month = value.month();
+
+ const year = value.year();
+ const options = [];
+ for (let i = year - 10; i < year + 10; i += 1) {
+ options.push(
+
+ {i}
+ ,
+ );
+ }
+ return (
+
+
+
+
+ {console.log("typyCHange:",e);onTypeChange(e.target.value)}} value={type}>
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }}
+ onSelect={onSelect}
+ />
+
+ )
+ return(
+
+
+
+ {name}
+ {!editFlag && setVisible(visible ? false : true)}> }
+
+ {time || "未设置"}
+
+
+ )
+}
+export default forwardRef(Date);
\ No newline at end of file
diff --git a/src/forge/Issues/Component/delBox.jsx b/src/forge/Issues/Component/delBox.jsx
new file mode 100644
index 000000000..89fed3e83
--- /dev/null
+++ b/src/forge/Issues/Component/delBox.jsx
@@ -0,0 +1,32 @@
+import React from "react";
+import Modals from '../../Component/PublicModal/Index';
+import { AlignTop } from '../../Component/layout';
+import { Button } from 'antd';
+
+function DelBox({visible,onCancel,onSuccess,content,title}){
+ return(
+
+
+
+
+ }
+ >
+
+
+
+ { content ?
+ content
+ :
+ 您确定要删除所有选中的疑修?
此操作将清空所有已选中的疑修,请谨慎操作
+ }
+
+
+
+ )
+}
+export default DelBox;
\ No newline at end of file
diff --git a/src/forge/Issues/Component/delayAuto.jsx b/src/forge/Issues/Component/delayAuto.jsx
new file mode 100644
index 000000000..dc411a471
--- /dev/null
+++ b/src/forge/Issues/Component/delayAuto.jsx
@@ -0,0 +1,54 @@
+import React , { useState , useEffect , useRef,useMemo} from 'react';
+import { Select , Spin } from 'antd';
+import debounce from 'lodash/debounce';
+
+function DebounceSelect({ fetchOptions, debounceTimeout = 600, ...props }) {
+ const [fetching, setFetching] = useState(false);
+ const [options, setOptions] = useState([]);
+ const fetchRef = useRef(0);
+
+ useEffect(()=>{
+ fetchOptions("").then((newOptions) => {
+ setOptions(newOptions);
+ });
+ },[])
+
+ const debounceFetcher = useMemo(() => {
+ const loadOptions = (value) => {
+ fetchRef.current += 1;
+ const fetchId = fetchRef.current;
+ setOptions([]);
+ setFetching(true);
+ fetchOptions(value).then((newOptions) => {
+ if (fetchId !== fetchRef.current) {
+ // for fetch callback order
+ return;
+ }
+ setOptions(newOptions);
+ setFetching(false);
+ });
+ };
+ return debounce(loadOptions, debounceTimeout);
+ }, [fetchOptions, debounceTimeout]);
+
+ return (
+ : null}
+ {...props}
+ defaultActiveFirstOption={false}
+ >
+ {
+ options && options.length >0 &&
+ options.map((i)=>{
+ return(
+ {i.value}
+ )
+ })
+ }
+
+ );
+}
+export default DebounceSelect
\ No newline at end of file
diff --git a/src/forge/Issues/Component/drop.jsx b/src/forge/Issues/Component/drop.jsx
new file mode 100644
index 000000000..f90a19d69
--- /dev/null
+++ b/src/forge/Issues/Component/drop.jsx
@@ -0,0 +1,47 @@
+import React,{useState, useEffect, useRef, useImperativeHandle,forwardRef} from 'react';
+import { Dropdown } from 'antd';
+import { findDOMNode } from 'react-dom';
+
+function Drop({overlay , children , placement, overlayClassName},ref){
+ const [ visible , setVisible ] = useState(false);
+ const refFa = useRef(null);
+ const refBox = useRef(null);
+
+ useImperativeHandle(ref, () => ({
+ clearVisible: (v) => {
+ // 父组件按钮:清除筛选条件,将dropmenu里的choose字段全部改为0
+ setVisible(v);
+ }
+ }))
+
+ useEffect(() => {
+ document.addEventListener('click', clickMe , false);
+ }, [])
+
+ const clickMe = ({ target }) => {
+ // 查找父组件
+ const faComponent = findDOMNode(refFa.current);
+ const boxComponent = findDOMNode(refBox.current);
+ if (faComponent && boxComponent) {
+ const isChild = faComponent.contains(target);
+ const isBox = boxComponent.contains(target);
+ if(!isChild && !isBox){
+ setVisible(false);
+ }
+ }
+ }
+ return(
+ {overlay}}
+ trigger={['click']}
+ overlayClassName={overlayClassName}
+ >
+ setVisible(visible ? false : true)}>
+ {children}
+
+
+ )
+}
+export default forwardRef(Drop);
\ No newline at end of file
diff --git a/src/forge/Issues/Component/dropMenu.jsx b/src/forge/Issues/Component/dropMenu.jsx
new file mode 100644
index 000000000..962243c0a
--- /dev/null
+++ b/src/forge/Issues/Component/dropMenu.jsx
@@ -0,0 +1,210 @@
+import React ,{ useState , useEffect , useRef } from 'react';
+import { findDOMNode } from 'react-dom';
+import { Dropdown , Menu , Input , message} from 'antd';
+import { getImageUrl } from 'educoder';
+
+const { Search } = Input;
+/**
+ *
+ * @param {placeholder} placeholder:默认显示内容(为空时)
+ * @param {editFlag} editFlag:是否有编辑权限
+ * @param {searchFlag} searchFlag:是否显示搜索框
+ * @param {selectValueList} selectValueList:将选中的list保存
+ * @param {searchFunc} searchFunc:搜索方法
+ * @param {onAdd} onAdd:标记管理
+ * @param {headImg} headImg:是否显示头像
+ * @param {menus} menus:下拉列表
+ * @param {chooseFunc} chooseFunc:选择下拉列表
+ * @param {double} double:undefined为单选,有值就是最多选的数量
+ * @param {colorFlag} colorFlag:选中值需根据颜色显示背景
+ * @param {mustFlag} mustFlag:必须选择一个
+ * @param {removeFlag} removeFlag:移除按钮
+ * @returns
+ */
+function DropMenu({
+ placeholder ="未设置",
+ editFlag,
+ searchFlag,
+ selectValueList,
+ searchFunc,
+ onAdd,
+ headImg,
+ menus,
+ chooseFunc,double,colorFlag,mustFlag,removeFlag
+}){
+ const [ visible , setVisible ] = useState(false);
+ const [ searchValue , setSearchValue ]= useState(undefined);
+ const [ valuesId , setValuesId ] = useState([]);
+ const [ valuesName , setValuesName ] = useState([]);
+
+ const refFa = useRef(null);
+ const refBox = useRef(null);
+
+ // 根据选中的列表循环出id数组
+ useEffect(()=>{
+ if(selectValueList && selectValueList.length > 0 ){
+ renderSelectList(selectValueList);
+ }else{
+ setValuesId([])
+ }
+ },[selectValueList])
+
+ function renderSelectList(list){
+ let a = list && list.length > 0 && list.map((i,k)=>{
+ return i.id ? i.id.toString() : i.name
+ })
+ setValuesId(a);
+ setValuesName(list);
+ }
+
+ useEffect(() => {
+ document.addEventListener('click', clickMe , false);
+ }, [])
+
+ const clickMe = ({ target }) => {
+ // 查找父组件
+ const faComponent = findDOMNode(refFa.current);
+ const boxComponent = findDOMNode(refBox.current);
+ if (faComponent && boxComponent) {
+ const isChild = faComponent.contains(target);
+ const isBox = boxComponent.contains(target);
+ if(!isChild && !isBox){
+ setVisible(false);
+ }
+ }
+ }
+ // 搜索
+ function changeSearchvalue(e){
+ setSearchValue(e.target.value);
+ searchFunc(e.target.value);
+ }
+
+ function chooseMenu(i){
+ let list = selectValueList;
+ let re = [];
+ re = list && list.length > 0 ? list:[];
+ let filter = [];
+ if(i.id){
+ filter = list.filter(j=>j.id === i.id);
+ }else{
+ filter = list.filter(j=>j.name === i.name);
+ }
+ if(filter && filter.length > 0){
+ if(!mustFlag){
+ if(i.id){
+ re = list.filter(j=>j.id !== i.id);
+ }else{
+ re = list.filter(j=>j.name !== i.name);
+ }
+ renderSelectList(re);
+ chooseFunc(re);
+ !double && setVisible(false);
+ }else{
+ setVisible(false);
+ }
+ }else{
+ if(double && (selectValueList && selectValueList.length >= double)){
+ message.info(`最多只能添加${double}个${placeholder}`);
+ return;
+ }
+ if(double){
+ re.push(i);
+ }else{
+ re = [i];
+ setVisible(false);
+ }
+ renderSelectList(re);
+ chooseFunc(re);
+ }
+ }
+
+ function showRemoveFunc(item){
+ let l = selectValueList ;
+ l = l.filter(i=>(i.id ? i.id.toString() : i.name) !== item.toString());
+ renderSelectList(l);
+ chooseFunc(l);
+ }
+
+ function renderNames(nameArrs){
+ return
+ {
+ nameArrs && nameArrs.length>0?
+ nameArrs.map((i,k)=>{
+ return(
+
+ {i.image_url &&
}
+ {
+ colorFlag ?
+ (
+ colorFlag === "2" ?
+ {i.name}
+ :
+ {i.name}
+ )
+ :
+ {i.name}
+ }
+ { removeFlag && showRemoveFunc(i.id || i.name)}>}
+
+ )
+ })
+ :{placeholder}
+ }
+
+ }
+ return(
+
+
+ {placeholder}
+ {!editFlag &&
+ setVisible(visible ? false : true)}>
+
+
+ }
+
+
+ { searchFunc &&
+
+
+
+ }
+ {
+ menus && menus.length >0?
+
+ :
+
+
{searchValue ? 暂无{placeholder}“{searchValue}”: `暂无${placeholder}`}
+
+ }
+ { onAdd && }
+
+ }>
+ 0 ? "operatevalue color-grey-3":"operatevalue"}>{renderNames(selectValueList)}
+
+
+ )
+}
+export default DropMenu;
\ No newline at end of file
diff --git a/src/forge/Issues/Component/menus.jsx b/src/forge/Issues/Component/menus.jsx
new file mode 100644
index 000000000..24aa86ad4
--- /dev/null
+++ b/src/forge/Issues/Component/menus.jsx
@@ -0,0 +1,93 @@
+import React ,{ useState , useRef , useEffect } from 'react';
+import { Input , Menu , Icon } from 'antd';
+import { getImageUrl } from 'educoder';
+import Drop from './drop';
+const { Search } = Input;
+
+/**
+ * @param {className} 的样式名称
+ * @param {name} 未选择时显示的内容
+ * @param {lists} 下拉列表,从接口获取,需一一填充
+ * @param {imgControl} 控制是否显示头像
+ * @param {size} 下拉框宽度,small:120px,large:260px
+ * @param {ids} 默认选择的项的id数组
+ * @param {search} 搜索方法
+ * @param {chooseFunc} 选择项后需调用列表的查询方法
+ * @param {update} 编辑状态
+ * @param {double} 是否可以多选
+ */
+function Menus({className,name, ids , lists , size , imgControl , searchFunc , chooseFunc , update , double ,names },ref){
+ const dropRef = useRef(null);
+ const [ chooseValue , setChooseValue ] = useState([]);
+ const [ showValue , setShowValue ] = useState(undefined);
+
+ useEffect(()=>{
+ ids ? setChooseValue(ids.split(",")) : setChooseValue([]);
+ setShowValue(names);
+ },[ids,names])
+
+
+ // 修改menus数组里的字段值
+ function changeMenusValue(i){
+ let l = ids;
+ let id = i.id.toString();
+ if(double){
+ l = ids ? ids.split(",") : [] ;
+ let nameArr = names ? names.split(",") : [] ;
+ if(l && l.indexOf(id)>=0){
+ l = l.filter(k=>k.toString() !== id);
+ nameArr = nameArr.filter(k=>k.toString() !== i.name);
+ }else{
+ l.push(id);
+ nameArr.push(i.name);
+ }
+ setChooseValue(l);
+ setShowValue(nameArr.join(","));
+ chooseFunc(l,nameArr.join(","));
+ }else{
+ if(l && l.indexOf(id)>=0){
+ setChooseValue([]);
+ setShowValue(undefined);
+ chooseFunc([]);
+ }else{
+ setChooseValue([`${i.id}`]);
+ setShowValue([i.name]);
+ chooseFunc([id],i.name);
+ }
+ dropRef.current && dropRef.current.clearVisible(false);
+ }
+ }
+
+ function menu(data){
+ return
+ { size !== "small" &&
+
searchFunc(e.target.value)}/>
+ }
+ {
+ data && data.length>0 ?
+
+ :
+
暂无{ids ? '{name}': name}
+ }
+
+ }
+ return(
+
+
+ {showValue || (update ? `更换${name}` : name) }
+
+
+
+ )
+}
+export default Menus;
\ No newline at end of file
diff --git a/src/forge/Issues/Component/newPanel.jsx b/src/forge/Issues/Component/newPanel.jsx
new file mode 100644
index 000000000..67a02943f
--- /dev/null
+++ b/src/forge/Issues/Component/newPanel.jsx
@@ -0,0 +1,129 @@
+import React , { forwardRef , useState } from 'react';
+import { Form , Input , Button } from 'antd';
+import MDEditor from "../../../modules/tpm/challengesnew/tpm-md-editor";
+import Upload from "../../Upload/Index";
+import Attachments from "../../Upload/attachment";
+import UploadImg from '../Img/UploadImg.png';
+
+function NewPanel(props,ref){
+ const [ description , setDescription ] = useState(undefined);
+ const [ fileList , setFileList] = useState(undefined);
+ const [ attachments , setAttachments ] = useState([]);
+ const [ save , setSave ] = useState([]);
+ const [ receivers_login , setReceiversLogin ] = useState(undefined);
+
+ const { createFunc , title , desc , files , onCancel , owner , projectsId } = props;
+
+ const { form: { getFieldDecorator, validateFields , setFieldsValue } } = props;
+ useState(()=>{
+ title && setTimeout(()=>{
+ setFieldsValue({subject:title});
+ desc && onContentChange(desc);
+ },100)
+ files && setAttachments(files);
+ files && setSave(files);
+ },[title , desc , files])
+
+ function onContentChange(value){
+ setDescription(value);
+ }
+ function UploadFunc(f){
+ let list = [];
+ let arr = [];
+ if(save && save.length>0 ){
+ arr = save.map(i=>{return i.id});
+ }
+ list = arr && arr.length>0 ? f.concat(arr) : f ;
+ setFileList(list);
+ };
+
+ function deleteLoad(id){
+ let arr = [];
+ let list = save;
+ if(list && list.length>0 ){
+ arr = list.filter(i=>i.id !== id);
+ }
+ setFileList(arr.map(i=>{return i.id}));
+ setSave(arr);
+ }
+
+ function changeAtWhoLoginList(loginList){
+ let list = new Set(receivers_login);
+ loginList.map(item => list.add(item));
+ setReceiversLogin(Array.from(list));
+ };
+
+ function sureFunc(){
+ validateFields((error,values)=>{
+ if (!error) {
+ createFunc(values,fileList,receivers_login,description);
+ }
+ })
+ }
+
+ function cancelFunc(){
+ if(onCancel){
+ onCancel();
+ }else{
+ window.history.back(-1);
+ }
+ }
+ return(
+
+
+ {getFieldDecorator("subject",{
+ rules:[{required:true,message:"请输入疑修标题"}]
+ })(
+
+ )}
+
+
+
+
+
+
+
+ }
+ size={100}
+ showNotification={props.showNotification}
+ />
+ {attachments && attachments.length > 0 &&
+
+ }
+
+
+
+
+
+
+ )
+}
+export default forwardRef(NewPanel);
diff --git a/src/forge/Issues/Img/UploadImg.png b/src/forge/Issues/Img/UploadImg.png
new file mode 100644
index 000000000..cb1e7d05c
Binary files /dev/null and b/src/forge/Issues/Img/UploadImg.png differ
diff --git a/src/forge/Issues/Img/biaoji.png b/src/forge/Issues/Img/biaoji.png
new file mode 100644
index 000000000..e40377459
Binary files /dev/null and b/src/forge/Issues/Img/biaoji.png differ
diff --git a/src/forge/Issues/Img/create.png b/src/forge/Issues/Img/create.png
new file mode 100644
index 000000000..63b4cc29c
Binary files /dev/null and b/src/forge/Issues/Img/create.png differ
diff --git a/src/forge/Issues/Img/emp.png b/src/forge/Issues/Img/emp.png
new file mode 100644
index 000000000..5db7c0778
Binary files /dev/null and b/src/forge/Issues/Img/emp.png differ
diff --git a/src/forge/Issues/Img/gold.png b/src/forge/Issues/Img/gold.png
new file mode 100644
index 000000000..3c64743b6
Binary files /dev/null and b/src/forge/Issues/Img/gold.png differ
diff --git a/src/forge/Issues/Img/issue-big.png b/src/forge/Issues/Img/issue-big.png
new file mode 100644
index 000000000..8d73e1d93
Binary files /dev/null and b/src/forge/Issues/Img/issue-big.png differ
diff --git a/src/forge/Issues/Img/issue.png b/src/forge/Issues/Img/issue.png
new file mode 100644
index 000000000..7a85ffff7
Binary files /dev/null and b/src/forge/Issues/Img/issue.png differ
diff --git a/src/forge/Issues/Img/millestones-big.png b/src/forge/Issues/Img/millestones-big.png
new file mode 100644
index 000000000..b57f83f31
Binary files /dev/null and b/src/forge/Issues/Img/millestones-big.png differ
diff --git a/src/forge/Issues/Img/pr.png b/src/forge/Issues/Img/pr.png
new file mode 100644
index 000000000..fc3deacf0
Binary files /dev/null and b/src/forge/Issues/Img/pr.png differ
diff --git a/src/forge/Issues/Pages/details.jsx b/src/forge/Issues/Pages/details.jsx
new file mode 100644
index 000000000..61f423bd9
--- /dev/null
+++ b/src/forge/Issues/Pages/details.jsx
@@ -0,0 +1,525 @@
+import React , { useEffect , useState , forwardRef , useRef } from 'react';
+import { Spin , Form , InputNumber, message } from 'antd';
+import { getImageUrl } from 'educoder';
+import { Link } from 'react-router-dom';
+import { Box , LongWidth } from '../../Component/layout';
+import RenderHtml from "../../../components/render-html";
+import DropMenu from '../Component/dropMenu';
+import NewPanel from '../Component/newPanel';
+import Attachments from "../../Upload/attachment";
+import DelBox from '../Component/delBox';
+import Date from '../Component/date';
+import moment from 'moment';
+import Copy from '../Component/copy';
+import axios from 'axios';
+import CommentList from '../Component/comments/list';
+import Claims from '../../claims/claims';
+import ChooseMenu from '../Component/chooseMenu';
+import CaseDrop from '../Component/caseDrop';
+
+function Details(props){
+ const owner = props.match.params.owner;
+ const projectsId = props.match.params.projectsId;
+ const index = props.match.params.index;
+
+ const [ details , setDetails ] = useState(undefined);
+ const [ statusList , setStatusList ] = useState([]);
+ const [ prioritiesList , setPrioritiesList ] = useState([]);
+ const [ chargeList , setChargeList ] = useState([]);
+ const [ charge , setCharge ] = useState(undefined);
+ const [ millstoneList , setMillstoneList ] = useState([]);
+ const [ millstone , setMillstone ] = useState(undefined);
+ const [ tagList , setTagList ] = useState(undefined);
+ const [ tag , setTag ] = useState(undefined);
+ const [ branchList , setBranchList ] = useState(undefined);
+ const [ branch , setBranch ] = useState(undefined);
+ const [ desc , setDesc ] = useState(undefined);
+
+ const [ orderId , setOrderId ] = useState(undefined);
+
+ const [ delVisible , setDelVisible] = useState(false);
+ const [ edit , setEdit] = useState(false);
+ const [ copy , setCopy] = useState(false);
+
+ const [ start_date, setStartDate ] = useState("");
+ const [ due_date, setDueDate ] = useState("");
+ const [ commentReload, setCommentReload] = useState(undefined);
+ const [ editFlag , setEditFlag ] = useState(false);
+ const [ amountEditFlag , setAmountEditFlag ] = useState(false);
+
+ const [ assigner_choose , setAssigner_choose ] = useState([]);
+ const [ prioritie_choose , setPrioritie_choose ] = useState([]);
+ const [ status_choose , setStatus_choose ] = useState([]);
+ const [ tag_choose , setTag_choose ] = useState([]);
+ const [ millstone_choose , setMillstone_choose ] = useState([]);
+ const [ branch_choose , setBranch_choose ] = useState([]);
+ const [ rewardAmount , setRewardAmount ] = useState(undefined);
+ const [ rewardFlag , setRewardFlag ] = useState(false);
+ const [ caseValue, setCaseValue ] = useState(undefined);
+
+ const pathname = props.history.location.pathname;
+ const permission = props && props.projectDetail && props.projectDetail.permission;
+ let colors = ["#1abcb1","#28be6c","#e67e22","#db3d1d"];
+
+ const {projectDetail , open_blockchain ,current_user } = props;
+ useEffect(()=>{
+ if(pathname === `/${owner}/${projectsId}/issues/${index}/copy`){
+ setEdit(true);
+ setCopy(true);
+ }else{
+ setEdit(false);
+ setCopy(false);
+ }
+ },[pathname])
+
+ useEffect(()=>{
+ if(projectDetail && details){
+ const { author, name} = projectDetail;
+ document.title = `${details.subject}-疑修-${author.name}/${name}`;
+ }
+ },[details,projectDetail])
+
+ useEffect(()=>{
+ if(index){
+ Init();
+ }
+ },[index])
+
+ function Init(){
+ const url = `/v1/${owner}/${projectsId}/issues/${index}`;
+ axios.get(url).then(result=>{
+ if(result && result.data){
+ let data = result.data;
+ setDetails(data);
+ let per = data && !data.user_permission;
+ setEditFlag(per);
+
+ setDesc(data && data.description);
+
+ const aut = current_user && data.author && (data.author.login === current_user.login);
+ const con = data.pull_fixed === false && aut;
+ setAmountEditFlag(con);
+
+ setAssigner_choose(data.assigners);
+ if(data.priority && data.priority.id){
+ setPrioritie_choose([{...data.priority,color:colors[data.priority.id-1]}]);
+ }else{
+ setPrioritie_choose([]);
+ }
+ setStatus_choose(data.status && data.status.id ? [data.status]:[]);
+ setTag_choose(data.tags);
+ setMillstone_choose(data.milestone && data.milestone.id ? [data.milestone]:[]);
+ setBranch_choose(data.branch_name ? [{name:data.branch_name}] : []);
+ setRewardAmount(data.blockchain_token_num);
+ setCaseValue(data.test_case);
+
+ data.start_date && setStartDate(moment(data.start_date).format('YYYY-MM-DD'));
+ data.due_date && setDueDate(moment(data.due_date).format('YYYY-MM-DD'));
+
+ setOrderId(data.id);
+ }
+ }).catch(error=>{
+ console.log(error);
+ })
+ }
+
+
+ function statusTag(name){
+ switch (name) {
+ case "低":
+ return "status low";
+ case "正常":
+ return "status normals";
+ case "高":
+ return "status hight";
+ default:
+ return "status urgent";
+ }
+ }
+ // 获取状态列表
+ useEffect(()=>{
+ getStatus();
+ },[])
+ function getStatus(){
+ const url = `/v1/${owner}/${projectsId}/issue_statues`;
+ axios.get(url).then(result=>{
+ if(result && result.data){
+ setStatusList(result.data.statues);
+ }
+ })
+ }
+ // 获取优先级列表
+ useEffect(()=>{
+ getPriorities();
+ },[])
+
+ function getPriorities(){
+ const url = `/v1/${owner}/${projectsId}/issue_priorities`;
+ axios.get(url).then(result=>{
+ if(result && result.data){
+ let priorities = result.data.priorities;
+ let array = addColorForPriorities(priorities);
+ setPrioritiesList(array);
+ }
+ })
+ }
+
+ function addColorForPriorities(list){
+ let array =[];
+ if(list && list.length>0){
+ array = list.map((i,k)=>{
+ let arr = {...i,color:colors[k]}
+ return arr;
+ })
+ }
+ return array;
+ }
+
+ // 获取负责人列表
+ useEffect(()=>{
+ getCharge();
+ },[charge])
+
+ function getCharge(){
+ const url = `/v1/${owner}/${projectsId}/collaborators`;
+ axios.get(url,{params:{keyword:charge,only_name:true}}).then(result=>{
+ if(result && result.data){
+ setChargeList(result.data.collaborators);
+ }
+ })
+ }
+ // 获取里程碑列表
+ useEffect(()=>{
+ getMillstone();
+ },[millstone])
+
+ function getMillstone(){
+ const url = `/v1/${owner}/${projectsId}/milestones`;
+ axios.get(url,{params:{keyword:millstone,only_name:true}}).then(result=>{
+ if(result && result.data){
+ setMillstoneList(result.data.milestones);
+ }
+ })
+ }
+ // 获取标记列表
+ useEffect(()=>{
+ getSign();
+ },[tag])
+ function getSign(){
+ const url = `/v1/${owner}/${projectsId}/issue_tags`;
+ axios.get(url,{params:{keyword:tag,only_name:true}}).then(result=>{
+ if(result && result.data){
+ setTagList(result.data.issue_tags);
+ }
+ })
+ }
+ // 获取标记列表
+ useEffect(()=>{
+ getBranch(branch);
+ },[branch])
+ function getBranch(branch){
+ if(branch){
+ let b = [...branchList];
+ let l = b.filter(i=>i.name.indexOf(branch)>-1);
+ setBranchList(l);
+ return ;
+ }
+ const url = `/${owner}/${projectsId}/branches.json`;
+ axios.get(url,{params:{keyword:tag}}).then(result=>{
+ if(result && result.data){
+ setBranchList(result.data);
+ }
+ })
+ }
+
+ // 可单个编辑保存右侧的项(!copy:非复制状态下)
+ function saveForeach(c,s,p,t,m,b,sDate,eDate,rewardAmount,caseValue){
+ if(!copy){
+ const url = `/v1/${owner}/${projectsId}/issues/${index}`;
+ axios.patch(url,{
+ branch_name: b ? b.join(",") :undefined,
+ status_id: s ? s.join(",") : undefined,
+ priority_id: p ? p.join(",") :undefined,
+ milestone_id: m ? m.join(",") :undefined,
+ issue_tag_ids: t?t:undefined,
+ assigner_ids: c?c:undefined,
+ start_date:sDate,
+ due_date:eDate,
+ blockchain_token_num:rewardAmount,
+ test_case:caseValue
+ }).then(result=>{
+ if(result){
+ Init();
+ // 更新操作日志
+ setCommentReload(Math.random());
+ }
+ }).catch(error=>{})
+ }
+ }
+
+ function deleteFunc(){
+ const url = `/v1/${owner}/${projectsId}/issues/${index}`;
+ axios.delete(url).then(result=>{
+ if(result){
+ props.showNotification("疑修删除成功!");
+ props.history.push(`/${owner}/${projectsId}/issues`);
+ }
+ }).catch(error=>{})
+ }
+
+ // 编辑保存
+ function createFunc(values,fileList,receivers_login,description){
+ let params ={
+ subject: values.subject,
+ attachment_ids: fileList,
+ receivers_login: receivers_login,
+ description: description
+ }
+ if(!copy){
+ // 调用编辑保存接口
+ const url = `/v1/${owner}/${projectsId}/issues/${index}`;
+ axios.patch(url,{
+ ...params
+ }).then(result=>{
+ if(result){
+ window.scrollTo(0,0);
+ props.showNotification("疑修更新成功!");
+ Init();
+ setEdit(false);
+ // 刷新操作记录
+ setCommentReload(Math.random());
+ }
+ }).catch(error=>{})
+ }else{
+ // 调用新建保存接口
+ const url = `/v1/${owner}/${projectsId}/issues`;
+ let b = branch_choose && branch_choose.length>0 ? branch_choose.map(i=>{return i.name}) :undefined;
+ let t = tag_choose && tag_choose.length>0 ? tag_choose.map(i=>{return i.id}) :undefined;
+ let a = assigner_choose && assigner_choose.length>0 ? assigner_choose.map(i=>{return i.id}) :undefined;
+ let m = millstone_choose && millstone_choose.length>0 ? millstone_choose.map(i=>{return i.id}) :undefined;
+ let p = prioritie_choose && prioritie_choose.length>0 ? prioritie_choose.map(i=>{return i.id}) :undefined;
+ let s = status_choose && status_choose.length>0 ? status_choose.map(i=>{return i.id}) :undefined;
+ axios.post(url,{
+ ...params,
+ branch_name: b && b.join(","),
+ status_id: s && s.join(","),
+ priority_id: p && p.join(","),
+ milestone_id: m && m.join(","),
+ issue_tag_ids: t,
+ assigner_ids: a,
+ start_date,
+ due_date
+ }).then(result=>{
+ if(result && result.data && result.data.project_issues_index){
+ window.scrollTo(0,0);
+ props.showNotification("任务复制成功!");
+ props.history.push(`/${owner}/${projectsId}/issues/${result.data.project_issues_index}`);
+ }
+ }).catch(error=>{})
+ }
+ }
+
+ // 取消编辑或复制
+ function onCancel(){
+ if(copy){
+ props.history.push(`/${owner}/${projectsId}/issues/${index}`);
+ }else{
+ setEdit(false);
+ window.scrollTo(0,0);
+ }
+ }
+
+ function refreshFunc(){
+ // 更新操作日志
+ setCommentReload(Math.random());
+ }
+
+
+ // 悬赏金额 失去焦点保存数据
+ function amountBlur(e){
+ if(!editFlag){
+ setRewardFlag(false);
+ const value = e.target.value;
+ if(value<0){
+ message.info("请输入大于0的正整数");
+ setRewardAmount(rewardAmount);
+ return;
+ }
+ setRewardAmount(e.target.value);
+ if((value && value >= 0) || !value){
+ saveForeach(undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,value);
+ }
+ }
+ }
+ function changeAmount(value){
+ if(amountEditFlag){
+ setRewardAmount(value);
+ }else{
+ setRewardAmount(rewardAmount);
+ }
+ }
+ return(
+ details ?
+
+
+ setDelVisible(false)}
+ onSuccess={deleteFunc}
+ content={}
+ />
+ {
+ edit ?
+
+
+
+ :
+
+
+
+
+
+ {details.priority &&
{ details.priority.name } }
+
{details.subject}
+
+
+
+ #{details.project_issues_index}
+
+ {
+ details.author &&
+
+
})
{details.author.name}
+
添加于{details.created_at}
+
+ }
+
+
+ {
+ details.user_permission &&
+
+ }
+
+
+ {desc ?
+
+ :
+
暂无描述
+ }
+ {details.attachments && details.attachments.length > 0 ?
+
+ : ""
+ }
+
+
+
+
+ }
+
+
+ {orderId &&
}
+
{setCharge(value)}}
+ headImg
+ selectValueList={assigner_choose}
+ editFlag={editFlag}
+ chooseFunc={(list)=>{setAssigner_choose(list);let l = list && list.length>0 ?list.map(i=>{return i.id || i.name}):[];saveForeach(l);}}
+ double={5}
+ removeFlag={!editFlag}
+ />
+ {setStatus_choose(list);let l = list && list.length>0 ?list.map(i=>{return i.id || i.name}):[];saveForeach(undefined,l);}}
+ />
+ {setPrioritie_choose(list);let l = list && list.length>0 ?list.map(i=>{return i.id || i.name}):[];saveForeach(undefined,undefined,l);}}
+ />
+ {setTag(value)}}
+ selectValueList={tag_choose}
+ chooseFunc={(list)=>{setTag_choose(list);let l = list && list.length>0 ?list.map(i=>{return i.id || i.name}):[];saveForeach(undefined,undefined,undefined,l);}}
+ double={3}
+ colorFlag="2"
+ removeFlag={!editFlag}
+ editFlag={editFlag}
+ onAdd={permission && permission !== "Reporter" ? ()=>{getSign();} :false}
+ owner={owner}
+ projectsId={projectsId}
+ />
+ {setMillstone(value)}}
+ selectValueList={millstone_choose}
+ editFlag={editFlag}
+ auto
+ chooseFunc={(list)=>{setMillstone_choose(list);let l = list && list.length>0 ?list.map(i=>{return i.id || i.name}):[];saveForeach(undefined,undefined,undefined,undefined,l);}}
+ />
+ {setBranch(value)}}
+ selectValueList={branch_choose}
+ editFlag={editFlag}
+ chooseFunc={(list)=>{setBranch_choose(list);let l = list && list.length>0 ?list.map(i=>{return i.id || i.name}):[];saveForeach(undefined,undefined,undefined,undefined,undefined,l);}}
+ />
+ {
+ open_blockchain &&
+
+
+ 悬赏金额
+ {/* {!editFlag && } */}
+
+
+
+ }
+ setCaseValue(v)} onBlur={(v)=>saveForeach(undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,v)}/>
+ {setStartDate(date);saveForeach(undefined,undefined,undefined,undefined,undefined,undefined,date)}} editFlag={editFlag}/>
+ {setDueDate(date);saveForeach(undefined,undefined,undefined,undefined,undefined,undefined,undefined,date)}} editFlag={editFlag}/>
+
+
+ :
+
+ )
+}
+export default Form.create()(forwardRef(Details));
\ No newline at end of file
diff --git a/src/forge/Issues/Pages/list.jsx b/src/forge/Issues/Pages/list.jsx
new file mode 100644
index 000000000..bc177ec84
--- /dev/null
+++ b/src/forge/Issues/Pages/list.jsx
@@ -0,0 +1,461 @@
+import React , { useRef , useState , useEffect } from 'react';
+import { Dropdown , Menu , Icon , Input , Checkbox , Pagination, Button , Tooltip ,Spin , DatePicker } from 'antd';
+import bj from '../Img/biaoji.png';
+import issueEmp from '../Img/issue-big.png';
+import { Link } from "react-router-dom";
+import AllMenus from '../Component/allMenus';
+import CheckProfile from '../../Component/ProfileModal/Profile';
+import Datas from '../Component/datas';
+import DelBox from '../Component/delBox';
+import axios from 'axios';
+import cookie from 'react-cookies';
+import emp from '../Img/emp.png';
+import moment from 'moment';
+
+const { RangePicker } = DatePicker;
+
+const { Search } = Input;
+const defaultLimit = 15;
+
+function List(props){
+ const [ visible , setVisible ] = useState(false);
+ const [ issueList , setIssueList ] = useState(undefined);
+ const [ closedCount , setClosedCount ] = useState(0);
+ const [ openedCount , setOpenedCount ] = useState(0);
+
+ const[ aboutMe , setAboutMe ] = useState("all");
+ const[ value , setValue ] = useState("");
+ const[ keyword , setKeyword ] = useState(undefined);
+
+ const [ category , setCategory] = useState("opened");
+ const [ begin_date , setBegin] = useState(undefined);
+ const [ end_date , setEnd] = useState(undefined);
+
+ const [ allValue , setAllValue ] = useState([]);
+ const [ allIds , setAllIds ] = useState([]);
+ const [ checkAll , setCheckAll ] = useState(false);
+
+ const [ names , setNames ] = useState(undefined);
+ const [ updateIds , setUpdateIds ] = useState(undefined);
+ const [ updateChooseIds , setUpdateChooseIds ] = useState(undefined);
+
+ const [ page , setPage ] = useState(1);
+ const [ limit , setLimit ] = useState(15);
+ const [ total , setTotal ] = useState(undefined);
+ const [ issueTotal , setIssueTotal ] = useState(0);
+
+ const [ clearFlag , setClearFlag ] = useState(false);
+ const [ has_created_issues , setHas_created_issues] = useState(false);
+
+ const menuRef = useRef(null);
+ const owner = props.match.params.owner;
+ const projectsId = props.match.params.projectsId;
+ const permission = props && props.projectDetail && props.projectDetail.permission;
+ const { projectDetail , current_user , open_blockchain} = props;
+
+ useEffect(()=>{
+ if(projectDetail){
+ const { author, name } = projectDetail;
+ document.title = `疑修-${author.name}/${name}`;
+ }
+ },[projectDetail])
+
+ useEffect(()=>{
+ const datas = cookie.load('issuestates');
+ let states = datas === "undefined" ? undefined : datas;
+ if(states){
+ setAboutMe(states.participant_category);
+ setCategory(states.category);
+ setPage(states.page);
+ setLimit(states.limit || defaultLimit);
+ setUpdateIds({...states});
+ setNames(states.names);
+ setBegin(states.begin_date);
+ setEnd(states.end_date);
+ // if(states.participant_category ==="all" && states.category === "opened" && states.page === 1 && states.limit===defaultLimit)
+ // Init({...states},states.page,states.names);
+ }else{
+ Init();
+ }
+ },[])
+
+ useEffect(()=>{
+ let v = allValue && allValue > 0;
+ if((updateIds && !v && (updateIds.author_id || updateIds.issue_priorities_id || updateIds.issue_tag_ids || updateIds.milestone_id || updateIds.sort_by || updateIds.status_id ||updateIds.assigner_id)) || value || end_date || begin_date || aboutMe !=="all"){
+ setClearFlag(true);
+ }else{
+ setClearFlag(false);
+ }
+ },[updateIds,value,allValue,begin_date,end_date,aboutMe])
+ // 自定义一个初始不更新的hook
+ const useUpdateEffect = (fn, inputs) => {
+ const didMountRef = useRef(false);
+ useEffect(() => {
+ if (didMountRef.current) fn();
+ else didMountRef.current = true;
+ }, inputs);
+ };
+
+ // 定义处理函数
+ function handleAllDisabled(){
+ Init(updateIds,page,names);
+ }
+
+ // 使用自定义hook
+ useUpdateEffect(handleAllDisabled, [aboutMe,keyword,category,limit,end_date,updateIds]);
+
+
+ function getDirection(id){
+ if(!id) return undefined;
+ if(id === "1" || id === "3" || id === "5"|| id === "7"){
+ return "desc"
+ }else{
+ return "asc"
+ }
+ }
+ function getBy(id){
+ if(!id) return undefined;
+ if(id === "1" || id === "2"){
+ return "issues.created_on"
+ }else if(id === "3" || id === "4"){
+ return "issues.updated_on"
+ }else if(id === "5" || id === "6"){
+ return "issue_priorities.position"
+ }else{
+ return "issues.blockchain_token_num"
+ }
+ }
+
+ // 获取issue列表数据
+ function Init(params,p,names){
+ setTotal(undefined);
+ const datas = cookie.load('issuestates');
+ let states = datas === "undefined" ? undefined : datas;
+ if(states){
+ cookie.remove('issuestates');
+ }
+ const url = `/v1/${owner}/${projectsId}/issues`;
+ axios.get(url,{
+ params:{
+ ...params,
+ page:p || 1,
+ keyword,
+ participant_category:aboutMe,
+ category,
+ limit,
+ begin_date,end_date,
+ sort_direction:getDirection(params && params.sort_by),
+ sort_by:getBy(params && params.sort_by),names:undefined
+ }
+ }).then(result=>{
+ if(result){
+ setIssueList(result.data.issues);
+ setTotal(result.data.total_count);
+ setClosedCount(result.data.closed_count);
+ setOpenedCount(result.data.opened_count);
+ const ids = result.data.issues.length>0 ? result.data.issues.map(i=>{return i.id}) : [];
+ setAllIds(ids);
+ setIssueTotal(result.data.total_issues_count);
+ setHas_created_issues(result.data.has_created_issues);
+
+ const d = {...params,keyword,participant_category:aboutMe,category,limit,page:p || 1,
+ sort_direction:getDirection(params && params.sort_by),begin_date,end_date,
+ sort_by:getBy(params && params.sort_by),names:names};
+
+ let inFifteenMinutes = new Date(new Date().getTime() + 24 * 3600 * 1000);
+ cookie.save('issuestates', {...d},{ expires: inFifteenMinutes,path:`/` });
+ }
+ }).then(error=>{})
+ }
+
+ // 第一个下拉搜索
+ const menu = (
+
+ )
+ function chooseAboutMe(e){
+ setPage(1);
+ // setCategory("opened");
+ setAboutMe(e.key);
+ }
+
+ //清除筛选条件
+ function clearCondition(){
+ setKeyword(undefined);
+ setAboutMe("all");
+ setCategory("opened");
+ setUpdateIds(undefined);
+ setAllValue([]);
+ setPage(1);
+ setValue(undefined);
+ setNames(undefined);
+ setEnd(undefined);
+ setBegin(undefined);
+ // if(!value){
+ // Init();
+ // }
+ // 清除下拉选项
+ menuRef.current && menuRef.current.clearChoose();
+ }
+
+ // 全选所有issue
+ function chooseAll(e){
+ setCheckAll(e.target.checked);
+ // 清除下拉选项
+ menuRef.current && menuRef.current.clearChoose();
+ if(e.target.checked){
+ setAllValue(allIds);
+ }else{
+ setAllValue([]);
+ }
+ }
+
+ // 选择列表里的issue
+ function checkIssues(value){
+ // 清除下拉选项
+ menuRef.current && menuRef.current.clearChoose();
+ setAllValue(value);
+ if(value.length === allIds.length){
+ setCheckAll(true);
+ }else{
+ setCheckAll(false);
+ }
+ }
+
+ // 取消
+ function cancelUpdate(){
+ setAllValue([]);
+ setCheckAll(false);
+ // 清除下拉选项
+ menuRef.current && menuRef.current.clearChoose();
+ }
+ // 确认修改 allValue updateIds
+ function sureUpdate(){
+ const url = `/v1/${owner}/${projectsId}/issues/batch_update`;
+ axios.patch(url,{
+ assigner_ids: updateChooseIds && updateChooseIds.assigner_id && updateChooseIds.assigner_id.split(","),
+ ids: allValue,
+ issue_tag_ids: updateChooseIds && updateChooseIds.issue_tag_ids && updateChooseIds.issue_tag_ids.split(","),
+ milestone_id: updateChooseIds && updateChooseIds.milestone_id,
+ priority_id: updateChooseIds && updateChooseIds.issue_priorities_id,
+ status_id: updateChooseIds && updateChooseIds.status_id
+ }).then(result=>{
+ if(result){
+ setUpdateIds(undefined);
+ setAllValue([]);
+ setTotal(undefined);
+ Init();
+ cancelUpdate();
+ }
+ }).catch(error=>{})
+ }
+
+ // 切换页码
+ function changepage(p){
+ setPage(p);
+ Init(updateIds,p,names);
+ if (document) { // 可以排除不需要置顶的页面
+ if (document.documentElement || document.body) {
+ document.documentElement.scrollTop = document.body.scrollTop = 0; // 切换路由时手动置顶
+ }
+ }
+ }
+
+ // 删除issue相关 func
+ function onSuccess(){
+ const url = `/v1/${owner}/${projectsId}/issues/batch_destroy`;
+ axios.delete(url,{
+ params:{ids:allValue}
+ }).then(result=>{
+ if(result){
+ setUpdateIds(undefined);
+ setAllValue([]);
+ setVisible(false);
+ setCheckAll(false);
+ props.showNotification("疑修删除成功!");
+ Init();
+ }
+ }).catch(error=>{})
+ }
+
+ function chooseFunc(ids,n){
+ setNames(n);
+ setPage(1);
+ if(allValue && allValue.length>0){
+ // 将ids保存下来以便修改
+ // setUpdateIds(ids);
+ setUpdateChooseIds(ids);
+ }else{
+ if(ids.status_id === "5"){
+ setCategory("closed");
+ }else{
+ setCategory("opened");
+ }
+ setUpdateIds(ids);
+ setTotal(undefined);
+ // Init(ids,1,n);
+ }
+ }
+
+ function chageLimit(c,p){
+ setPage(1);
+ setLimit(p);
+ }
+ function changeCategory(value){
+ if(value !== category){
+ let ids = {...updateIds};
+ let ns = {...names};
+ if(value === "closed"){
+ ns = {...ns,status_name:"关闭"}
+ ids = {...ids,status_id:'5'};
+ setNames(ns)
+ setUpdateIds(ids);
+ }else{
+ ns = {...ns,status_name:undefined}
+ ids = {...ids,status_id:undefined};
+ setNames(ns)
+ setUpdateIds(ids);
+ }
+ setCategory(value);
+ setPage(1);
+ setTotal(undefined);
+ }
+ }
+
+ function changeSearchValueFunc(e){
+ setValue(e.target.value);
+ if(e.target.value===""){
+ setKeyword(undefined);
+ }
+ }
+
+ // 选择搜索时间
+ function changeBeginTime(data, value){
+ setPage(1);
+ setBegin(value[0] || '');
+ setEnd(value[1] || '');
+ }
+ return(
+
+
setVisible(false)} onSuccess={onSuccess}/>
+
+
+ {
+ (current_user && current_user.login) &&
+
+
+ {aboutMe === "all" ? "全部":aboutMe === "aboutme"?"与我相关":aboutMe === "assignedme"?"我负责的":aboutMe === "authoredme"?"我创建的":"@我的"}
+
+
+
+ }
+
setKeyword(value)}
+ style={{ width: 354 , height : 32 }}
+ allowClear
+ />
+ {
+ clearFlag &&
+
+ 清除筛选条件
+ }
+
+
+
+ {
+ permission && permission !== "Reporter" &&
+
标记管理
+ }
+ {props.history.push(`/${owner}/${projectsId}/issues/new`)}} checklogin className="operateButton ml20">创建疑修
+
+
+
+
+
+
+ {
+ allValue && allValue.length>0 ?
+
选择{allValue.length}个issue
+ :
+
+ - {changeCategory("all")}}>全部{issueTotal}
+ - {changeCategory("opened")}}>开启中{openedCount}
+ - {changeCategory("closed")}}>已关闭{closedCount}
+
+ }
+
+
+
0}
+ owner={owner}
+ projectsId={projectsId}
+ chooseFunc={chooseFunc}
+ defaultNames={names}
+ defaultIds={allValue && allValue.length>0 ? undefined : updateIds}
+ open_blockchain={open_blockchain}
+ />
+ {
+ allValue && allValue.length>0 ?
+
+
+
+
+
+ :""
+ }
+
+
+ {
+ total === 0 &&
+ (!has_created_issues ?
+
+

+
欢迎使用疑修(Issue)
+
疑修用于记录与跟踪待办事项、项目bug、功能需求等。在使用之前,请您先{props.history.push(`/${owner}/${projectsId}/issues/new`)}} className="color-blue">创建一个疑修
+
+ :
+
+ )
+ }
+ {
+ total > 0 &&
+
+
+
+ {issueList.map((item,key)=>{
+ return(
+ }
+ item={item}
+ owner={owner}
+ projectsId={projectsId}
+ />
+ )
+ })
+ }
+
+
+ {
+ total > defaultLimit &&
+
+ }
+
+ }
+ {total === undefined &&
}
+
+
+ )
+}
+export default List;
\ No newline at end of file
diff --git a/src/forge/Issues/Pages/new.jsx b/src/forge/Issues/Pages/new.jsx
new file mode 100644
index 000000000..b40307380
--- /dev/null
+++ b/src/forge/Issues/Pages/new.jsx
@@ -0,0 +1,306 @@
+import React , { useEffect , useState , forwardRef , useRef } from 'react';
+import { Form , InputNumber } from 'antd';
+import { Box , LongWidth } from '../../Component/layout';
+import DropMenu from '../Component/dropMenu';
+import ChooseMenu from '../Component/chooseMenu';
+import AddTagsBox from '../Component/addTagsBox';
+import Date from '../Component/date';
+import NewPanel from '../Component/newPanel';
+import axios from 'axios';
+import CaseDrop from '../Component/caseDrop';
+
+function New(props){
+ // history search 是否含有意见反馈标识
+ const {location:{search}, projectDetail} = props;
+ const feedBack = search && search.indexOf('type=feedback') !== -1;
+ // 里程碑id
+ const milepostId = props.match.params.milepostId;
+
+
+ const [ statusList , setStatusList ] = useState([]);
+ const [ prioritiesList , setPrioritiesList ] = useState([]);
+ const [ chargeList , setChargeList ] = useState([]);
+ const [ charge , setCharge ] = useState(undefined);
+ const [ millstoneList , setMillstoneList ] = useState([]);
+ const [ millstone , setMillstone ] = useState(undefined);
+ const [ tagList , setTagList ] = useState(undefined);
+ const [ tag , setTag ] = useState(undefined);
+ const [ branchList , setBranchList ] = useState(undefined);
+ const [ branch , setBranch ] = useState(undefined);
+
+
+ const [ assigner_choose , setAssigner_choose ] = useState([]);
+ const [ prioritie_choose , setPrioritie_choose ] = useState([]);
+ const [ status_choose , setStatus_choose ] = useState([]);
+ const [ tag_choose , setTag_choose ] = useState([]);
+ const [ millstone_choose , setMillstone_choose ] = useState([]);
+ const [ branch_choose , setBranch_choose ] = useState([]);
+ const [ caseValue, setCaseValue ] = useState(undefined);
+
+ const [ start_date, setStartDate ] = useState("");//moment().format('YYYY-MM-DD')
+ const [ due_date, setDueDate ] = useState("");
+
+ const [ rewardAmount , setRewardAmount ] = useState(undefined);
+
+ const owner = props.match.params.owner;
+ const projectsId = props.match.params.projectsId;
+ const permission = props && props.projectDetail && props.projectDetail.permission;
+ const { open_blockchain } = props;
+ const ref = useRef(null);
+
+ useEffect(()=>{
+ if(projectDetail){
+ if(feedBack){
+ document.title = `意见反馈`;
+ return;
+ }
+ const { author, name} = projectDetail;
+ document.title = `新建疑修-${author.name}/${name}`
+ }
+ },[projectDetail, feedBack])
+
+ useEffect(()=>{
+ if(milepostId){
+ getMillstone(milepostId);
+ }
+ },[milepostId])
+
+
+ // 获取状态列表
+ useEffect(()=>{
+ getStatus();
+ },[])
+ function getStatus(){
+ const url = `/v1/${owner}/${projectsId}/issue_statues`;
+ axios.get(url).then(result=>{
+ if(result && result.data){
+ let status = result.data.statues;
+ setStatusList(status);
+ if(status && status.length>0){
+ setStatus_choose(status.filter(i=>i.id === 1));
+ }
+ }
+ })
+ }
+ // 获取优先级列表
+ useEffect(()=>{
+ getPriorities();
+ },[])
+
+ function getPriorities(){
+ const url = `/v1/${owner}/${projectsId}/issue_priorities`;
+ axios.get(url).then(result=>{
+ if(result && result.data){
+ let priorities = result.data.priorities;
+ let array =[];
+ let colors = ["#1abcb1","#28be6c","#e67e22","#db3d1d"];
+ if(priorities && priorities.length>0){
+ array = priorities.map((i,k)=>{
+ let arr = {...i,color:colors[k]}
+ return arr;
+ })
+ }
+ setPrioritiesList(array);
+ setPrioritie_choose(array.filter(i=>i.id === 2));
+ }
+ })
+ }
+
+ // 获取负责人列表
+ useEffect(()=>{
+ getCharge();
+ },[charge])
+
+ function getCharge(){
+ const url = `/v1/${owner}/${projectsId}/collaborators`;
+ axios.get(url,{params:{keyword:charge,only_name:true}}).then(result=>{
+ if(result && result.data){
+ setChargeList(result.data.collaborators);
+ if(feedBack && !charge){
+ // 指定指派成员-意见反馈
+ const {collaborators} = result.data;
+ const id = collaborators.filter(item=>item.id === 86107);
+ setAssigner_choose(id.length === 0 ? [collaborators[0]] : id)
+ }
+ }
+ })
+ }
+ // 获取里程碑列表
+ useEffect(()=>{
+ getMillstone(millstone);
+ },[millstone])
+
+ function getMillstone(keyword){
+ const url = `/v1/${owner}/${projectsId}/milestones`;
+ axios.get(url,{params:{keyword,only_name:true}}).then(result=>{
+ if(result && result.data){
+ let milestones = result.data.milestones;
+ if(milepostId && milepostId === keyword){
+ setMillstone_choose(milestones);
+ }else{
+ setMillstoneList(milestones);
+ }
+ }
+ })
+ }
+ // 获取标记列表
+ useEffect(()=>{
+ getSign();
+ },[tag])
+ function getSign(){
+ const url = `/v1/${owner}/${projectsId}/issue_tags`;
+ axios.get(url,{params:{keyword:tag,only_name:true}}).then(result=>{
+ if(result && result.data){
+ setTagList(result.data.issue_tags);
+ }
+ })
+ }
+ // 获取标记列表
+ useEffect(()=>{
+ getBranch(branch);
+ },[branch])
+ function getBranch(branch){
+ if(branch){
+ let b = [...branchList];
+ let l = b.filter(i=>i.name.indexOf(branch)>-1);
+ setBranchList(l);
+ return ;
+ }
+ const url = `/${owner}/${projectsId}/branches.json`;
+ axios.get(url,{params:{keyword:tag}}).then(result=>{
+ if(result && result.data){
+ setBranchList(result.data);
+ }
+ })
+ }
+
+
+ // 创建
+ function createFunc(values,fileList,receivers_login,description){
+ const { subject } = values;
+ const url = `/v1/${owner}/${projectsId}/issues`;
+ let b = branch_choose && branch_choose.length>0 ? branch_choose.map(i=>{return i.name}) :undefined;
+ let t = tag_choose && tag_choose.length>0 ? tag_choose.map(i=>{return i.id}) :undefined;
+ let a = assigner_choose && assigner_choose.length>0 ? assigner_choose.map(i=>{return i.id}) :undefined;
+ let m = millstone_choose && millstone_choose.length>0 ? millstone_choose.map(i=>{return i.id}) :undefined;
+ let p = prioritie_choose && prioritie_choose.length>0 ? prioritie_choose.map(i=>{return i.id}) :undefined;
+ let s = status_choose && status_choose.length>0 ? status_choose.map(i=>{return i.id}) :undefined;
+ axios.post(url,{
+ description,subject,
+ branch_name:b && b.join(","),
+ status_id:s && s.join(","),
+ priority_id:p && p.join(","),
+ milestone_id:m && m.join(","),
+ issue_tag_ids:t,
+ assigner_ids:a,
+ attachment_ids:fileList,
+ start_date,due_date,receivers_login,
+ blockchain_token_num:rewardAmount,
+ test_case:caseValue
+ }).then(result=>{
+ if(result && result.data && result.data.project_issues_index){
+ window.scrollTo(0,0);
+ props.showNotification("任务创建成功!");
+ props.history.push(`/${owner}/${projectsId}/issues/${result.data.project_issues_index}`);
+ }
+ }).catch(error=>{})
+ }
+
+
+ function changeAmount(value){
+ if(value && value > 0){
+ setRewardAmount(value);
+ }
+ if(!value){
+ setRewardAmount(value);
+ }
+ }
+ return(
+
+
新建疑修
+
+
+ {/* 意见反馈初始化内容 */}
+
+
+
+
{setCharge(value)}}
+ headImg
+ selectValueList={assigner_choose}
+ chooseFunc={(list)=>{setAssigner_choose(list);}}
+ double={5}
+ removeFlag
+ />
+ {setStatus_choose(list);}}
+ />
+ {setPrioritie_choose(list);}}
+ />
+ {setTag(value)}}
+ selectValueList={tag_choose}
+ chooseFunc={(list)=>{setTag_choose(list);}}
+ double={3}
+ colorFlag="2"
+ removeFlag
+ onAdd={permission && permission !== "Reporter" ? ()=>{getSign();} :false}
+ owner={owner}
+ projectsId={projectsId}
+ />
+ {setMillstone(value)}}
+ selectValueList={millstone_choose}
+ editFlag={milepostId ? true : false}
+ chooseFunc={(list)=>{setMillstone_choose(list);}}
+ />
+ {setBranch(value)}}
+ selectValueList={branch_choose}
+ chooseFunc={(list)=>{setBranch_choose(list);}}
+ />
+ {
+ open_blockchain &&
+
+
+ 悬赏金额
+ {/* {!(milepostId ? true : false) && } */}
+
+
+
+ }
+ {console.log("case:",v);setCaseValue(v)}}/>
+ setStartDate(date)}/>
+ setDueDate(date)}/>
+
+
+
+ )
+}
+export default Form.create()(forwardRef(New));
\ No newline at end of file
diff --git a/src/forge/Issues/Pages/sign.jsx b/src/forge/Issues/Pages/sign.jsx
new file mode 100644
index 000000000..be3abaf0e
--- /dev/null
+++ b/src/forge/Issues/Pages/sign.jsx
@@ -0,0 +1,267 @@
+import React , { useEffect , useState } from 'react';
+import create from '../Img/create.png';
+import { Menu , Dropdown , Icon, Input, Button , Spin , Pagination } from 'antd';
+import ColorCard from '../Component/colorCard';
+import DelBox from '../Component/delBox';
+import axios from 'axios';
+import {Link} from 'react-router-dom';
+const limit = 15;
+function Sign(props){
+ const [ edit , setEdit ] = useState(false);
+ const [ colors , setColors ] = useState(undefined);
+ const [ delVisible , setDelVisible ] = useState(false);
+ const [ editId , setEditId ] = useState(undefined);
+ const [ list , setList ] = useState(undefined);
+ const [ total , setTotal ] = useState(undefined);
+ const [ page , setPage ] = useState(1);
+
+ const [ name , setName ] = useState(undefined);
+ const [ desc , setDesc ] = useState(undefined);
+ const [ order_name , setOrderName ] = useState(undefined);
+ const [ order_type , setOrderType ] = useState(undefined);
+ const [ nameFlag , setNameFlag ] = useState(undefined);
+ const [ defaultColor , setDefaultColor ]= useState(undefined);
+
+ const [ arrayName , setArrayName ] = useState("标记");
+ const [ key , setKey ] = useState("0");
+ const owner = props.match.params.owner;
+ const projectsId = props.match.params.projectsId;
+ const { projectDetail } = props;
+ const permission = projectDetail && props.projectDetail.permission;
+
+
+ useEffect(()=>{
+ if(permission !== undefined){
+ if(!permission || (permission && permission === "Reporter")){
+ window.location.href = "/403";
+ }
+ }
+ },[permission])
+
+ useEffect(()=>{
+ if(projectDetail){
+ const { author, name } = projectDetail;
+ document.title = `项目标记-${author.name}/${name}`;
+ }
+ },[projectDetail])
+
+ useEffect(()=>{
+ Init();
+ },[page,order_name,order_type])
+
+ function Init(){
+ const url = `/v1/${owner}/${projectsId}/issue_tags`;
+ axios.get(url,{
+ params:{
+ page,limit,sort_by:order_name,sort_direction:order_type
+ }
+ }).then(result=>{
+ if(result && result.data){
+ setList(result.data.issue_tags);
+ setTotal(result.data.total_count);
+ }
+ })
+ }
+
+ function arrayList(e){
+ const { eventKey , value , children , createName } = e.item.props;
+ setPage(1);
+ if(value === order_type && createName === order_name){
+ setOrderName(undefined);
+ setOrderType(undefined);
+ setArrayName("标记");
+ setKey("0");
+ }else{
+ setOrderName(createName);
+ setOrderType(value);
+ setArrayName(children);
+ setKey(eventKey);
+ }
+ }
+
+ const menu = (
+
+ );
+
+ function getColor(colors){
+ setColors(colors);
+ }
+
+ function deleteFunc(){
+ if(editId){
+ const url = `/v1/${owner}/${projectsId}/issue_tags/${editId}`;
+ axios.delete(url).then(result=>{
+ if(result){
+ props.showNotification("项目标记删除成功!");
+ if(list && list.length === 1 && page>1){
+ setPage(page-1);
+ }else{
+ Init();
+ }
+ setDelVisible(false);
+ }
+ }).catch(error=>{})
+ }
+ }
+
+ function sureSave(){
+ if(!name){
+ setNameFlag(true);
+ }else{
+ setNameFlag(false);
+ if(editId){
+ // 编辑
+ const url = `/v1/${owner}/${projectsId}/issue_tags/${editId}`;
+ axios.patch(url,{
+ color: colors || defaultColor,
+ description: desc,
+ name
+ }).then(result=>{
+ if(result){
+ props.showNotification("标记编辑成功!");
+ Init();
+ cancel();
+ }
+ }).catch(error=>{})
+ }else{
+ // 保存
+ const url = `/v1/${owner}/${projectsId}/issue_tags`;
+ axios.post(url,{
+ color: colors || defaultColor,
+ description: desc,
+ name
+ }).then(result=>{
+ if(result){
+ props.showNotification("标记新增成功!");
+ Init();
+ cancel();
+ }
+ }).catch(error=>{})
+ }
+ }
+ }
+
+ function cancel(){
+ setNameFlag(false);
+ setName(undefined);
+ setEdit(false);
+ setDesc(undefined);
+ }
+
+ function editFunc(i){
+ setEditId(i.id);
+ setDefaultColor(i.color);
+ setName(i.name);
+ setDesc(i.description);
+ setEdit(true);
+ }
+
+ function onChangeValue(e){
+ setName(e.target.value);
+ if(e.target.value){
+ setNameFlag(false);
+ }else{
+ setNameFlag(true);
+ }
+ }
+
+ function createSign(){
+ const c = Math.random().toString(16).substr(-6);
+ c && setDefaultColor(`#${c}`);
+ setEdit(true);
+ }
+ return(
+
+
setDelVisible(false)}
+ onSuccess={deleteFunc}
+ title="删除标记"
+ content={}
+ />
+
+
疑修 / 项目标记
+
创建标记
+
+ {
+ edit &&
+
+
+
+ { nameFlag &&
请输入标记名称
}
+
+
setDesc(e.target.value)} placeholder="描述30字以内"/>
+
+
+
+
+
+
+ }
+
+ 项目标记({total || 0})
+
+ {arrayName}
+
+
+ {
+ list && list.length > 0 ?
+
+ :""
+ }
+ {
+ total > limit &&
+
+
setPage(p)} pageSize={limit}/>
+
+ }
+ {total === undefined &&
}
+
+ )
+}
+export default Sign;
\ No newline at end of file
diff --git a/src/forge/Issues/index.jsx b/src/forge/Issues/index.jsx
new file mode 100644
index 000000000..a3bb5dfd4
--- /dev/null
+++ b/src/forge/Issues/index.jsx
@@ -0,0 +1,80 @@
+import React,{useEffect} from 'react';
+import { Route, Switch } from "react-router-dom";
+import Loadable from "react-loadable";
+import Loading from "../../Loading";
+import './index.scss';
+
+const List = Loadable({
+ loader: () => import("./Pages/list"),
+ loading: Loading,
+});
+const Detail = Loadable({
+ loader: () => import("./Pages/details"),
+ loading: Loading,
+});
+const Sign = Loadable({
+ loader: () => import("./Pages/sign"),
+ loading: Loading,
+});
+const New = Loadable({
+ loader: () => import("./Pages/new"),
+ loading: Loading,
+});
+
+function Index(props){
+ const pathname = props.history.location.pathname;
+ const { project } = props;
+ const open_blockchain = project && project.open_blockchain;
+
+ useEffect(() => {
+ if (document) { // 可以排除不需要置顶的页面
+ if (document.documentElement || document.body) {
+ document.documentElement.scrollTop = document.body.scrollTop = 0; // 切换路由时手动置顶
+ }
+ }
+ }, [pathname]);
+ return(
+
+
+ (
+
+ )}
+ >
+ {/* 里程碑创建issue */}
+ (
+
+ )}
+ >
+ (
+
+ )}
+ >
+ (
+
+ )}
+ >
+ (
+
+ )}
+ >
+ (
+
+ )}
+ >
+
+
+ )
+}
+export default Index;
\ No newline at end of file
diff --git a/src/forge/Issues/index.scss b/src/forge/Issues/index.scss
new file mode 100644
index 000000000..7a5541822
--- /dev/null
+++ b/src/forge/Issues/index.scss
@@ -0,0 +1,870 @@
+.borderNo.ant-input,.borderNo .ant-input-number-input,.borderNo,.borderNo.ant-input-number-focused{
+ border:none!important;
+ padding:4px 0px!important;
+ background-color: transparent!important;
+ box-shadow: none!important;
+ .ant-input-number-handler-wrap{
+ display: none;
+ }
+ &:focus{
+ border:none!important;
+ box-shadow: none!important;
+ }
+}
+
+.pagebox{
+ width: 1200px;
+ margin:0px auto;
+}
+// 删除issue弹框
+.deldesc{
+ justify-content: center;
+ .red{
+ color: #DF0002;
+ }
+}
+// 可公用样式(在issue的页面中)
+// 可点击(有向下箭头且点击出现下拉框,移入灰色背景加深)的灰色按钮样式
+.dorpdownButton{
+ padding:0px 15px;
+ height:32px;
+ color: #333333!important;
+ cursor: pointer;
+ line-height: 32px;
+ background-color:#fafbfc;
+ border:1px solid #d0d0d0;
+ border-radius: 4px;
+ display: flex;
+ align-items: center;
+ min-width: 107px;
+ box-sizing: border-box;
+ &>span{
+ display: block;
+ width: 56px;
+ text-align: center;
+ }
+ &:hover{
+ background-color: #f3f4f6;
+ }
+}
+// flex-左右,上下居中
+.between{
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+// 蓝色背景操作栏
+.bluebar{
+ height:50px;
+ background-color:#fafcff;
+ border:1px solid rgba(42, 97, 255, 0.23);
+ border-radius:4px 4px 0px 0px;
+ padding:0px 26px;
+}
+// 按钮样式
+.ant-btn-background-ghost{
+ border-color:#acb0bf;
+ color: #acb0bf;
+ background-color: #fff!important;
+ &.ant-btn-primary{
+ color: #466aff;
+ border-color: #466aff;
+ background-color: #fff!important;
+ }
+ &.ant-btn-danger{
+ color: #f60011;
+ border-color: #f60011;
+ background-color:rgba(196, 0, 14, 0.09)!important;
+ }
+}
+.lists{
+ margin-bottom: 50px;
+}
+.dataempty{
+ height: 420px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border: 1px solid;
+ border-color: #d9d9d9;
+ border-radius: 0px 0px 4px 4px;
+ border-top: none;
+}
+// 列表为空样式
+.listempty{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ background-color:#fafcff;
+ border:1px solid rgba(42, 97, 255, 0.23);
+ border-top: none;
+ border-radius:0px 0px 4px 4px;
+ height: 344px;
+ padding-top: 62px;
+ color: #333;
+}
+// 列表页面样式
+.pageheader{
+ display: flex;
+ justify-content: space-between;
+ padding:30px 0px;
+ align-items: center;
+ &>div{
+ display: flex;
+ align-items: center;
+ }
+}
+.listheader{
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ height:50px;
+ background-color:#fafcff;
+ border:1px solid;
+ border-color:rgba(42, 97, 255, 0.23);
+ border-radius:4px 4px 0px 0px;
+ padding-left: 18px;
+ .menusul{
+ display: flex;
+ align-items: center;
+ }
+ ul{
+ display: flex;
+ align-items: center;
+ &.statusul{
+ li{
+ width: 106px;
+ font-size: 15px;
+ &>span{
+ height:19px;
+ line-height: 17px;
+ color: #666;
+ background-color:rgba(70, 106, 255, 0.09);
+ border-radius:10px;
+ margin-left: 5px;
+ padding:0px 6px;
+ font-size: 13px;
+ display: block;
+ border:1px solid ;
+ border-color: rgba(70, 106, 255, 0.01);
+ min-width: 30px;
+ text-align: center;
+ }
+ }
+ }
+ li{
+ color: #898d9d;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ &.active{
+ color: #466aff;
+ // font-weight: 500;
+ &>span{
+ font-weight: normal;
+ color: #466aff;
+ border-color: #466aff;
+ background-color: #fff;
+ }
+ }
+ }
+ }
+ .dropboxul{
+ padding-right: 20px;
+ li.minwidth{
+ min-width: 70px;
+ }
+ li{
+ min-width:88px;
+ display: flex;
+ justify-content: flex-end;
+ cursor: default;
+ margin-left: 12px;
+ .dropspan{
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ &>span{
+ max-width: 80px;
+ display: inline-block;
+ text-align: right;
+ }
+ }
+ }
+ }
+
+}
+// issue列表
+.listdatas{
+ border:1px solid #d0d0d0;
+ border-top: none;
+ border-radius: 0px 0px 2px 2px;
+ &>div:not(.none_panels){
+ padding:20px 18px;
+ border-bottom: 1px solid #eee;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ &:hover{
+ background-color:rgba(231, 233, 242, 0.26);
+ }
+ &:last-child{
+ border-bottom: none;
+ }
+ .issuedetail{
+ display: flex;
+ align-items: flex-start;
+ flex:1;
+ }
+ }
+ .idetails{
+ display: flex;
+ align-items: center;
+ &>a{
+ color: #40424a;
+ margin-right: 10px;
+ font-size: 15px;
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 375px;
+ white-space: nowrap;
+ }
+ .tagscolor{
+ padding:0px 6px;
+ border-radius: 2px;
+ height: 20px;
+ line-height: 20px;
+ max-width: 108px;
+ font-size: 13px;
+ cursor: default;
+ color: #fff;
+ }
+ }
+ .infos{
+ display: flex;
+ align-items: center;
+ color: #898d9d;
+ margin-top: 12px;
+ font-size: 13px;
+ // img{
+ // height: 22px;
+ // width: 22px;
+ // margin-right: 4px;
+ // border-radius: 50%;
+ // }
+ }
+ .issuecondition{
+ display: flex;
+ align-items: center;
+ color: #40424a;
+ .principal{
+ position: relative;
+ display: flex;
+ justify-content: flex-end;
+ width: 150px;
+ text-align: justify;
+ // &.hovers:hover{
+ // a{
+ // position:initial;
+ // }
+ // }
+ // a{
+ // position: absolute;
+ // right: 0px;
+ // transition: 0.6s;
+ // }
+ // img,span{
+ // width: 22px;
+ // height: 22px;
+ // border-radius: 50%;
+ // }
+ // span{
+ // background-color:#ced5ef;
+ // text-align: center;
+ // line-height: 12px;
+ // color:#000000;
+ // z-index: 6;
+ // }
+ }
+ &>div{
+ width: 90px;
+ text-align: right;
+ }
+ .commentnum{
+ padding-right: 5px;
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ }
+ }
+}
+// 状态样式-公用
+
+.status{
+ display: block;
+ height:22px;
+ border-radius:6px;
+ text-align: center;
+ margin-right: 10px;
+ line-height: 20px;
+ width: 45px;
+ font-size: 14px;
+ border:1px solid #fff;
+ &.normals{
+ border-color:#28be6c;
+ color:#28be6c;
+ }
+ &.hight{
+ border-color: #e67e22;
+ color: #e67e22;
+ }
+ &.urgent{
+ border-color: #db3d1d;
+ color: #db3d1d;
+ }
+ &.low{
+ border-color: #1abcb1;
+ color: #1abcb1;
+ }
+}
+.ilog{
+ min-width: 45px;
+ margin-right: 10px;
+ clear: both;
+ .number{
+ background-color:rgba(213, 220, 246, 0.36);
+ border-radius:4px;
+ height: 19px;
+ line-height: 19px;
+ color: #666666;
+ text-align: center;
+ float: left;
+ padding:0px 4px;
+ cursor: pointer;
+ font-size: 13px;
+ }
+}
+// colorCard
+.color{
+ width: 20px;
+ height: 20px;
+ border-radius: 2px;
+}
+.swatch{
+ padding: 5px;
+ background: #fff;
+ border-radius: 1px;
+ width: 92px;
+ height: 28px;
+ line-height: 20px;
+ box-shadow: 0 0 0 1px rgba(0,0,0,.1);
+ display: flex;
+ cursor: pointer;
+}
+.popover {
+ position: absolute;
+ z-index: 2;
+}
+.cover {
+ position: fixed;
+ top: 0px;
+ right: 0px;
+ bottom: 0px;
+ left: 0px;
+}
+.modalcolor {
+ width: 20px;
+ height: 20px;
+ border-radius: 2px;
+}
+// 标记管理页面
+.editbar{
+ padding:18px 20px;
+ background-color:rgba(218, 225, 251, 0.24);
+ display: flex;
+ align-items: center;
+ margin-bottom: 30px;
+ justify-content: space-between;
+ &>div{
+ position: relative;
+ .inputred{
+ border-color: red;
+ }
+ .red{
+ position: absolute;
+ left: 166px;
+ width: 100%;
+ top: 2px;
+ color: red;
+ }
+ }
+}
+.signlist{
+ padding:10px 0px;
+ margin-bottom: 40px!important;
+ &>li{
+ display: flex;
+ margin-bottom: 5px;
+ padding:10px 20px;
+ &>p{
+ flex:1;
+ color: 40424a;
+ &:first-child{
+ flex:1.2;
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ }
+ &:last-child{
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ justify-content: flex-end;
+ }
+ .square{
+ display: block;
+ width: 22px;
+ height: 15px;
+ border-radius:2px;
+ }
+ .line{
+ position: relative;
+ padding-left: 13px;
+ &::before{
+ position: absolute;
+ height:13px;
+ width: 1px;
+ left: 0px;
+ top:7px;
+ background-color:#d5d5d5;
+ content: "";
+ }
+ }
+ }
+ }
+}
+// 新建页面样式
+.shortwidth{
+ width: 330px;
+ padding-left: 50px;
+ &>li{
+ border-bottom: 1px solid rgba(172, 176, 191, 0.17);
+ padding-bottom: 8px;
+ margin-bottom: 22px!important;
+ &>span{
+ font-size: 15px;
+ position: relative;
+ color: #40424a;
+ display: flex;
+ width: 100%;
+ height: 20px;
+ line-height: 20px;
+ font-weight: 600;
+ a{
+ position: absolute;
+ right: 0px;
+ }
+ }
+ .operatevalue{
+ line-height: 30px;
+ color: #acb0bf;
+ margin-top: 10px;
+ display: flex;
+ flex-wrap: wrap;
+ .colorsborder{
+ padding: 0px 8px;
+ height: 20px;
+ line-height: 18px;
+ border-radius: 4px;
+ text-align: center;
+ border:1px solid ;
+ font-size: 13px;
+ }
+ .colorsquare{
+ padding: 0px 8px;
+ height: 20px;
+ line-height: 20px;
+ border-radius: 4px;
+ text-align: center;
+ color: #fff;
+ font-size: 13px;
+ }
+ &>p{
+ margin-top: 5px!important;
+ position: relative;
+ padding-right: 15px;
+ &.removeFlag>span{
+ max-width: 230px;
+ }
+ .removeicon{
+ display: none;
+ }
+ }
+ .removeFlag:hover{
+ border-radius:2px;
+ .removeicon{
+ display: block;
+ }
+ }
+ &>p:first-child{
+ margin-top: 0px;
+ }
+ }
+ }
+}
+.addTags_form{
+ .ant-row.ant-form-item{
+ margin-bottom: 12px;
+ }
+ .manageTitle{
+ margin-bottom: 20px!important;
+ padding-bottom: 15px;
+ line-height: 22px;
+ color:#5f6872;
+ font-size:16px;
+ border-bottom:1px solid #e1e3e8;
+ }
+ .inline{
+ display: flex;
+ align-items: flex-start;
+ }
+}
+.addTagsModal{
+ .ant-modal-content{
+ background-image:linear-gradient(359.37deg,#ebf3ff 0%,#f8fbff 55.01%,#f1f5ff 100%);
+ }
+ .ant-modal-header{
+ background-color: unset;
+ padding:0px 24px;
+ height: 50px;
+ line-height: 50px;
+ .ant-modal-title{
+ text-align: left;
+ color:#333333;
+ font-size:17px;
+ font-weight: normal!important;
+ height: 50px;
+ line-height: 50px!important;
+ }
+ }
+ .ant-modal-close{
+ top:0px !important;
+ }
+ .popover{
+ left: 94px;
+ top:0px;
+ }
+}
+.menusEmpty{
+ padding:12px 20px 10px 16px;
+ &>p{
+ padding:10px 16px;
+ }
+ &>a{
+ padding:10px 16px;
+ display: block;
+ border-top: 1px solid rgba(172, 176, 191, 0.17);
+ }
+}
+.piecemenu{
+ li{
+ display: flex;
+ align-items: center;
+ }
+}
+.colorpiece{
+ display: block;
+ width: 22px!important;
+ height: 15px;
+ margin-right: 9px;
+ border-radius:2px;
+}
+.overlayStyle{
+ background-color:#ffffff;
+ border-radius:6px;
+ box-shadow:0px 0px 10px rgba(24, 54, 181, 0.17);
+ max-width: 280px;
+ z-index: 100;
+ .searchbox{
+ padding:12px 20px 0px 16px;
+ }
+ .ant-menu{
+ padding:10px 16px 10px 16px;
+ max-height: 324px;
+ overflow-y: auto;
+ li{
+ padding:0px 16px;
+ height: 38px;
+ line-height: 38px;
+ border-bottom: none;
+ color:#898d9d;
+ position: relative;
+ width: 100%;
+ box-sizing: border-box;
+ &:hover,&.ant-menu-item-selected{
+ background-color:rgba(70, 106, 255, 0.07);
+ color:#40424a;
+ }
+ &.ant-menu-item-selected::before{
+ content:"✓";
+ position: absolute;
+ right: 15px;
+ color: #acb0bf;
+ top: 0px;
+ }
+ }
+ }
+}
+//详情页面
+.editpanel{
+ padding:20px;
+ margin-top: 25px;
+ border:1px solid rgba(42, 97, 255, 0.23);
+ border-radius: 2px;
+}
+.detailbanner{
+ // margin-top: 25px;
+ // height:82px;
+ // background-color:#fafcff;
+ // border:1px solid rgba(42, 97, 255, 0.23);
+ // border-radius:4px;
+ // padding:12px 25px 12px 20px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ .detailtitle{
+ flex: 1;
+ &>div{
+ display: flex;
+ align-items: flex-start;
+ }
+ .name{
+ font-size: 16px;
+ font-weight: 700;
+ color:#333;
+ line-height: 22px;
+ max-width: 580px;
+ word-break: break-all;
+ }
+ .author{
+ img{
+ width: 26px;
+ height: 26px;
+ margin-right: 4px;
+ border-radius: 50%;
+ }
+ color: #466aff;
+ }
+ }
+ .detailoperate{
+ display: flex;
+ align-items: center;
+ }
+}
+.descPanel{
+ margin-top:30px;
+ // padding:20px;
+ // background-color: #f7f8fd;
+ // border:1px solid #c9d8ff;
+ // border-radius: 2px;
+}
+// 新建页面
+.explain{
+ .ant-form-explain{
+ position: absolute;
+ }
+}
+
+
+.overlaydrop{
+ &.large{
+ width: 260px;
+ }
+ &.small{
+ width: 120px;
+ padding:12px 0px!important;
+ }
+ padding:18px 15px;
+ position: relative;
+ border-radius:6px;
+ box-shadow:0px 0px 10px rgba(24, 54, 181, 0.17);
+ background-color: #fff;
+ .ant-menu{
+ max-height: 305px;
+ overflow-y: auto;
+ li{
+ height: 38px;
+ line-height: 38px;
+ border-bottom: none!important;
+ display: flex;
+ align-items: center;
+ padding-left: 6px;
+ padding-right: 0px;
+ img{
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ }
+ span{
+ display: block;
+ width:100%;
+ margin-left: 10px;
+ padding-right: 25px;
+ }
+ &:hover,&.ant-menu-item-selected{
+ background-color:rgba(70, 106, 255, 0.07);
+ color:#40424a;
+ }
+ &.ant-menu-item-selected::before{
+ content:"✓";
+ position: absolute;
+ right: 15px;
+ color: #acb0bf;
+ top: 0px;
+ }
+ }
+ }
+}
+
+// 声明
+.claimpart{
+ padding-bottom: 15px;
+ border-bottom: 1px solid #eee;
+ margin-bottom: 20px;
+}
+
+// issue版本2
+.overlayChooseStyle{
+ width: 636px;
+ background-color:#ffffff;
+ border-radius:6px;
+ box-shadow:0px 0px 10px rgba(24, 54, 181, 0.17);
+ z-index: 100;
+ padding:30px 20px;
+ .choosedul{
+ display: flex;
+ flex-wrap: wrap;
+ padding-bottom: 10px;
+ border-bottom: 1px solid #e4e4e6;
+ margin-bottom: 20px!important;
+ li{
+ height:24px;
+ background-color:#eff2ff;
+ border:1px solid;
+ border-color:#466aff;
+ border-radius:2px;
+ color:#466aff;
+ font-size:14px;
+ margin-right: 15px;
+ margin-bottom: 10px!important;
+ padding:0px 7px;
+ display: flex;
+ align-items: center;
+ span{
+ display: block;
+ max-width:120px ;
+ }
+ }
+ }
+ .counttips{
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ }
+ .ant-menu{
+ display: flex;
+ flex-wrap: wrap;
+ padding:20px 0px 5px 0px;
+ box-sizing: border-box;
+ max-height: 307px;
+ overflow-y: auto;
+ &.piecemenu li{
+ width: auto;
+ &>span{
+ display: flex;
+ }
+ span.task-hide{
+ max-width: unset;
+ }
+ &:nth-child(5n){
+ margin-right: 24px!important;
+ }
+ }
+ li{
+ width: 98px;
+ height:32px;
+ line-height:30px;
+ text-align: center;
+ font-size:14px;
+ border-radius:2px;
+ margin-right: 24px!important;
+ margin-bottom: 15px!important;
+ border:1px solid!important;
+ border-color: #f4f6fe!important;
+ padding:0px 5px;
+ &.commonli{
+ background-color:#f4f6fe!important;
+ }
+ .removeicon{
+ display: block;
+ }
+ span.task-hide{
+ color: #3f455b;
+ margin:0px auto;
+ position: relative;
+ color:#3f455b;
+ max-width: 80px;
+ display: inline-block;
+ }
+ span{
+ position: relative;
+ margin:0px auto;
+ }
+ &.colorli{
+ border-color: transparent!important;
+ span{
+ color: #fff;
+ position: relative;
+ margin:0px auto;
+ }
+ }
+ &.commonli.ant-menu-item-selected{
+ background-color:#e2e8ff!important;
+ color:#3f5097;
+ border-color:#466aff!important;
+ }
+ &.colorli.ant-menu-item-selected{
+ border-color: transparent!important;
+ }
+ &.colorli.ant-menu-item-selected{
+ &>span::before{
+ content:"✓";
+ position: absolute;
+ right: -12px;
+ color: #fff;
+ top: -16px;
+ }
+ }
+ &:nth-child(5n){
+ margin-right: 0px!important;
+ }
+ }
+ }
+}
+
+.boxStyles{
+ margin-top: 10px!important;
+ width: 100%;
+ input,input[class~="ant-input"]:focus{
+ border:none!important;
+ padding:0px;
+ }
+ div[class~='ant-select-selection__placeholder']{
+ margin-left: 0px!important;
+ margin-right: 0px!important;
+ }
+ span[class~='ant-select-arrow']{
+ opacity: 0;
+ }
+}
\ No newline at end of file
diff --git a/src/forge/Main/Detail.js b/src/forge/Main/Detail.js
index 213d891c8..e52be3a40 100644
--- a/src/forge/Main/Detail.js
+++ b/src/forge/Main/Detail.js
@@ -32,7 +32,7 @@ const OrderDetail = Loadable({
loading: Loading,
})
const OrderIndex = Loadable({
- loader: () => import('../Order/order'),
+ loader: () => import('../Issues/index'),
loading: Loading,
})
const CoderRootIndex = Loadable({
@@ -93,7 +93,7 @@ const UpdateMerge = Loadable({
})
const MilepostDetail = Loadable({
- loader: () => import('../Order/MilepostDetail'),
+ loader: () => import('../Order/MilepostDetail.jsx'),
loading: Loading,
})
const WatchUsers = Loadable({
@@ -711,11 +711,11 @@ class Detail extends Component {
}
>
{/* 标签列表 */}
- ()
}
- >
+ > */}
{/* 仓库设置 */}
{/*里程碑详情*/}
- ()
}
@@ -748,36 +748,36 @@ class Detail extends Component {
}
>
{/* 里程碑页面新建任务 */}
- ()
}
- >
+ > */}
{/* 新建任务 */}
- ()
}
- >
+ > */}
{/* 修改详情 edit*/}
- ()
}
- >
+ > */}
{/* 复制详情 copyetail*/}
- ()
}
- >
+ > */}
{/* 任务详情 */}
- ()
}
- >
+ > */}
{/* 动态 */}
{
- getList();
- },[])
+ // getList();
+ const url = `/v1/${owner}/${projectsId}/branches.json`;
+ Axios.get(url,{
+ params:{
+ keyword: name,
+ page: current,
+ limit: pageSize
+ }
+ }).then(result=>{
+ if(result){
+ const {branches, total_count} = result.data;
+ setTotal(total_count)
+ setList(branches);
+ setNewFormBranchName(branches[0].name);
+ }
+ setIsSpin(false);
+ }).catch(error=>{setIsSpin(false);})
+ },[name, reload, pageSize, current])
+
+ useEffect(()=>{
+ if(projectDetail && document.title.indexOf('所有分支-') === -1){
+ const { author, name} = projectDetail;
+ document.title = `所有分支-${author.name}/${name}`;
+ }
+ }, [projectDetail])
const menu =(zip_url,tar_url)=> (
@@ -29,6 +66,105 @@ function Index(props) {
)
+ const columns = [
+ {
+ title: "分支名称",
+ dataIndex: "name",
+ key: 1,
+ ellipsis: true,
+ className: "branchNameColumn",
+ render: (txt, item) => {
+ return (
+ {window.scrollTo(0,0)}} className="task-hide">{txt}
+ )
+ }
+ },
+ {
+ title: "更新信息",
+ dataIndex: "commit",
+ key: 3,
+ ellipsis: true,
+ width: "240px",
+ render: (txt, item) => {
+ return (
+
+ {
+ txt && txt.committer && txt.committer.id?
+
+

+
{txt && txt.committer && txt.committer.name}
+
+ :
+
+
+ {txt && txt.committer && txt.committer.name}
+
+ }
+
更新于{txt && txt.time_ago}
+
+ )
+ }
+ },
+ {
+ title: "commit信息",
+ dataIndex: "commit_id",
+ key: 4,
+ ellipsis: true,
+ width: "250px",
+ render: (txt, item) => {
+ return
+ }
+ },
+ {
+ title: "分支类型",
+ dataIndex: "default_branch",
+ key: 5,
+ width: "150px",
+ render: (txt, item) => {
+ return isManager ? txt === item.name ? 默认分支 : : txt === item.name ? '默认分支' : '普通分支'
+ }
+ },
+ {
+ title: "操作",
+ dataIndex: "name",
+ key: 6,
+ align: "center",
+ width: "320px",
+ className: "branchActionColumn",
+ render: (txt, item) => {
+ return (
+
+ {
+ (isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) &&
+
+ 合并请求
+ }
+
+ 下载
+
+ {isManager && (txt === item.default_branch ?
:
)}
+
+ )
+ }
+ }
+ ];
+
function getList() {
const url = `/${owner}/${projectsId}/branches_slice.json`;
Axios.get(url).then(result=>{
@@ -39,10 +175,121 @@ function Index(props) {
}).catch(error=>{setIsSpin(false);})
}
+ // 删除分支确认函数
+ function deleteLabel(){
+ Axios.delete(`/v1/${owner}/${projectsId}/branches/${visible.name}.json`).then(res=>{
+ if(res && res.data){
+ if(current>1 && (list && list.length===1)){
+ setCurrent(current-1);
+ }else{
+ setReload(Math.random());
+ }
+ setVisible(false);
+ !res.data.status && message.success('删除成功');
+ }
+ })
+ }
+
+ // 新建分支确认函数
+ function createBranch(){
+ setNewBranchError(undefined);
+ if(!newBranchName){
+ setNewBranchError("请输入新建分支名称");
+ }else{
+ Axios.post(`/v1/${owner}/${projectsId}/branches.json`, {
+ new_branch_name: newBranchName,
+ old_branch_name: newFormBranchName
+ }).then(res=>{
+ if(res && res.data){
+ // 重新请求仓库详情接口,更新分支总数信息
+ getDetail();
+ setReload(Math.random());
+ setAddBranch(false);
+ message.success('新建分支成功');
+ }
+ })
+ }
+ }
+
+ // 新建分支名检查格式
+ function checkNewBranchName(e) {
+ setNewBranchError(undefined);
+ const value = e.target.value;
+ if (value) {
+ const str = '^*';
+ let reg = /\\/g;
+ if(reg.test(value)){
+ setNewBranchError('分支名不能包含下列任何字符:^ * \\ ');
+ }else{
+ for(var i=0;i -1){
+ setNewBranchError('分支名不能包含下列任何字符:^ * \\ ');
+ return;
+ }else{
+ setNewBranchName(e.target.value);
+ }
+ }
+ }
+ }
+ }
+
+ // 更新默认仓库分支
+ function updateDefaultBranch(value, info){
+ Axios.patch(`/v1/${owner}/${projectsId}/branches/update_default_branch.json`,{
+ name: info.name
+ }).then(res=>{
+ if(res && res.data){
+ getDetail();
+ setReload(Math.random());
+ !res.data.status && message.success('操作成功');
+ }
+ })
+ }
+
+ // 改变pagesize
+ function onShowSizeChange(current, pageSize){
+ window.scrollTo(0, 0);
+ setCurrent(1);
+ setPageSize(pageSize);
+ }
+
+ // 切换页数
+ function changePage(page, pageSize){
+ window.scrollTo(0, 0);
+ setCurrent(page);
+ }
+
+ // 新建分支按钮点击函数
+ function addBranchBtn(){
+ setAddBranch(true);
+ const url = `/v1/${owner}/${projectsId}/branches/all.json`;
+ Axios.get(url).then(result=>{
+ if(result){
+ setBranchList(result.data);
+ }
+ }).catch(error=>{console.log('error', error);})
+ }
+
return(
- {
+
+
{setCurrent(1);setName(value)}} allowClear/>
+
+ {isManager && 分支设置}
+ {(isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) && }
+
+
+
+ {/* {
list && list.length>0 && list.map((item,key)=>{
return(
@@ -86,7 +333,12 @@ function Index(props) {
{
(isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) &&
-
+ 合并请求
+
+ 合并请求
}
下载
@@ -101,11 +353,47 @@ function Index(props) {
)
})
- }
- {
- list && list.length === 0 &&
- }
+ } */}
+ {setVisible(false)}}
+ visible={Boolean(visible)}
+ width="456px"
+ btn={
+
+
+
+
+ }
+ >
+
+
+
确定删除{visible.name}分支?
+
+
+ {setAddBranch(false)}}
+ visible={addBranch}
+ width="388px"
+ footer={
+
+ }
+ className="createNewBranchModal"
+ >
+
+
分支名称
+
+
{newBranchError}
+
分支起点
+
+
+
)
}
diff --git a/src/forge/Main/tree/Index.scss b/src/forge/Main/tree/Index.scss
index f65a1c68f..1c31ea8f1 100644
--- a/src/forge/Main/tree/Index.scss
+++ b/src/forge/Main/tree/Index.scss
@@ -1,3 +1,98 @@
+.treeinfo{
+ .branchLastUpdateUserImage{
+ height: 20px;
+ width: 20px;
+ margin-right: 5px;
+ }
+}
+.f6_bor_but, .f6_bor_but:focus{
+ color:#f60011;
+ background-color:rgba(196, 0, 14, 0.09);
+ border:1px solid #f60011;
+ border-radius:5px;
+ &:hover{
+ color:#f60011;
+ background-color:rgba(196, 0, 14, 0.18);
+ border-color:#ff727c;
+ }
+ &:active{
+ color:#f60011;
+ background-color:rgba(196, 0, 14, 0.22);
+ border-color:#f60011;
+ }
+}
+.branchListTable{
+ .ant-table-thead > tr > th{
+ border-top: 1px solid rgba(42, 97, 255, 0.23);
+ border-bottom: 1px solid rgba(42, 97, 255, 0.23) !important;
+ background-color:#fafcff;
+ }
+ .ant-table-column-title{
+ color:#40424a;
+ }
+ .ant-table-thead > tr:first-child > th:last-child{
+ border-right: 1px solid rgba(42, 97, 255, 0.23);
+ }
+ .ant-table-thead > tr:first-child > th:first-child{
+ border-left: 1px solid rgba(42, 97, 255, 0.23);
+ }
+ .ant-table-tbody > tr > td{
+ border-color: #eeeeee;
+ padding: 18.5px 16px;
+ }
+ .branchNameColumn{
+ border-left: 1px solid #d0d0d0;
+ }
+ .branchActionColumn{
+ border-right: 1px solid #d0d0d0;
+ }
+ .task-hide{
+ color: $primary-color;
+ }
+ .ant-table-empty .ant-table-placeholder{
+ border-left: 1px solid #d0d0d0;
+ border-right: 1px solid #d0d0d0;
+ }
+}
+.branchListActionBox{
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin: 20px 0 30px;
+}
+.createNewBranchModal{
+ .ant-modal-title{
+ text-align: left;
+ color:#333333;
+ font-size:17px;
+ font-weight: normal !important;
+ }
+ .ant-modal-header{
+ border-bottom: none;
+ background-color:rgba(70, 106, 255, 0.05);
+ }
+ .ant-modal-close{right: 5px;}
+ .ant-modal-close-x{font-size: 26px;}
+ .ant-modal-footer{
+ border-top: none;
+ text-align: center;
+ padding-bottom: 53px;
+ }
+ .ant-modal-content{
+ background-image:linear-gradient(359.37deg,#ebf3ff 0%,#f8fbff 55.01%,#f1f5ff 100%);
+ }
+ .createBranchLabel{
+ color:#27282d;
+ margin-bottom: 12px;
+ }
+ .createBranchInput, .createBranchInput .ant-select-selection{
+ border-color:#9eaacb;
+ background-color: transparent !important;
+ }
+ .newBranchError{
+ color:#df0002;
+ }
+}
.branchSort{
font-weight: 500;
color: #333333;
@@ -49,14 +144,16 @@
}
.treecopy{
flex:1;
- display: flex;
- justify-content: center;
+ display: flex;
+ // justify-content: center;
+ &>div:not(.treeCopyBox){
+ position: relative;
+ }
&>div{
height: 32px;
background: #FAFBFC;
border-radius: 4px;
border: 1px solid #D0D0D0;
- position: relative;
z-index: 1;
display: flex;
align-items: center;
@@ -64,6 +161,7 @@
padding:0px 15px;
border-right: 1px solid rgba(153, 153, 153, 0.4);
height: 100%;
+ width: 140px;
img{
margin-right: 4px;
}
diff --git a/src/forge/Order/AmplifyImg.js b/src/forge/Order/AmplifyImg.js
index 568ac7f92..114fa7e6a 100644
--- a/src/forge/Order/AmplifyImg.js
+++ b/src/forge/Order/AmplifyImg.js
@@ -1,7 +1,7 @@
import React from 'react';
import { Modal } from 'antd';
-import './order.css';
+import './order.scss';
function AmplifyImg(props) {
return (
diff --git a/src/forge/Order/Detail.js b/src/forge/Order/Detail.js
index 4e6c92a29..e76c24451 100644
--- a/src/forge/Order/Detail.js
+++ b/src/forge/Order/Detail.js
@@ -1,4 +1,4 @@
-import React, { Component, useRef } from "react";
+import React, { Component } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
@@ -8,7 +8,7 @@ import Attachments from "../Upload/attachment";
import RenderHtml from "../../components/render-html";
import Comments from "../comments/comments";
import Claims from "../claims/claims"
-import "./order.css";
+import "./order.scss";
class Detail extends Component {
constructor(props) {
@@ -44,6 +44,20 @@ class Detail extends Component {
this.getDetail();
};
+ componentDidUpdate=()=>{
+ this.updateDocumentTitle();
+ }
+
+ // 更新网页标题
+ updateDocumentTitle(){
+ const {projectDetail} = this.props;
+ const {data} = this.state;
+ if(projectDetail && data){
+ const { author, name} = projectDetail;
+ document.title = `${data.subject}-疑修-${author.name}/${name}`;
+ }
+ }
+
getDetail = () => {
const { projectsId, orderId, owner } = this.props.match.params;
const url = `/${owner}/${projectsId}/issues/${orderId}.json`;
@@ -55,11 +69,6 @@ class Detail extends Component {
data: result.data,
isSpins: false
});
- const {projectDetail} = this.props;
- if(projectDetail){
- const { author, name} = projectDetail;
- document.title = `${result.data && result.data.subject}-疑修-${author.name}/${name}`;
- }
}
})
.catch((error) => {
diff --git a/src/forge/Order/Milepost.js b/src/forge/Order/Milepost.js
index a6f0c3cb6..e228dd452 100644
--- a/src/forge/Order/Milepost.js
+++ b/src/forge/Order/Milepost.js
@@ -1,54 +1,49 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
-import { Dropdown, Icon, Menu, Pagination, Typography, Popconfirm, Spin } from 'antd';
-import NoneData from '../Nodata';
+import { Dropdown, Icon, Menu, Pagination, Popconfirm, Spin, Button, Tooltip } from 'antd';
+import emp from '../../forge/Issues/Img/emp.png';
import axios from 'axios';
-import './order.css';
-import CheckProfile from '../Component/ProfileModal/Profile';
-
-const { Text } = Typography;
-
+import './milepost.scss';
class Milepost extends Component {
constructor(props) {
super(props);
this.state = {
data: undefined,
- limit: 15,
+ limit: 10,
page: 1,
order_type: undefined,
- //新建标签区域是否显示 none 隐藏 block 显示
- display: 'none',
+ // 里程碑 开启/关闭 状态
status: 'open',
- openselect: 1,
- closeselect: undefined,
order_name: undefined,
-
- spinings: true
+ spinings: true,
+ // tooltip显隐
+ visible: false
}
}
+ componentDidUpdate(){
+ this.updateDocumentTitle();
+ }
componentDidMount = () => {
- this.getList(1, this.state.status, 'desc');
- }
- componentDidUpdate = () => {
+ this.getList(1, this.state.limit, this.state.status);
this.updateDocumentTitle();
}
+
// 更新网页标题
updateDocumentTitle(){
const {projectDetail} = this.props;
if(projectDetail){
const { author, name} = projectDetail;
- document.title = `新建合并请求-${author.name}/${name}`;
+ document.title = `里程碑-${author.name}/${name}`;
}
}
- getList = (page, status, order_type, order_name) => {
+ getList = (page, limit, category, sort_by, sort_direction) => {
const { projectsId ,owner } = this.props.match.params;
- const { limit } = this.state;
- const url = `/${owner}/${projectsId}/milestones.json`;
+ const url = `/v1/${owner}/${projectsId}/milestones.json`;
axios.get(url, {
params: {
- projectsId, page, limit, status, order_type, order_name
+ page, limit: limit, category, sort_by, sort_direction
}
}).then((result) => {
if (result) {
@@ -63,45 +58,24 @@ class Milepost extends Component {
}
opneMilelist = (type) => {
- const { order_name } = this.state;
if (type) {
- const { current_user } = this.props;
- if (type === 1) {
- this.setState({
- status: 'open',
- openselect: current_user.user_id,
- closeselect: undefined,
-
- })
- this.getList(1, 'open', 'desc', order_name);
- } else {
- this.setState({
- status: 'closed',
- openselect: undefined,
- closeselect: current_user.user_id
- })
- this.getList(1, 'closed', 'desc', order_name);
- }
+ this.setState({
+ status: type === 1 ? 'open' : 'closed'
+ })
+ this.getList(1, this.state.limit, type === 1 ? 'open' : 'closed', this.state.order_name, this.state.order_type);
}
-
}
updatestatusemile = (status, arr) => {
const { projectsId , owner } = this.props.match.params;
const url = `/${owner}/${projectsId}/milestones/${arr.id}/update_status.json`;
- const { current_user } = this.props;
axios.post(url, {
project_id: projectsId,
id: arr.id,
status: status
}).then(result => {
if (result) {
- this.setState({
- status: status,
- closeselect: status === "closed" ? current_user.user_id : undefined,
- openselect: status === "closed" ? undefined : current_user.user_id
- })
- this.getList(1, status, 'desc');
+ this.getList(1, this.state.limit, this.state.status, this.state.order_name, this.state.order_type);
const { getDetail } = this.props;
getDetail && getDetail();
}
@@ -120,7 +94,7 @@ class Milepost extends Component {
}
}).then((result) => {
if (result) {
- this.getList(1, this.state.status, 'desc');
+ this.getList(1, this.state.limit, this.state.status, this.state.order_name, this.state.order_type);
const { getDetail } = this.props;
getDetail && getDetail();
}
@@ -134,39 +108,44 @@ class Milepost extends Component {
this.setState({
page
})
- const { status } = this.state;
- this.getList( page , status );
+ this.getList(page, this.state.limit, this.state.status, this.state.order_name, this.state.order_type);
}
// 排序
arrayList = (e) => {
+ const name = e.key !== 'order' ? e.key : undefined;
+ const type = e.item.props.value !== 'order' ? e.item.props.value : undefined;
this.setState({
- order_name: e.key,
- order_type: e.item.props.value
+ order_name: name,
+ order_type: type
})
- this.getList(1, this.state.status, e.item.props.value, e.key);
+ this.getList(1, this.state.limit, this.state.status, name, type);
}
-
- //控制新建标签页是否显示
- newshow = () => {
+ // 分页组件
+ onShowSizeChange = (current, pageSize) =>{
this.setState({
- display: 'block'
- });
-
- };
- newclose = () => {
- this.setState({
- display: 'none'
- });
- };
+ page: 1,
+ limit: pageSize
+ })
+ this.getList(1, pageSize, this.state.status, this.state.order_name, this.state.order_type);
+ }
+ // tooltip判断是否显示
+ // onVisibleChange = (visible, value) => {
+ // console.log('visible, value', visible, value);
+ // this.setState({
+ // visible: value.length >24 ? visible : false
+ // })
+ // }
render() {
- const { data, limit, page, openselect, closeselect, spinings } = this.state;
+ const { data, limit, page, spinings, status, order_name, order_type, visible } = this.state;
const { projectsId , owner } = this.props.match.params;
+ const { isManager, isDeveloper} = this.props;
const menu = (
-