forked from Gitlink/forgeplus-react
Compare commits
170 Commits
master
...
dev_edu_lo
Author | SHA1 | Date |
---|---|---|
|
11d3d90def | |
|
c3fcf4a1bb | |
|
97b246d608 | |
|
83a5a5111f | |
|
3b7766bd71 | |
|
d1086c2051 | |
|
1e3ce12d93 | |
|
0566d32268 | |
|
da9e643b47 | |
|
c8eb745a4e | |
|
31a14d7868 | |
|
a89485f09a | |
|
68a0e8d225 | |
|
3ebef52e63 | |
|
357039e4eb | |
|
8b1b61031a | |
|
3b31b5c47b | |
|
7da0c7f6ab | |
|
d9effff762 | |
|
f162443756 | |
|
4979d30a8a | |
|
a8981c48f3 | |
|
cdc43a4ac5 | |
|
4f6482597b | |
|
b4c773b58e | |
|
a7384907cb | |
|
0e1281b3b9 | |
|
54cb27343d | |
|
a363e62542 | |
|
d8b2a20568 | |
|
145bbefe57 | |
|
bdd2a4c30f | |
|
3c585cb06d | |
|
29437494f8 | |
|
f415151f89 | |
|
12828b0fdf | |
|
7c9f7857e9 | |
|
8a1e5328de | |
|
2dbb1b1eb2 | |
|
873fccc7b3 | |
|
0057c90995 | |
|
1d7275fcd7 | |
|
4fd89c4fc3 | |
|
3d5ceb21f2 | |
|
9d387e9a81 | |
|
3c76c3f228 | |
|
00e5b53e86 | |
|
410a51093b | |
|
47a5f84ed4 | |
|
814aa775c7 | |
|
67fcb49342 | |
|
01d915385c | |
|
fee812c63b | |
|
b948fe9459 | |
|
f4136f87b4 | |
|
875b52eb92 | |
|
94d5040e84 | |
|
d450d77c2c | |
|
8c4151fdb7 | |
|
9feeaafaa2 | |
|
8a968fbf04 | |
|
6105df55a0 | |
|
c2a718ef4d | |
|
d1bbe72857 | |
|
35a03e9f99 | |
|
475c48c69d | |
|
4da91c11eb | |
|
bca1102b58 | |
|
6f8a8e099c | |
|
691ace31df | |
|
22cd220aa5 | |
|
37553fcf19 | |
|
6fa2fd24fb | |
|
cf5ac359ee | |
|
5cc7f51505 | |
|
585cf95840 | |
|
05aab13502 | |
|
dbdd736bf6 | |
|
2d5b5217c5 | |
|
ed1194a90f | |
|
18dbf76743 | |
|
c8dfe9fdff | |
|
fe9e565e33 | |
|
d3ed2727ef | |
|
fccb96ebb5 | |
|
712de65d40 | |
|
325f84ce80 | |
|
85bd0ffb62 | |
|
0f59544d10 | |
|
57c8f256fa | |
|
0470da643f | |
|
878ff76b00 | |
|
d6e7666607 | |
|
138db0b0cb | |
|
ba81f51e76 | |
|
3ca1ce6c1b | |
|
d4550d44e9 | |
|
0138eb2f1e | |
|
e1aef30b9d | |
|
277ba72f91 | |
|
6a58a468f9 | |
|
14486724fa | |
|
3201b7265b | |
|
f774ce974d | |
|
fdca717eeb | |
|
4b304ead34 | |
|
67d914ddb6 | |
|
e6020c3e13 | |
|
af2feeb34f | |
|
40918bf1d7 | |
|
8a5a7a0647 | |
|
93ba9c6a98 | |
|
12322f8785 | |
|
8c1bebcfdc | |
|
04bdbd7c30 | |
|
f57ee7fd99 | |
|
1e0f522f4a | |
|
798d919447 | |
|
1f6a4bda6c | |
|
0d546f4789 | |
|
44996b5dea | |
|
134d79faa3 | |
|
2677efec83 | |
|
7482d1184c | |
|
58fb71b324 | |
|
5517b28062 | |
|
0bd7f7d900 | |
|
9cfe2c186e | |
|
e4c54622b8 | |
|
21902543f4 | |
|
e541e91a06 | |
|
b6dc01b0be | |
|
f0858e7ecc | |
|
f9f79e0365 | |
|
8903363695 | |
|
b9a8becec3 | |
|
2fcd2fd066 | |
|
898ad15343 | |
|
1cf7655e63 | |
|
2383710c54 | |
|
3b3d6dc8b1 | |
|
c74c40b73e | |
|
c5bbcd9c1d | |
|
74deb640a9 | |
|
534da2115a | |
|
f2ef3183ea | |
|
1182a45cdc | |
|
29f37b9760 | |
|
f5fa45e1ce | |
|
97bf4a5a46 | |
|
5e4d3a92a1 | |
|
29f25a585d | |
|
6bd57d8877 | |
|
e7aa871b53 | |
|
9c22457249 | |
|
68b1296652 | |
|
0f7c8a4b5d | |
|
98289b05aa | |
|
83086e7d61 | |
|
76c88a659a | |
|
ae8ece2695 | |
|
93994cb785 | |
|
917958c880 | |
|
65b906f49f | |
|
90be5ad793 | |
|
eeaefc5810 | |
|
284bf67f82 | |
|
fbdde52651 | |
|
64dcdce51b | |
|
741a461f7e |
|
@ -5058,13 +5058,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"echarts": {
|
"echarts": {
|
||||||
"version": "4.7.0",
|
"version": "4.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/echarts/-/echarts-4.7.0.tgz",
|
"resolved": "https://registry.nlark.com/echarts/download/echarts-4.9.0.tgz",
|
||||||
"integrity": "sha512-NlOTdUcAsIyCCG+N4uh0ZEvXtrPW2jvcuqf03RyqYeCKzyPbiOQ4I3MdKXMhxG3lBdqQNdNXVT71SB4KTQjN0A==",
|
"integrity": "sha1-qbm6oD8Doqcx5jQMVb77V6nhNH0=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"zrender": "4.3.0"
|
"zrender": "4.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"echarts-wordcloud": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/echarts-wordcloud/download/echarts-wordcloud-2.0.0.tgz?cache=0&sync_timestamp=1610779172014&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fecharts-wordcloud%2Fdownload%2Fecharts-wordcloud-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-Uu+BeJWAH/6emd0brKt2hrLewEo="
|
||||||
|
},
|
||||||
"editor.md": {
|
"editor.md": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/editor.md/-/editor.md-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/editor.md/-/editor.md-1.5.0.tgz",
|
||||||
|
@ -9888,6 +9893,11 @@
|
||||||
"esprima": "^4.0.0"
|
"esprima": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"js2wordcloud": {
|
||||||
|
"version": "1.1.12",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/js2wordcloud/download/js2wordcloud-1.1.12.tgz",
|
||||||
|
"integrity": "sha1-8BdC2k5qyzAAsoY1dmQWjvn8o64="
|
||||||
|
},
|
||||||
"jsbn": {
|
"jsbn": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
||||||
|
@ -14024,9 +14034,9 @@
|
||||||
"integrity": "sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8="
|
"integrity": "sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8="
|
||||||
},
|
},
|
||||||
"qrcode.react": {
|
"qrcode.react": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-1.0.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/qrcode.react/download/qrcode.react-1.0.1.tgz",
|
||||||
"integrity": "sha512-jBXleohRTwvGBe1ngV+62QvEZ/9IZqQivdwzo9pJM4LQMoCM2VnvNBnKdjvGnKyDZ/l0nCDgsPod19RzlPvm/Q==",
|
"integrity": "sha1-KDS7UOXidf/lr2kG7/FTkf6eOKU=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.4.0",
|
"loose-envify": "^1.4.0",
|
||||||
"prop-types": "^15.6.0",
|
"prop-types": "^15.6.0",
|
||||||
|
@ -20517,9 +20527,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"zrender": {
|
"zrender": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/zrender/-/zrender-4.3.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/zrender/download/zrender-4.3.2.tgz",
|
||||||
"integrity": "sha512-Dii6j2bDsPkxQayuVf2DXJeruIB/mKVxxcGRZQ9GExiBd4c3w7+oBuvo1O/JGHeFeA1nCmSDVDs/S7yKZG1nrA=="
|
"integrity": "sha1-7HQy+UFcgsc1hLa3uMR+GwFiCcY="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,8 @@
|
||||||
"dompurify": "^2.0.15",
|
"dompurify": "^2.0.15",
|
||||||
"dotenv": "4.0.0",
|
"dotenv": "4.0.0",
|
||||||
"dotenv-expand": "4.2.0",
|
"dotenv-expand": "4.2.0",
|
||||||
"echarts": "^4.7.0",
|
"echarts": "^4.9.0",
|
||||||
|
"echarts-wordcloud": "^2.0.0",
|
||||||
"editor.md": "^1.5.0",
|
"editor.md": "^1.5.0",
|
||||||
"eslint": "4.10.0",
|
"eslint": "4.10.0",
|
||||||
"eslint-config-react-app": "^2.1.0",
|
"eslint-config-react-app": "^2.1.0",
|
||||||
|
@ -46,6 +47,7 @@
|
||||||
"install": "^0.12.2",
|
"install": "^0.12.2",
|
||||||
"jest": "20.0.4",
|
"jest": "20.0.4",
|
||||||
"js-base64": "^2.5.2",
|
"js-base64": "^2.5.2",
|
||||||
|
"js2wordcloud": "^1.1.12",
|
||||||
"katex": "^0.11.1",
|
"katex": "^0.11.1",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"loglevel": "^1.6.8",
|
"loglevel": "^1.6.8",
|
||||||
|
@ -62,7 +64,7 @@
|
||||||
"postcss-loader": "2.0.8",
|
"postcss-loader": "2.0.8",
|
||||||
"promise": "8.0.1",
|
"promise": "8.0.1",
|
||||||
"prop-types": "^15.6.1",
|
"prop-types": "^15.6.1",
|
||||||
"qrcode.react": "^1.0.0",
|
"qrcode.react": "^1.0.1",
|
||||||
"qs": "^6.9.3",
|
"qs": "^6.9.3",
|
||||||
"quill": "^1.3.7",
|
"quill": "^1.3.7",
|
||||||
"quill-delta-to-html": "^0.11.0",
|
"quill-delta-to-html": "^0.11.0",
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -38,78 +38,6 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.head-nav ul#header-nav li {
|
|
||||||
float: left;
|
|
||||||
height: 60px;
|
|
||||||
line-height: 60px;
|
|
||||||
margin-right: 30px;
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
font-size: 16px
|
|
||||||
}
|
|
||||||
|
|
||||||
.head-nav ul#header-nav li a {
|
|
||||||
display: block;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
color: #fff
|
|
||||||
}
|
|
||||||
|
|
||||||
.head-nav ul#header-nav li a:hover {
|
|
||||||
color: #cccccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.head-nav ul#header-nav li:last-child {
|
|
||||||
margin-right: 0px
|
|
||||||
}
|
|
||||||
|
|
||||||
.head-nav ul#header-nav li.active a {
|
|
||||||
color: #459be5 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.head-nav ul#header-nav li.active p {
|
|
||||||
color: #459be5 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.head-nav ul#header-nav li p:hover {
|
|
||||||
color: #cccccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.head-nav ul#header-nav li p {
|
|
||||||
display: block;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
color: #fff
|
|
||||||
}
|
|
||||||
|
|
||||||
.head-nav ul#header-nav li.active div ul li a {
|
|
||||||
color: #000 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.head-nav ul#header-nav li.active div ul li a:hover {
|
|
||||||
color: #FFF !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.head-nav ul#header-nav li.active ul li a {
|
|
||||||
color: #000 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.head-nav ul#header-nav li.active ul li a:hover {
|
|
||||||
color: #FFF !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.head-nav ul#header-nav li.active:after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
left: 0px;
|
|
||||||
top: auto;
|
|
||||||
bottom: 10px;
|
|
||||||
right: auto;
|
|
||||||
height: 2px;
|
|
||||||
width: 14px;
|
|
||||||
background-color: #459be5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-img {
|
.nav-img {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 2px;
|
top: 2px;
|
||||||
|
|
|
@ -25,9 +25,6 @@ html {
|
||||||
min-width: 1200px
|
min-width: 1200px
|
||||||
}
|
}
|
||||||
|
|
||||||
.newFooter {
|
|
||||||
max-height: 110px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.newFooter {
|
.newFooter {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
@ -1307,6 +1307,7 @@ td,
|
||||||
span {
|
span {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
margin-bottom: 0px!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
table,
|
table,
|
||||||
|
@ -2346,7 +2347,6 @@ input::-ms-clear {
|
||||||
/*中间部分宽度固定为1200*/
|
/*中间部分宽度固定为1200*/
|
||||||
.newMain {
|
.newMain {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding-bottom: 110px;
|
|
||||||
min-width: 1200px;
|
min-width: 1200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3410,7 +3410,7 @@ a.user_bluebg_btn {
|
||||||
}
|
}
|
||||||
|
|
||||||
.cdefault {
|
.cdefault {
|
||||||
cursor: default
|
cursor: default!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3585,43 +3585,6 @@ a.user_bluebg_btn {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------个人主页:右侧提示区域--------------------------*/
|
|
||||||
.-task-sidebar {
|
|
||||||
position: fixed;
|
|
||||||
width: 40px;
|
|
||||||
height: 180px;
|
|
||||||
right: 0;
|
|
||||||
bottom: 80px;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
.-task-sidebar div {
|
|
||||||
height: 40px;
|
|
||||||
line-height: 40px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 40px;
|
|
||||||
background: #4CACFF;
|
|
||||||
color: #fff;
|
|
||||||
font-size: 20px;
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.-task-sidebar div i {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.-task-sidebar div i:hover {
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gotop {
|
|
||||||
background-color: rgba(208, 207, 207, 0.5) !important;
|
|
||||||
padding: 0px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***** loading ******/
|
/***** loading ******/
|
||||||
/*****载入中******/
|
/*****载入中******/
|
||||||
#ajax-indicator {
|
#ajax-indicator {
|
||||||
|
@ -3945,11 +3908,21 @@ html>body #ajax-indicator {
|
||||||
max-height: 340px;
|
max-height: 340px;
|
||||||
}/*头部导航条样式---2018-03-19--by-cs*/
|
}/*头部导航条样式---2018-03-19--by-cs*/
|
||||||
|
|
||||||
|
.privateTag{
|
||||||
|
display: block;
|
||||||
|
padding:0px 6px;
|
||||||
|
border-radius: 12px;
|
||||||
|
border:1px solid #2FC25B;
|
||||||
|
height: 18px;
|
||||||
|
line-height: 18px;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-left: 10px;
|
||||||
|
color: #2FC25B;
|
||||||
|
}
|
||||||
.head-nav {
|
.head-nav {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
height: 70px;
|
height: 70px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
min-width: 780px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -3971,14 +3944,14 @@ html>body #ajax-indicator {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
padding:0px 20px;
|
padding-right:40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.head-nav ul#header-nav li a {
|
.head-nav ul#header-nav li a {
|
||||||
display: block;
|
display: block;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
color: #333;
|
color: #fff;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4108,21 +4081,6 @@ em.vertical-line {
|
||||||
|
|
||||||
/* 右侧内容宽度变化的话,需要调整posi-search right的值*/
|
/* 右侧内容宽度变化的话,需要调整posi-search right的值*/
|
||||||
|
|
||||||
/*底部*/
|
|
||||||
.newFooter {
|
|
||||||
max-height: 110px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.newFooter {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
background: #323232;
|
|
||||||
clear: both;
|
|
||||||
min-width: 1200px;
|
|
||||||
z-index: 8;
|
|
||||||
left: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footercon {
|
.footercon {
|
||||||
border-bottom: 1px solid #47494d;
|
border-bottom: 1px solid #47494d;
|
||||||
|
@ -6719,3 +6677,12 @@ ul.count_ul li:not(:last-child):after {
|
||||||
input.ant-input-lg::placeholder{
|
input.ant-input-lg::placeholder{
|
||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
}
|
}
|
||||||
|
p{
|
||||||
|
margin-bottom: 0px!important;
|
||||||
|
}
|
||||||
|
.toprightNum{
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
top:4px;
|
||||||
|
color: #999;
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -5,6 +5,139 @@
|
||||||
"css_prefix_text": "icon-",
|
"css_prefix_text": "icon-",
|
||||||
"description": "",
|
"description": "",
|
||||||
"glyphs": [
|
"glyphs": [
|
||||||
|
{
|
||||||
|
"icon_id": "17575494",
|
||||||
|
"name": "file-submodule",
|
||||||
|
"font_class": "file-submodule",
|
||||||
|
"unicode": "e866",
|
||||||
|
"unicode_decimal": 59494
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "7539612",
|
||||||
|
"name": "nv",
|
||||||
|
"font_class": "nv1",
|
||||||
|
"unicode": "e864",
|
||||||
|
"unicode_decimal": 59492
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "7539613",
|
||||||
|
"name": "nan",
|
||||||
|
"font_class": "nan1",
|
||||||
|
"unicode": "e865",
|
||||||
|
"unicode_decimal": 59493
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21936935",
|
||||||
|
"name": "邮箱",
|
||||||
|
"font_class": "youxiang",
|
||||||
|
"unicode": "e8b2",
|
||||||
|
"unicode_decimal": 59570
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21936924",
|
||||||
|
"name": "单位",
|
||||||
|
"font_class": "danwei",
|
||||||
|
"unicode": "e8a7",
|
||||||
|
"unicode_decimal": 59559
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21936925",
|
||||||
|
"name": "待办事项",
|
||||||
|
"font_class": "daibanshixiang",
|
||||||
|
"unicode": "e8a8",
|
||||||
|
"unicode_decimal": 59560
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21936928",
|
||||||
|
"name": "概览",
|
||||||
|
"font_class": "gailan",
|
||||||
|
"unicode": "e8ab",
|
||||||
|
"unicode_decimal": 59563
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21936929",
|
||||||
|
"name": "男",
|
||||||
|
"font_class": "nan",
|
||||||
|
"unicode": "e8ac",
|
||||||
|
"unicode_decimal": 59564
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21936930",
|
||||||
|
"name": "女",
|
||||||
|
"font_class": "nv",
|
||||||
|
"unicode": "e8ad",
|
||||||
|
"unicode_decimal": 59565
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21936931",
|
||||||
|
"name": "工作流",
|
||||||
|
"font_class": "gongzuoliu1",
|
||||||
|
"unicode": "e8ae",
|
||||||
|
"unicode_decimal": 59566
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21936934",
|
||||||
|
"name": "数据统计",
|
||||||
|
"font_class": "shujutongji",
|
||||||
|
"unicode": "e8b1",
|
||||||
|
"unicode_decimal": 59569
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21936936",
|
||||||
|
"name": "项目",
|
||||||
|
"font_class": "xiangmu",
|
||||||
|
"unicode": "e8b3",
|
||||||
|
"unicode_decimal": 59571
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21936937",
|
||||||
|
"name": "组织",
|
||||||
|
"font_class": "zuzhi",
|
||||||
|
"unicode": "e8b4",
|
||||||
|
"unicode_decimal": 59572
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "14835599",
|
||||||
|
"name": "右箭头",
|
||||||
|
"font_class": "arrowRight",
|
||||||
|
"unicode": "e863",
|
||||||
|
"unicode_decimal": 59491
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21151489",
|
||||||
|
"name": "箭头镂空-左",
|
||||||
|
"font_class": "jiantouloukong-zuo",
|
||||||
|
"unicode": "e861",
|
||||||
|
"unicode_decimal": 59489
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21151557",
|
||||||
|
"name": "箭头镂空-右",
|
||||||
|
"font_class": "jiantouloukong-you",
|
||||||
|
"unicode": "e862",
|
||||||
|
"unicode_decimal": 59490
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21568989",
|
||||||
|
"name": "分享",
|
||||||
|
"font_class": "fenxiang1",
|
||||||
|
"unicode": "e89c",
|
||||||
|
"unicode_decimal": 59548
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21568990",
|
||||||
|
"name": "回到顶部",
|
||||||
|
"font_class": "huidaodingbu1",
|
||||||
|
"unicode": "e89d",
|
||||||
|
"unicode_decimal": 59549
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21568993",
|
||||||
|
"name": "帮助",
|
||||||
|
"font_class": "bangzhu",
|
||||||
|
"unicode": "e8a0",
|
||||||
|
"unicode_decimal": 59552
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"icon_id": "991344",
|
"icon_id": "991344",
|
||||||
"name": "提交",
|
"name": "提交",
|
||||||
|
@ -4236,7 +4369,7 @@
|
||||||
{
|
{
|
||||||
"icon_id": "1004630",
|
"icon_id": "1004630",
|
||||||
"name": "点赞2",
|
"name": "点赞2",
|
||||||
"font_class": "dianzan1",
|
"font_class": "dianzaned",
|
||||||
"unicode": "e639",
|
"unicode": "e639",
|
||||||
"unicode_decimal": 58937
|
"unicode_decimal": 58937
|
||||||
},
|
},
|
||||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 733 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,5 +1,5 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="zh-CN" class="notranslate translated-ltr" translate="no">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name=”Keywords” Content=”trustie,trustieforge,forge,确实让创建更美好,协同开发平台″>
|
<meta name=”Keywords” Content=”trustie,trustieforge,forge,确实让创建更美好,协同开发平台″>
|
||||||
|
|
55
src/App.js
55
src/App.js
|
@ -17,8 +17,7 @@ import marked from './common/marked';
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
|
||||||
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
|
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
|
||||||
|
import SiderBar from './forge/Component/SiderBar'
|
||||||
import history from './history';
|
|
||||||
|
|
||||||
import { SnackbarHOC } from 'educoder'
|
import { SnackbarHOC } from 'educoder'
|
||||||
import { initAxiosInterceptors } from './AppConfig'
|
import { initAxiosInterceptors } from './AppConfig'
|
||||||
|
@ -75,6 +74,10 @@ const EducoderLogin = Loadable({
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const ProjectIndex = Loadable({
|
||||||
|
loader: () => import("./forge/Main/Index"),
|
||||||
|
loading: Loading,
|
||||||
|
});
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -100,39 +103,11 @@ class App extends Component {
|
||||||
Addcoursestypes: false
|
Addcoursestypes: false
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
ModalCancelsy = () => {
|
|
||||||
this.setState({
|
|
||||||
mydisplay: false,
|
|
||||||
})
|
|
||||||
window.location.href = "/";
|
|
||||||
};
|
|
||||||
ModalshowCancelsy = () => {
|
|
||||||
this.setState({
|
|
||||||
mydisplay: true,
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
disableVideoContextMenu = () => {
|
|
||||||
window.$("body").on("mousedown", "video", function (event) {
|
|
||||||
if (event.which === 3) {
|
|
||||||
window.$('video').bind('contextmenu', function () { return false; });
|
|
||||||
} else {
|
|
||||||
window.$('video').unbind('contextmenu');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
document.title = "loading...";
|
document.title = "loading...";
|
||||||
this.disableVideoContextMenu();
|
|
||||||
history.listen(() => {
|
|
||||||
this.forceUpdate()
|
|
||||||
const $ = window.$
|
|
||||||
$("html").animate({ scrollTop: $('html').scrollTop() - 0 })
|
|
||||||
});
|
|
||||||
|
|
||||||
initAxiosInterceptors(this.props);
|
initAxiosInterceptors(this.props);
|
||||||
this.getAppdata();
|
this.getAppdata();
|
||||||
|
|
||||||
window.addEventListener('error', (event) => {
|
window.addEventListener('error', (event) => {
|
||||||
const msg = `${event.type}: ${event.message}`;
|
const msg = `${event.type}: ${event.message}`;
|
||||||
});
|
});
|
||||||
|
@ -207,11 +182,13 @@ class App extends Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { mygetHelmetapi } = this.state;
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<ConfigProvider locale={zhCN}>
|
<ConfigProvider locale={zhCN}>
|
||||||
<MuiThemeProvider theme={theme}>
|
<MuiThemeProvider theme={theme}>
|
||||||
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
|
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
|
||||||
|
<SiderBar/>
|
||||||
<Router>
|
<Router>
|
||||||
<Switch>
|
<Switch>
|
||||||
{/*项目*/}
|
{/*项目*/}
|
||||||
|
@ -224,14 +201,6 @@ class App extends Component {
|
||||||
}>
|
}>
|
||||||
</Route>
|
</Route>
|
||||||
{/*项目*/}
|
{/*项目*/}
|
||||||
<Route
|
|
||||||
path={"/projects"}
|
|
||||||
render={
|
|
||||||
(props) => {
|
|
||||||
return (<Projects {...this.props} {...props} {...this.state} />)
|
|
||||||
}
|
|
||||||
}>
|
|
||||||
</Route>
|
|
||||||
<Route
|
<Route
|
||||||
path="/register"
|
path="/register"
|
||||||
render={
|
render={
|
||||||
|
@ -260,10 +229,18 @@ class App extends Component {
|
||||||
return (<InfosIndex {...this.props} {...this.state} />)
|
return (<InfosIndex {...this.props} {...this.state} />)
|
||||||
}
|
}
|
||||||
}></Route>
|
}></Route>
|
||||||
|
<Route
|
||||||
|
path={"/projects"}
|
||||||
|
render={
|
||||||
|
(props) => {
|
||||||
|
return (<Projects {...this.props} {...props} {...this.state} />)
|
||||||
|
}
|
||||||
|
}>
|
||||||
|
</Route>
|
||||||
<Route exact path="/"
|
<Route exact path="/"
|
||||||
render={
|
render={
|
||||||
(props) => (
|
(props) => (
|
||||||
<Projects {...this.props} {...props} {...this.state}></Projects>
|
<Projects {...this.props} {...props} {...this.state} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import axios from 'axios';
|
||||||
import { requestProxy } from "./indexEduplus2RequestProxy";
|
import { requestProxy } from "./indexEduplus2RequestProxy";
|
||||||
import { broadcastChannelOnmessage, isDev, queryString } from 'educoder';
|
import { broadcastChannelOnmessage, isDev, queryString } from 'educoder';
|
||||||
import { notification } from 'antd';
|
import { notification } from 'antd';
|
||||||
import cookie from 'react-cookies';
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
let message501 = false;
|
let message501 = false;
|
||||||
|
@ -11,10 +11,8 @@ broadcastChannelOnmessage('refreshPage', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
function locationurl(list) {
|
function locationurl(list) {
|
||||||
if (window.location.port === "3007") {
|
if (window.location.port !== "3007") {
|
||||||
|
window.location.href = list
|
||||||
} else {
|
|
||||||
window.location.href = list
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO 开发期多个身份切换
|
// TODO 开发期多个身份切换
|
||||||
|
@ -26,78 +24,41 @@ if (isDev) {
|
||||||
parsed = queryString.parse(_search);
|
parsed = queryString.parse(_search);
|
||||||
}
|
}
|
||||||
debugType = window.location.search.indexOf('debug=t') !== -1 ? 'teacher' :
|
debugType = window.location.search.indexOf('debug=t') !== -1 ? 'teacher' :
|
||||||
window.location.search.indexOf('debug=s') !== -1 ? 'student' :
|
window.location.search.indexOf('debug=s') !== -1 ? 'student' :
|
||||||
window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin'
|
window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin'
|
||||||
}
|
}
|
||||||
function clearAllCookie() {
|
|
||||||
cookie.remove('_educoder_session', { path: '/' });
|
|
||||||
cookie.remove('autologin_trustie', { path: '/' });
|
|
||||||
setpostcookie()
|
|
||||||
}
|
|
||||||
clearAllCookie();
|
|
||||||
function setpostcookie() {
|
|
||||||
const str = window.location.pathname;
|
|
||||||
if (str.indexOf("/wxcode") !== -1) {
|
|
||||||
cookie.remove('_educoder_session', { path: '/' });
|
|
||||||
cookie.remove('autologin_trustie', { path: '/' });
|
|
||||||
const _params = window.location.search;
|
|
||||||
if (_params) {
|
|
||||||
let _search = _params.split('?')[1];
|
|
||||||
let _educoder_sessions = _search.split('&')[0].split('=');
|
|
||||||
cookie.save('_educoder_session', _educoder_sessions[1], { domain: '.educoder.net', path: '/' });
|
|
||||||
let autologin_trusties = _search.split('&')[1].split('=');
|
|
||||||
cookie.save('autologin_trustie', autologin_trusties[1], { domain: '.educoder.net', path: '/' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setpostcookie();
|
|
||||||
|
|
||||||
window._debugType = debugType;
|
window._debugType = debugType;
|
||||||
export function initAxiosInterceptors(props) {
|
export function initAxiosInterceptors(props) {
|
||||||
|
// 判断网络是否连接
|
||||||
initOnlineOfflineListener();
|
initOnlineOfflineListener();
|
||||||
var proxy = "http://localhost:3000";
|
|
||||||
proxy = "https://testforgeplus.trustie.net";
|
|
||||||
|
|
||||||
const requestMap = {};
|
var proxy = "http://106.75.178.228:81";
|
||||||
window.setfalseInRequestMap = function (keyName) {
|
|
||||||
requestMap[keyName] = false;
|
|
||||||
}
|
|
||||||
//响应前的设置
|
//响应前的设置
|
||||||
axios.interceptors.request.use(
|
axios.interceptors.request.use(
|
||||||
config => {
|
config => {
|
||||||
setpostcookie()
|
if(config.url.indexOf("http") !== -1) {
|
||||||
clearAllCookie()
|
|
||||||
|
|
||||||
if (config.url.indexOf(proxy) !== -1) {
|
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
requestProxy(config)
|
requestProxy(config);
|
||||||
|
|
||||||
let url = `/api${config.url}`;
|
let url = `/api${config.url}`;
|
||||||
|
|
||||||
if (`${config[0]}` !== `true`) {
|
if (`${config[0]}` !== `true`) {
|
||||||
if (window.location.port === "3007") {
|
if (window.location.port === "3007") {
|
||||||
config.url = `${proxy}${url}`;
|
config.url = `${proxy}${url}`;
|
||||||
if (config.url.indexOf('?') === -1) {
|
// if (config.url.indexOf('?') === -1) {
|
||||||
config.url = `${config.url}?debug=${debugType}`;
|
// config.url = `${config.url}?debug=${debugType}`;
|
||||||
} else {
|
// } else {
|
||||||
config.url = `${config.url}&debug=${debugType}`;
|
// config.url = `${config.url}&debug=${debugType}`;
|
||||||
}
|
// }
|
||||||
} else {
|
} else {
|
||||||
config.url = url;
|
config.url = url;
|
||||||
}
|
}
|
||||||
setpostcookie();
|
|
||||||
}
|
|
||||||
if (config.url.indexOf('update_file') === -1) {
|
|
||||||
requestMap[config.url] = true;
|
|
||||||
|
|
||||||
window.setTimeout("setfalseInRequestMap('" + config.url + "')", 900)
|
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
err => {
|
err => {
|
||||||
return Promise.reject(err);
|
return Promise.reject(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
axios.interceptors.response.use(function (response) {
|
axios.interceptors.response.use(function (response) {
|
||||||
if (response === undefined) {
|
if (response === undefined) {
|
||||||
|
@ -146,8 +107,6 @@ export function initAxiosInterceptors(props) {
|
||||||
message501 = false
|
message501 = false
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
requestMap[response.config.url] = false;
|
|
||||||
setpostcookie();
|
|
||||||
return response;
|
return response;
|
||||||
}, function (error) {
|
}, function (error) {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
|
|
|
@ -9,20 +9,7 @@ class Loading extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return ""
|
||||||
<div className="App" style={{ minHeight: '800px', width: "100%" }}>
|
|
||||||
<style>
|
|
||||||
{
|
|
||||||
`
|
|
||||||
.margintop{
|
|
||||||
margin-top:20%;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<Spin size="large" className={"margintop"} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,17 @@ const isDev = window.location.port == 3007;
|
||||||
const isdev2= window.location.hostname ==='www.educoder.net'
|
const isdev2= window.location.hostname ==='www.educoder.net'
|
||||||
export const TEST_HOST = "https://testforgeplus.trustie.net/"
|
export const TEST_HOST = "https://testforgeplus.trustie.net/"
|
||||||
export function getImageUrl(path) {
|
export function getImageUrl(path) {
|
||||||
// https://www.educoder.net
|
const local = 'https://testforgeplus.educoder.net';
|
||||||
// https://testbdweb.trustie.net
|
const normal = 'https://ali-cdn.educoder.net/images';
|
||||||
// const local = 'http://localhost:3000'
|
if(path.substr(0, 7) !== "/system"){
|
||||||
const local = 'https://testforgeplus.trustie.net';
|
if (isDev) {
|
||||||
if (isDev) {
|
return `${local}/${path}`
|
||||||
return `${local}/${path}`
|
}
|
||||||
|
if(path.substr(0, 7) !== "/images"){
|
||||||
|
return `${normal}${path}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return `/${path}`;
|
return `${path}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getImage(path) {
|
export function getImage(path) {
|
||||||
|
@ -162,7 +165,7 @@ export function getmyUrl(geturl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUploadActionUrl(path, goTest) {
|
export function getUploadActionUrl(path, goTest) {
|
||||||
return `${getUrl()}/api/attachments.json?debug=${window._debugType || 'admin'}`;
|
return `${getUrl()}/api/attachments.json`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUploadLogoActionUrl() {
|
export function getUploadLogoActionUrl() {
|
||||||
|
|
|
@ -64,7 +64,7 @@ function CommentItem({
|
||||||
const commentAvatar = (author) => (
|
const commentAvatar = (author) => (
|
||||||
<img
|
<img
|
||||||
className="item-flex flex-image"
|
className="item-flex flex-image"
|
||||||
src={author.image_url ? getImageUrl(`images/${author.image_url}`) : 'https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg'}
|
src={author.image_url ? getImageUrl(`/${author.image_url}`) : 'https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg'}
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -46,18 +46,18 @@ export default ({
|
||||||
let id = decodeURIComponent(u.split("#")[1]);
|
let id = decodeURIComponent(u.split("#")[1]);
|
||||||
let ele = document.getElementById(id);
|
let ele = document.getElementById(id);
|
||||||
if(ele){
|
if(ele){
|
||||||
window.scrollTo(0, ele.offsetTop + 220);
|
window.scrollTo(0, ele.offsetTop + 120);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},[url])
|
},[url,html])
|
||||||
|
|
||||||
const el = useRef();
|
const el = useRef();
|
||||||
function onAncherHandler(e) {
|
function onAncherHandler(e) {
|
||||||
let target = e.target
|
let target = e.target;
|
||||||
if (target.tagName.toUpperCase() === 'A') {
|
if (target.tagName.toUpperCase() === 'A') {
|
||||||
let ancher = target.getAttribute('href')
|
let ancher = target.getAttribute('href');
|
||||||
if (ancher.startsWith('#')) {
|
if (ancher && ancher.startsWith('#')) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
let viewEl = document.getElementById(ancher.replace('#', ''))
|
let viewEl = document.getElementById(ancher.replace('#', ''))
|
||||||
if (viewEl) {
|
if (viewEl) {
|
||||||
|
|
|
@ -69,7 +69,7 @@ function Index(props){
|
||||||
<div className="aboutPanels">
|
<div className="aboutPanels">
|
||||||
<div className="aboutContent">
|
<div className="aboutContent">
|
||||||
<AlignCenterBetween style={{padding:"14px 20px"}}>
|
<AlignCenterBetween style={{padding:"14px 20px"}}>
|
||||||
<span className="font-16"><i className="iconfont icon-xiangmujianjie mr5 font-16 color-blue"></i>项目简介</span>
|
<span className="font-16"><i className="iconfont icon-xiangmujianjie mr5 font-16 color-blue"></i>项目概览</span>
|
||||||
{ editOpration && !edit && <a onClick={editContent} className="color-blue">编辑</a> }
|
{ editOpration && !edit && <a onClick={editContent} className="color-blue">编辑</a> }
|
||||||
</AlignCenterBetween>
|
</AlignCenterBetween>
|
||||||
{
|
{
|
||||||
|
@ -117,7 +117,7 @@ function Index(props){
|
||||||
{content ?
|
{content ?
|
||||||
<RenderHtml className="break_word_comments imageLayerParent" value={content} url={props.history.location}/>
|
<RenderHtml className="break_word_comments imageLayerParent" value={content} url={props.history.location}/>
|
||||||
:
|
:
|
||||||
<div>暂无简介~</div>
|
<div>暂无概览~</div>
|
||||||
}
|
}
|
||||||
{attachments && attachments.length > 0 &&
|
{attachments && attachments.length > 0 &&
|
||||||
<Attachments
|
<Attachments
|
||||||
|
|
|
@ -33,7 +33,7 @@ class ActivityItem extends Component {
|
||||||
}
|
}
|
||||||
<p className="itemLine mt10">
|
<p className="itemLine mt10">
|
||||||
<Link to={`/users/${item && item.user_login}`} className="show-user-link">
|
<Link to={`/users/${item && item.user_login}`} className="show-user-link">
|
||||||
<img alt="" src={getImageUrl(`images/${item.user_avatar}`)} className="createImage" />
|
<img alt="" src={getImageUrl(`/${item.user_avatar}`)} className="createImage" />
|
||||||
<span className="mr20">{item.user_name}</span>
|
<span className="mr20">{item.user_name}</span>
|
||||||
</Link>
|
</Link>
|
||||||
{item.created_at && <span className="color-grey-9">创建于<span className="ml2 color-grey-6">{item.created_at}</span></span>}
|
{item.created_at && <span className="color-grey-9">创建于<span className="ml2 color-grey-6">{item.created_at}</span></span>}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import axios from 'axios';
|
||||||
import { getImageUrl } from 'educoder';
|
import { getImageUrl } from 'educoder';
|
||||||
|
|
||||||
const { Option } = AutoComplete;
|
const { Option } = AutoComplete;
|
||||||
function AddMember({getID,login}){
|
function AddMember({getID,login,showNotification}){
|
||||||
const [ id , setID ] = useState(undefined);
|
const [ id , setID ] = useState(undefined);
|
||||||
const [ source , setSource ] = useState(undefined);
|
const [ source , setSource ] = useState(undefined);
|
||||||
const [ searchKey , setSearchKey ] = useState(undefined);
|
const [ searchKey , setSearchKey ] = useState(undefined);
|
||||||
|
@ -42,10 +42,10 @@ function AddMember({getID,login}){
|
||||||
className="user_img radius"
|
className="user_img radius"
|
||||||
width="28"
|
width="28"
|
||||||
height="28"
|
height="28"
|
||||||
src={getImageUrl(`images/${item && item.image_url}`)}
|
src={getImageUrl(`/${item && item.image_url}`)}
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
<span className="ml10" style={{ "vertical-align": "middle" }}>
|
<span className="ml10" style={{ verticalAlign: "middle" }}>
|
||||||
{item.username}
|
{item.username}
|
||||||
<span className="color-grey ml10">({item.login})</span>
|
<span className="color-grey ml10">({item.login})</span>
|
||||||
</span>
|
</span>
|
||||||
|
@ -66,7 +66,12 @@ function AddMember({getID,login}){
|
||||||
};
|
};
|
||||||
|
|
||||||
function addCollaborator(){
|
function addCollaborator(){
|
||||||
getID && getID(id);
|
if(source && source.length>0){
|
||||||
|
getID && getID(id);
|
||||||
|
setSearchKey(undefined);
|
||||||
|
}else{
|
||||||
|
showNotification("请选择存在的用户!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return(
|
return(
|
||||||
|
|
|
@ -6,7 +6,7 @@ import './Component.scss';
|
||||||
function Cards({img , title, desc , rightBtn , src}){
|
function Cards({img , title, desc , rightBtn , src}){
|
||||||
return(
|
return(
|
||||||
<div className="cards">
|
<div className="cards">
|
||||||
{img &&<div className="img"><img src={getImageUrl(`images/${img}`)} alt=""/></div>}
|
{img &&<div className="img"><img src={getImageUrl(`/${img}`)} alt=""/></div>}
|
||||||
<div className="content">
|
<div className="content">
|
||||||
<p className="titles">
|
<p className="titles">
|
||||||
<Link to={src}>{title}</Link>
|
<Link to={src}>{title}</Link>
|
||||||
|
|
|
@ -112,6 +112,9 @@ li.ant-menu-item{
|
||||||
right:240px;
|
right:240px;
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
}
|
}
|
||||||
|
.laterest{
|
||||||
|
color: #05690d;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1800px){
|
@media screen and (max-width: 1800px){
|
||||||
.handleBox{
|
.handleBox{
|
||||||
|
@ -152,3 +155,209 @@ li.ant-menu-item{
|
||||||
margin:0px 20px!important;
|
margin:0px 20px!important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menuPanels{
|
||||||
|
width: 240px;
|
||||||
|
height: 180px;
|
||||||
|
.ant-popover-content,.ant-popover-inner{
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.halfs{
|
||||||
|
margin-top: 24px;
|
||||||
|
padding:24px 0px 0px 0px;
|
||||||
|
border-top: 1px solid #e8e8e8;
|
||||||
|
.attrPerson{
|
||||||
|
padding-bottom: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.menuinfos{
|
||||||
|
padding:15px 0px;
|
||||||
|
&>a{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
border-right: 1px solid #eee;
|
||||||
|
flex: 1;
|
||||||
|
& >span:first-child{
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
& >span:last-child{
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
&:last-child{
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------个人主页:右侧提示区域--------------------------*/
|
||||||
|
.-task-sidebar {
|
||||||
|
position: fixed;
|
||||||
|
width: 40px;
|
||||||
|
right: 0;
|
||||||
|
bottom: 80px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 1920px){
|
||||||
|
.-task-sidebar{
|
||||||
|
right:220px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 1750px){
|
||||||
|
.-task-sidebar{
|
||||||
|
right:160px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 1650px){
|
||||||
|
.-task-sidebar{
|
||||||
|
right:115px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 1550px){
|
||||||
|
.-task-sidebar{
|
||||||
|
right:90px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 1450px){
|
||||||
|
.-task-sidebar{
|
||||||
|
right:45px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 1200px){
|
||||||
|
.-task-sidebar{
|
||||||
|
right:0px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.-task-sidebar>div {
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 40px;
|
||||||
|
color: #999;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #FFFFFF;
|
||||||
|
box-shadow: 0px 0px 10px 1px #F1F1F1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.-task-sidebar>div i {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.-task-sidebar>div:hover i {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
.-task-sidebar>div:hover{
|
||||||
|
background: #1890FF;
|
||||||
|
box-shadow: 0px 0px 10px 2px #B6D0FC;
|
||||||
|
}
|
||||||
|
.helpBox{
|
||||||
|
width: 260px;
|
||||||
|
z-index: 103;
|
||||||
|
&.shareContent{
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
.ant-popover-inner-content{
|
||||||
|
padding:0px;
|
||||||
|
}
|
||||||
|
p.titlecontent{
|
||||||
|
font-size: 18px;
|
||||||
|
color: #333;
|
||||||
|
line-height: 20px;
|
||||||
|
padding:15px 20px;
|
||||||
|
}
|
||||||
|
.faqUl{
|
||||||
|
padding:0px 20px 10px;
|
||||||
|
max-height: 230px;
|
||||||
|
overflow-y: auto;
|
||||||
|
li{
|
||||||
|
background: #F5F5F5;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding:0px 20px;
|
||||||
|
color: #333;
|
||||||
|
height: 34px;
|
||||||
|
line-height: 34px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
a{
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
background-color: #D1E9FF;
|
||||||
|
a{
|
||||||
|
color: #333!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.shareUl{
|
||||||
|
padding:10px 0px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.titlecontent{
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
li > i{
|
||||||
|
font-size: 32px!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.-task-desc {
|
||||||
|
background: #494949;
|
||||||
|
width: 90px;
|
||||||
|
line-height: 36px;
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 13px;
|
||||||
|
z-index: 999999;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.-task-desc div {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: -7px;
|
||||||
|
height: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.-task-desc div img {
|
||||||
|
float: left
|
||||||
|
}
|
||||||
|
|
||||||
|
.-task-sidebar .scan_ewm {
|
||||||
|
position: absolute !important;
|
||||||
|
right: 45px !important;
|
||||||
|
bottom: 0px !important;
|
||||||
|
background-color: #494949 !important;
|
||||||
|
-webkit-box-sizing: border-box !important;
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
line-height: 16px !important;
|
||||||
|
display: none;
|
||||||
|
height: 213px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trangle_right {
|
||||||
|
position: absolute;
|
||||||
|
right: -5px;
|
||||||
|
bottom: 15px;
|
||||||
|
width: 0;
|
||||||
|
height: 0px;
|
||||||
|
border-top: 6px solid transparent;
|
||||||
|
border-left: 5px solid #494949;
|
||||||
|
border-bottom: 6px solid transparent
|
||||||
|
}
|
||||||
|
|
|
@ -1,21 +1,154 @@
|
||||||
import React from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { AlignCenter , FlexAJ } from '../Component/layout';
|
import { AlignCenter , FlexAJ } from '../Component/layout';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import { Popover , Spin } from 'antd';
|
||||||
import { getImageUrl } from 'educoder';
|
import { getImageUrl } from 'educoder';
|
||||||
|
import './Component.scss';
|
||||||
|
import { getUser } from '../GetData/getData';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
function Contributors({contributors,owner,projectsId}){
|
function Contributors({contributors,owner,projectsId}){
|
||||||
|
const [ menuList ,setMenuList ]= useState([]);
|
||||||
|
const [ list , setList ]= useState(undefined);
|
||||||
|
const [ total , setTotal ]= useState(0);
|
||||||
|
const [ menu , setMenu ] = useState("");
|
||||||
|
const [ login , setLogin ] = useState(undefined);
|
||||||
|
const [ isSpin , setIsSpin ] = useState(false);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(contributors && contributors.total_count>0){
|
||||||
|
setTotal(contributors.total_count);
|
||||||
|
setList(contributors.list);
|
||||||
|
}
|
||||||
|
},[contributors])
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(login){
|
||||||
|
getUsers(login);
|
||||||
|
}else{
|
||||||
|
setMenu(undefined);
|
||||||
|
}
|
||||||
|
},[login])
|
||||||
|
|
||||||
|
async function getUsers(login){
|
||||||
|
setIsSpin(true);
|
||||||
|
let a = menuList && menuList.filter(i=>i.login === login);
|
||||||
|
if(a.length === 0){
|
||||||
|
let result = await getUser(login);
|
||||||
|
let arr = menuList;
|
||||||
|
arr.push({...result});
|
||||||
|
setMenuList(arr);
|
||||||
|
setMenusFunc(result);
|
||||||
|
setIsSpin(false);
|
||||||
|
}else{
|
||||||
|
setMenusFunc(a[0]);
|
||||||
|
setIsSpin(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMenusFunc(data){
|
||||||
|
if(data){
|
||||||
|
let ele = (
|
||||||
|
<Spin spinning={isSpin}>
|
||||||
|
<FlexAJ>
|
||||||
|
<AlignCenter>
|
||||||
|
<Link to={`/users/${data.login}`}><img src={getImageUrl(`/${data.image_url}`)} alt="" className="radius" width="38px" height="38px"/></Link>
|
||||||
|
<Link to={`/users/${data.login}`} className="ml10">{data.name}</Link>
|
||||||
|
</AlignCenter>
|
||||||
|
{
|
||||||
|
data.is_watch ? <a className="color-grey-9" onClick={()=>FocusFunc(false,data.login)}>取消关注</a>:<a className="color-blue" onClick={()=>FocusFunc(true,data.login)}>关注</a>
|
||||||
|
}
|
||||||
|
</FlexAJ>
|
||||||
|
<AlignCenter className="menuinfos">
|
||||||
|
<a href={data.projects_url}>
|
||||||
|
<span>{data.projects_count}</span>
|
||||||
|
<span>项目数</span>
|
||||||
|
</a>
|
||||||
|
<a href={data.followers_url}>
|
||||||
|
<span>{data.followers_count}</span>
|
||||||
|
<span>粉丝数</span>
|
||||||
|
</a>
|
||||||
|
<a href={data.following_url}>
|
||||||
|
<span>{data.following_count}</span>
|
||||||
|
<span>关注数</span>
|
||||||
|
</a>
|
||||||
|
</AlignCenter>
|
||||||
|
{
|
||||||
|
data.organizations && data.organizations.length > 0 ?
|
||||||
|
<AlignCenter className="font-12 pt4 pb4">
|
||||||
|
<span>所属组织:</span>
|
||||||
|
<div className="task-hide flex1">
|
||||||
|
{renderArray(data.organizations)}
|
||||||
|
</div>
|
||||||
|
</AlignCenter>
|
||||||
|
:""
|
||||||
|
}
|
||||||
|
{
|
||||||
|
data.location && <AlignCenter className="font-12 pt4 pb4"><span>所在地址:</span><span className="ml5">{data.location}</span></AlignCenter>
|
||||||
|
}
|
||||||
|
</Spin>
|
||||||
|
)
|
||||||
|
setMenu(ele);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function FocusFunc(flag,login){
|
||||||
|
axios({
|
||||||
|
method: flag ? 'post' : 'delete',
|
||||||
|
url: `/watchers/${flag ? 'follow' : 'unfollow'}.json`,
|
||||||
|
params: {target_type: "user",id:login}
|
||||||
|
}).then(result => {
|
||||||
|
if (result && (result.data.status === 0 || result.data.status === 2)) {
|
||||||
|
let a = menuList && menuList.filter(i=>i.login === login);
|
||||||
|
if(a){
|
||||||
|
a[0].is_watch = flag;
|
||||||
|
}
|
||||||
|
setMenusFunc(a[0]);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderArray(array){
|
||||||
|
let str = "";
|
||||||
|
for(var i = 0;i<array.length;i++){
|
||||||
|
str += array[i].name +"、";
|
||||||
|
}
|
||||||
|
let substr = str.substr(0,str.length-1);
|
||||||
|
return (<span title={substr}>{substr}</span>)
|
||||||
|
}
|
||||||
|
|
||||||
|
function setVisibleFunc(flag,l,index){
|
||||||
|
if(l !== login){
|
||||||
|
setLogin(l);
|
||||||
|
}
|
||||||
|
var lx = list.concat();
|
||||||
|
lx.map(i=>i.visible =false);
|
||||||
|
if(flag){
|
||||||
|
lx[index].visible = flag;
|
||||||
|
}
|
||||||
|
lx.splice();
|
||||||
|
setList(lx);
|
||||||
|
}
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div>
|
<div className="halfs">
|
||||||
<FlexAJ>
|
<FlexAJ>
|
||||||
<AlignCenter><span className="font-16 color-grey-6">贡献者</span>{ contributors && contributors.total_count > 0 && <span className="infoCount">{contributors.total_count}</span>}</AlignCenter>
|
<AlignCenter><span className="font-16 color-grey-6">贡献者</span>{ contributors && contributors.total_count > 0 && <span className="infoCount">{contributors.total_count}</span>}</AlignCenter>
|
||||||
<Link className="font-12 color-grey-9" to={`/projects/${owner}/${projectsId}/contribute`}>全部</Link>
|
<Link className="font-12 color-grey-9" to={`/projects/${owner}/${projectsId}/contribute`}>全部</Link>
|
||||||
</FlexAJ>
|
</FlexAJ>
|
||||||
<div className="attrPerson">
|
<div className="attrPerson" onMouseLeave={()=>setVisibleFunc(false)}>
|
||||||
{
|
{
|
||||||
contributors && contributors.total_count > 0 ?
|
total > 0 ?
|
||||||
contributors.list.map((item,key)=>{
|
list.map((item,key)=>{
|
||||||
return(
|
return(
|
||||||
<Link key={key} to={`/users/${item.login}`}><img src={getImageUrl(`images/${item.image_url}`)} alt=""/></Link>
|
<Popover content={menu} visible={item.visible} overlayClassName="menuPanels" placement="top">
|
||||||
|
<Link key={key} to={`/users/${item.login}`}>
|
||||||
|
<img src={getImageUrl(`/${item.image_url}`)} alt="" onMouseOver={()=>setVisibleFunc(true,item.login,key)}/>
|
||||||
|
</Link>
|
||||||
|
</Popover>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
:""
|
:""
|
||||||
|
|
|
@ -4,6 +4,12 @@ import './Component.scss';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
const { TreeNode , DirectoryTree } = Tree;
|
const { TreeNode , DirectoryTree } = Tree;
|
||||||
|
|
||||||
|
function turnbar(str){
|
||||||
|
if(str && str.length>0 && str.indexOf("/")>-1){
|
||||||
|
return str.replaceAll('/','%2F');
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
function DrawerPanel({visible,onClose,branch,owner,projectsId,history, name , list}){
|
function DrawerPanel({visible,onClose,branch,owner,projectsId,history, name , list}){
|
||||||
const [ treeData , setTreeData ] = useState(undefined);
|
const [ treeData , setTreeData ] = useState(undefined);
|
||||||
const [ isSpin , setIsSpin ] = useState(true);
|
const [ isSpin , setIsSpin ] = useState(true);
|
||||||
|
@ -71,7 +77,8 @@ function DrawerPanel({visible,onClose,branch,owner,projectsId,history, name , li
|
||||||
let dataref = event.node.props.dataRef;
|
let dataref = event.node.props.dataRef;
|
||||||
if(dataref.type==="file"){
|
if(dataref.type==="file"){
|
||||||
onClose();
|
onClose();
|
||||||
history.push(`/projects/${owner}/${projectsId}/tree/${branch}/${dataref.path}`);
|
let value = turnbar(branch);
|
||||||
|
history.push(`/projects/${owner}/${projectsId}/tree/${value}/${dataref.path}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
.ant-modal-mask{
|
||||||
|
z-index: 10000;
|
||||||
|
}
|
||||||
|
.ant-modal-wrap{
|
||||||
|
z-index: 10001;
|
||||||
|
.ant-form-explain{
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
import React , {forwardRef, useEffect} from 'react';
|
||||||
|
import { Modal , Form , Input , Button } from 'antd';
|
||||||
|
import './EAccount.scss';
|
||||||
|
|
||||||
|
function EducoderAccount({form , visible , onOk , email}){
|
||||||
|
const { getFieldDecorator, validateFields , setFieldsValue } = form;
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(email){
|
||||||
|
setFieldsValue({email})
|
||||||
|
}
|
||||||
|
},[email])
|
||||||
|
|
||||||
|
function onSure(){
|
||||||
|
validateFields((error,values)=>{
|
||||||
|
if(!error){
|
||||||
|
onOk(values);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const layout = {
|
||||||
|
labelCol: { span: 5 },
|
||||||
|
wrapperCol: { span: 18 },
|
||||||
|
};
|
||||||
|
return(
|
||||||
|
<Modal
|
||||||
|
visible={visible}
|
||||||
|
title="提示"
|
||||||
|
width="500px"
|
||||||
|
closable={false}
|
||||||
|
footer={
|
||||||
|
<Button type="primary" onClick={onSure}>确定</Button>
|
||||||
|
}
|
||||||
|
centered
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<p className="mb15 edu-txt-center" style={{maxWidth:"350px",margin:"0px auto"}}>
|
||||||
|
{
|
||||||
|
email ?
|
||||||
|
`平台已检测到您已绑定邮箱${email},请您确认如下操作`
|
||||||
|
:
|
||||||
|
"平台已检测到您未绑定邮箱,为不影响使用协同开发功能,请先绑定邮箱"
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
<Form {...layout}>
|
||||||
|
<Form.Item label="邮箱">
|
||||||
|
{getFieldDecorator("email",{
|
||||||
|
rules:[{required:true,message:"请输入邮箱账号"}]
|
||||||
|
})(
|
||||||
|
<Input placeholder="请输入您的邮箱账号" width="220px" disabled={email}/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="密码">
|
||||||
|
{getFieldDecorator("password",{
|
||||||
|
rules:[{required:true,message:"请输入您的平台密码"}]
|
||||||
|
})(
|
||||||
|
<Input.Password placeholder="请输入您的平台密码" width="220px"/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Form.create()(forwardRef(EducoderAccount));
|
|
@ -45,7 +45,7 @@ const Div = styled.div`{
|
||||||
export default (({ user , img, name, time, focusStatus, is_current_user, login , successFunc }) => {
|
export default (({ user , img, name, time, focusStatus, is_current_user, login , successFunc }) => {
|
||||||
return (
|
return (
|
||||||
<Div>
|
<Div>
|
||||||
<Link to={`/users/${user && user.login}`}><Img src={getImageUrl(`images/${img}`)} /></Link>
|
<Link to={`/users/${user && user.login}`}><Img src={getImageUrl(`/${img}`)} /></Link>
|
||||||
<div className="m-infos">
|
<div className="m-infos">
|
||||||
<Link to={`/users/${user && user.login}`}><Name>{name}</Name></Link>
|
<Link to={`/users/${user && user.login}`}><Name>{name}</Name></Link>
|
||||||
<Time><I className="iconfont icon-shijian"></I>加入时间:{time}</Time>
|
<Time><I className="iconfont icon-shijian"></I>加入时间:{time}</Time>
|
||||||
|
|
|
@ -23,7 +23,10 @@ function Releases({owner,projectsId,releaseVersions}){
|
||||||
<AlignTop className="mt10">
|
<AlignTop className="mt10">
|
||||||
<i className="iconfont icon-biaoqian3 color-grey-6 font-18 mr10"></i>
|
<i className="iconfont icon-biaoqian3 color-grey-6 font-18 mr10"></i>
|
||||||
<div>
|
<div>
|
||||||
<p className="font-16 color-grey-6"><Link to={`/projects/${owner}/${projectsId}/releases/8/update`}>{item.name}</Link></p>
|
<p className="font-16 color-grey-6">
|
||||||
|
<Link to={`/projects/${owner}/${projectsId}/releases`}>{item.name}</Link>
|
||||||
|
<span className="font-12 laterest ml5">最新</span>
|
||||||
|
</p>
|
||||||
<p className="color-grey-9 font-13">{item.created_at}</p>
|
<p className="color-grey-9 font-13">{item.created_at}</p>
|
||||||
</div>
|
</div>
|
||||||
</AlignTop>
|
</AlignTop>
|
||||||
|
|
|
@ -44,7 +44,7 @@ export default ({ getUser })=>{
|
||||||
className="user_img radius"
|
className="user_img radius"
|
||||||
width="28"
|
width="28"
|
||||||
height="28"
|
height="28"
|
||||||
src={getImageUrl(`images/${item && item.image_url}`)}
|
src={getImageUrl(`/${item && item.image_url}`)}
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
<span className="ml10" style={{ "vertical-align": "middle" }}>
|
<span className="ml10" style={{ "vertical-align": "middle" }}>
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Popover , Tooltip } from 'antd';
|
||||||
|
import './Component.scss';
|
||||||
|
import axios from 'axios';
|
||||||
|
import ShareModal from './SiderBarShareModal';
|
||||||
|
|
||||||
|
const $ = window.$;
|
||||||
|
|
||||||
|
$(window).scroll(function () {
|
||||||
|
if ($(".gotop").length > 0) {
|
||||||
|
if ($(document).scrollTop() > 0) {
|
||||||
|
$(".-task-sidebar .gotop").show();
|
||||||
|
$(".gotop").click(function () {
|
||||||
|
$("html,body").scrollTop(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ($(document).scrollTop() === 0) {
|
||||||
|
$(".-task-sidebar .gotop").hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function SiderBar() {
|
||||||
|
const [ data , setData ] = useState([]);
|
||||||
|
const [ visible , setVisible ] = useState(false);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
getFAQ();
|
||||||
|
},[])
|
||||||
|
|
||||||
|
function getFAQ(){
|
||||||
|
const url = `/faqs.json`;
|
||||||
|
axios.get(url).then(result=>{
|
||||||
|
if(result && result.data){
|
||||||
|
setData(result.data);
|
||||||
|
}
|
||||||
|
}).catch(error=>{})
|
||||||
|
}
|
||||||
|
function content(list){
|
||||||
|
return <div>
|
||||||
|
<p className="titlecontent">帮助</p>
|
||||||
|
<ul className="faqUl">
|
||||||
|
{
|
||||||
|
list && list.map((i,k)=>{
|
||||||
|
return(
|
||||||
|
<li><a href={`${i.url}`} title={i.question} target="_blank">{i.question}</a></li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
function shareContent(){
|
||||||
|
return <div>
|
||||||
|
<ul className="shareUl">
|
||||||
|
<p className="titlecontent">分享到</p>
|
||||||
|
<li onClick={()=>setVisible(true)}><i className="iconfont icon-weixin2" style={{color:"#62b900"}}></i></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className={"-task-sidebar"} >
|
||||||
|
<ShareModal visible={visible} urlValue={window.location.href} onCancel={()=>setVisible(false)}/>
|
||||||
|
{
|
||||||
|
data && data.length > 0 && (data[0] && data[0].question) ?
|
||||||
|
<Popover content={content(data)} overlayClassName="helpBox" placement={"left"}>
|
||||||
|
<div className="feedback">
|
||||||
|
<i className="iconfont icon-bangzhu font-22"></i>
|
||||||
|
</div>
|
||||||
|
</Popover>
|
||||||
|
:""
|
||||||
|
}
|
||||||
|
{/* <div className="scan pr" title="微信扫一扫">
|
||||||
|
<span className="inline erweima"><i className="iconfont icon-erweima color-white font-22 fl"></i></span>
|
||||||
|
</div>*/}
|
||||||
|
<Popover content={shareContent()} overlayClassName="helpBox shareContent" placement={"left"}>
|
||||||
|
<div className="consult">
|
||||||
|
<i className="iconfont icon-fenxiang1"></i>
|
||||||
|
</div>
|
||||||
|
</Popover>
|
||||||
|
<div className="gotop">
|
||||||
|
<Tooltip title="返回顶部" placement={"right"}>
|
||||||
|
<a><i className="iconfont icon-huidaodingbu1"></i></a>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SiderBar;
|
|
@ -0,0 +1,27 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Modal } from 'antd';
|
||||||
|
import QRCode from 'qrcode.react';
|
||||||
|
|
||||||
|
function SiderBarShareModal({visible,urlValue,onCancel}) {
|
||||||
|
return(
|
||||||
|
<Modal
|
||||||
|
title={"分享到微信"}
|
||||||
|
visible={visible}
|
||||||
|
width="500px"
|
||||||
|
closable={true}
|
||||||
|
footer={false}
|
||||||
|
onCancel={onCancel}
|
||||||
|
>
|
||||||
|
<div style={{textAlign:"center"}}>
|
||||||
|
{urlValue &&<QRCode
|
||||||
|
value={urlValue}
|
||||||
|
size={200}
|
||||||
|
fgColor="#000000"
|
||||||
|
style={{margin:"20px"}}
|
||||||
|
/>}
|
||||||
|
<p>打开微信“扫一扫”,点击右上角菜单,即可将网页分享至朋友圈</p>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default SiderBarShareModal;
|
|
@ -28,6 +28,11 @@ export const AlignTop = styled.div`{
|
||||||
display:flex;
|
display:flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}`
|
}`
|
||||||
|
export const AlignAJBottom = styled.div`{
|
||||||
|
display:flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-end;
|
||||||
|
}`
|
||||||
// 左右结构
|
// 左右结构
|
||||||
export const Box = styled.div`{
|
export const Box = styled.div`{
|
||||||
display:flex;
|
display:flex;
|
||||||
|
|
|
@ -37,7 +37,7 @@ function About(props, ref) {
|
||||||
const [ typeFlag, setTypeFlag] = useState(false);
|
const [ typeFlag, setTypeFlag] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
const AuthorLogin = props.author && props.author.login;
|
const AuthorLogin = props.projectDetail && props.projectDetail.author && props.projectDetail.author.login;
|
||||||
const CurrentLogin = props.current_user && props.current_user.login;
|
const CurrentLogin = props.current_user && props.current_user.login;
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if(CurrentLogin === AuthorLogin){
|
if(CurrentLogin === AuthorLogin){
|
||||||
|
@ -176,12 +176,12 @@ function About(props, ref) {
|
||||||
CurrentLogin !== AuthorLogin ?
|
CurrentLogin !== AuthorLogin ?
|
||||||
<div className="noOperation">DevOps开启功能暂未对项目创建者以外的角色开放,可以联系项目创建者进行开启,开启后便可查看构建信息。</div>:""
|
<div className="noOperation">DevOps开启功能暂未对项目创建者以外的角色开放,可以联系项目创建者进行开启,开启后便可查看构建信息。</div>:""
|
||||||
}
|
}
|
||||||
<a href={"https://forum.trustie.net/forums/3110/detail"} target="_blank" style={{ color: "#5091FF"}}>
|
{/* <a href={"https://forum.trustie.net/forums/3110/detail"} target="_blank" style={{ color: "#5091FF"}}>
|
||||||
了解什么是DevOps?
|
了解什么是DevOps?
|
||||||
</a>
|
</a>
|
||||||
<a href={"https://forum.trustie.net/forums/3080/detail"} target="_blank" style={{ color: "#5091FF"}}>
|
<a href={"https://forum.trustie.net/forums/3080/detail"} target="_blank" style={{ color: "#5091FF"}}>
|
||||||
如何使用DevOps?
|
如何使用DevOps?
|
||||||
</a>
|
</a> */}
|
||||||
{
|
{
|
||||||
AuthorLogin === CurrentLogin ?
|
AuthorLogin === CurrentLogin ?
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
@ -233,7 +233,7 @@ function About(props, ref) {
|
||||||
step === 1 ?
|
step === 1 ?
|
||||||
<div>
|
<div>
|
||||||
<AlignCenter style={{justifyContent:"center",marginTop:"20px"}}>
|
<AlignCenter style={{justifyContent:"center",marginTop:"20px"}}>
|
||||||
<span style={{marginBottom:"42px"}}>密码:</span>
|
<span className="mb40">密码:</span>
|
||||||
<div>
|
<div>
|
||||||
<Input.Password value={authorityVal} className={authorityValFlag===true && "flags"} onChange={(e)=>setAuthorityVal(e.target.value)} style={{width:"220px"}}></Input.Password>
|
<Input.Password value={authorityVal} className={authorityValFlag===true && "flags"} onChange={(e)=>setAuthorityVal(e.target.value)} style={{width:"220px"}}></Input.Password>
|
||||||
<p className="color-grey-9" style={{textAlign:"left",lineHeight:'21px'}}>您已保存相关服务器信息,请输入密码,<br/>确认授权DevOps应用</p>
|
<p className="color-grey-9" style={{textAlign:"left",lineHeight:'21px'}}>您已保存相关服务器信息,请输入密码,<br/>确认授权DevOps应用</p>
|
||||||
|
|
|
@ -10,6 +10,12 @@ import { Link } from 'react-router-dom';
|
||||||
// killed:"已撤销",
|
// killed:"已撤销",
|
||||||
// pending:"准备中"
|
// pending:"准备中"
|
||||||
// }
|
// }
|
||||||
|
function turnbar(str){
|
||||||
|
if(str && str.length>0 && str.indexOf("/")>-1){
|
||||||
|
return str.replaceAll('/','%2F');
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
function renderTableStatus(status) {
|
function renderTableStatus(status) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case "running":
|
case "running":
|
||||||
|
@ -65,8 +71,9 @@ function List({ list, operate , projectsId , owner , showModal , deleteFunc }){
|
||||||
width:"15%",
|
width:"15%",
|
||||||
ellipsis:true,
|
ellipsis:true,
|
||||||
render:(value,item)=>{
|
render:(value,item)=>{
|
||||||
|
let v = turnbar(item.branch);
|
||||||
return(
|
return(
|
||||||
<Link to={`/projects/${owner}/${projectsId}/tree/${item.branch}/${value}`} className="color-blue">{value}</Link>
|
<Link to={`/projects/${owner}/${projectsId}/tree/${v}/${value}`} className="color-blue">{value}</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,7 +12,7 @@ function ServiceModal({sureModal}){
|
||||||
<div className="mt30" style={{textAlign:"center"}}>
|
<div className="mt30" style={{textAlign:"center"}}>
|
||||||
<Radio.Group value={type} onChange={changeType}>
|
<Radio.Group value={type} onChange={changeType}>
|
||||||
<Radio value={1}>自有服务器</Radio>
|
<Radio value={1}>自有服务器</Radio>
|
||||||
<Radio value={2}>Trustie服务器</Radio>
|
<Radio value={2}>平台服务器</Radio>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
<p className="mt30"><Button type="primary" onClick={()=>sureModal(type)}>下一步</Button></p>
|
<p className="mt30"><Button type="primary" onClick={()=>sureModal(type)}>下一步</Button></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { useState, useEffect , useImperativeHandle ,forwardRef } from "re
|
||||||
import { FlexAJ, AlignCenter , Banner } from "../Component/layout";
|
import { FlexAJ, AlignCenter , Banner } from "../Component/layout";
|
||||||
import { Table, Pagination, Popconfirm } from "antd";
|
import { Table, Pagination, Popconfirm } from "antd";
|
||||||
import { truncateCommitId } from "../common/util";
|
import { truncateCommitId } from "../common/util";
|
||||||
import {getUrl} from 'educoder';
|
import { getImageUrl } from 'educoder';
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ function Structure(props,ref){
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
author:item.author && item.author.name,
|
author:item.author && item.author.name,
|
||||||
|
image_url:item.author && item.author.image_url,
|
||||||
message: {
|
message: {
|
||||||
branch: item.branch_target,
|
branch: item.branch_target,
|
||||||
message: item.message,
|
message: item.message,
|
||||||
|
@ -244,7 +245,7 @@ function Structure(props,ref){
|
||||||
{meg.sha && <span className="color-orange">{meg.sha}</span>}
|
{meg.sha && <span className="color-orange">{meg.sha}</span>}
|
||||||
</div>
|
</div>
|
||||||
<AlignCenter>
|
<AlignCenter>
|
||||||
<img style={{borderRadius:"50%",marginRight:"10px",width:"25px",height:"25px"}} src={`${current_user && getUrl(`/images/${current_user.image_url}`)}`} />
|
<img style={{borderRadius:"50%",marginRight:"10px",width:"25px",height:"25px"}} alt="" src={`${item.image_url && getImageUrl(`/${item.image_url}`)}`} />
|
||||||
<div className="task-hide ml5" style={{ maxWidth: "300px" }}>
|
<div className="task-hide ml5" style={{ maxWidth: "300px" }}>
|
||||||
{meg.message}
|
{meg.message}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
import React ,{ forwardRef, useEffect, useState } from 'react';
|
||||||
|
import { Modal , Form , Input , Radio , Select } from 'antd';
|
||||||
|
import SearchUser from '../Component/SearchUser';
|
||||||
|
import './Index.scss';
|
||||||
|
import Axios from 'axios';
|
||||||
|
|
||||||
|
const { Option } = Select;
|
||||||
|
function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
|
||||||
|
const { getFieldDecorator, validateFields , setFieldsValue } = form;
|
||||||
|
const [ cate , setCate ] = useState(0);
|
||||||
|
const [ value , setValue ] = useState(undefined);
|
||||||
|
|
||||||
|
const [ organizations , setOrganizations ] = useState(undefined);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
setFieldsValue({goal:cate})
|
||||||
|
},[])
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(owner && repo && visible===true){
|
||||||
|
getTeam();
|
||||||
|
}
|
||||||
|
if(!visible){
|
||||||
|
setFieldsValue({
|
||||||
|
owner_name:undefined,
|
||||||
|
identifier:undefined
|
||||||
|
})
|
||||||
|
setValue(undefined)
|
||||||
|
}
|
||||||
|
},[repo,owner,visible])
|
||||||
|
|
||||||
|
function getTeam(){
|
||||||
|
const url = `/${owner}/${repo}/applied_transfer_projects/organizations.json`;
|
||||||
|
Axios.get(url).then(result=>{
|
||||||
|
if(result){
|
||||||
|
setOrganizations(result.data.organizations);
|
||||||
|
}
|
||||||
|
}).catch(error=>{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认转移
|
||||||
|
function onOk(){
|
||||||
|
validateFields((error,values)=>{
|
||||||
|
console.log(...values);
|
||||||
|
if(!error){
|
||||||
|
const url = `/${owner}/${repo}/applied_transfer_projects.json`;
|
||||||
|
Axios.post(url,{
|
||||||
|
...values
|
||||||
|
}).then(result=>{
|
||||||
|
if(result){
|
||||||
|
onSuccess(result.data && result.data.owner);
|
||||||
|
}
|
||||||
|
}).catch(error=>{})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
function changeType(e){
|
||||||
|
setCate(e.target.value);
|
||||||
|
setFieldsValue({
|
||||||
|
owner_name:undefined
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkIdentifier(rule, value, callback){
|
||||||
|
if(!value){
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
if (repo && value !== repo) {
|
||||||
|
callback("请输入当前项目的标识!");
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
const layout = {
|
||||||
|
labelCol: { span: 5 },
|
||||||
|
wrapperCol: { span: 18 },
|
||||||
|
};
|
||||||
|
|
||||||
|
function getUser(id){
|
||||||
|
setValue(id);
|
||||||
|
setFieldsValue({
|
||||||
|
owner_name:id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return(
|
||||||
|
<Modal
|
||||||
|
width="620px"
|
||||||
|
visible={visible}
|
||||||
|
title="转移仓库"
|
||||||
|
onCancel={onCancel}
|
||||||
|
onOk={onOk}
|
||||||
|
okText="确认转移"
|
||||||
|
cancelText={"取消"}
|
||||||
|
centered
|
||||||
|
>
|
||||||
|
<div className="diverModal">
|
||||||
|
{
|
||||||
|
cate === 0 ?
|
||||||
|
<ul className="descUl">
|
||||||
|
<li>转移需对方确认接受,转移成功后你将被移出仓库,其他已有成员权限不变</li>
|
||||||
|
<li>转移成功后,仓库的地址将变更至目标用户的命名空间下</li>
|
||||||
|
<li>已有成员如需继续操作仓库,需更新本地仓库的remote,使之指向新的地址</li>
|
||||||
|
</ul>
|
||||||
|
:
|
||||||
|
<ul className="descUl">
|
||||||
|
<li>仓库仅可以转移到您已经加入的组织中,不可以转移到未加入的组织中</li>
|
||||||
|
<li>涉及到仓库改名操作,请提前做好仓库备份并且在转移后对本地仓库的remote进行修改</li>
|
||||||
|
<li>转移仓库到组织后,你和组织创建者/管理员同时拥有对该仓库的管理操作</li>
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
<Form {...layout} colon={false} layout={"horizontal"}>
|
||||||
|
<Form.Item label="转移给:" style={{marginBottom:"0px"}}>
|
||||||
|
{getFieldDecorator("goal",{
|
||||||
|
rules:[]
|
||||||
|
})(
|
||||||
|
<Radio.Group onChange={changeType}>
|
||||||
|
<Radio value={0}>个人</Radio>
|
||||||
|
<Radio value={1}>组织</Radio>
|
||||||
|
</Radio.Group>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
{
|
||||||
|
cate === 0 &&
|
||||||
|
<Form.Item label=" ">
|
||||||
|
{getFieldDecorator("owner_name",{
|
||||||
|
rules:[{required:true,message:"请输入目标用户名"}]
|
||||||
|
})(
|
||||||
|
// <Input placeholder="请输入目标用户" autoComplete={"off"}/>
|
||||||
|
<SearchUser getUser={getUser} width={"100%"} placeholder="请输入目标用户" value={value}/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
cate === 1 &&
|
||||||
|
<Form.Item label=" ">
|
||||||
|
{getFieldDecorator("owner_name",
|
||||||
|
{rules:[{required:true,message:"请选择目标组织"}]}
|
||||||
|
)(
|
||||||
|
<Select placeholder="请选择目标组织" getPopupContainer={trigger => trigger.parentNode}>
|
||||||
|
{
|
||||||
|
organizations && organizations.length > 0 ?
|
||||||
|
organizations.map((i,k)=>{
|
||||||
|
return(
|
||||||
|
<Option value={i.name}>{i.nickname}</Option>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
:""
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
}
|
||||||
|
|
||||||
|
<Form.Item label="仓库名称:">
|
||||||
|
{getFieldDecorator("identifier",
|
||||||
|
{
|
||||||
|
rules:[
|
||||||
|
{required:true,message:"请输入仓库名称"},
|
||||||
|
{
|
||||||
|
validator:checkIdentifier
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)(
|
||||||
|
<Input placeholder="请输入仓库名称" autoComplete={"off"}/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Form.create()(forwardRef(DivertModal));
|
|
@ -0,0 +1,107 @@
|
||||||
|
import React, { useEffect } from 'react';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
|
function Index(props) {
|
||||||
|
useEffect(()=>{
|
||||||
|
Init();
|
||||||
|
},[])
|
||||||
|
|
||||||
|
function Init() {
|
||||||
|
var myCharts = document.getElementById('main');
|
||||||
|
var myEcharts = echarts.init(myCharts);
|
||||||
|
var option = {
|
||||||
|
title: {
|
||||||
|
text: '项目实施进度表',
|
||||||
|
left: 10
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
y: 'bottom',
|
||||||
|
data: ['计划时间', '实际时间'] //修改的地方1
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
containLabel: true,
|
||||||
|
left: 20
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'time'
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
data: ['任务一', '任务二', '任务三', '任务四', '任务五', '任务六', '任务七']
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
formatter: function(params) {
|
||||||
|
var res = params[0].name + "</br>"
|
||||||
|
var date0 = params[0].data;
|
||||||
|
var date1 = params[1].data;
|
||||||
|
var date2 = params[2].data;
|
||||||
|
var date3 = params[3].data;
|
||||||
|
date0 = date0.getFullYear() + "-" + (date0.getMonth() + 1) + "-" + date0.getDate();
|
||||||
|
date1 = date1.getFullYear() + "-" + (date1.getMonth() + 1) + "-" + date1.getDate();
|
||||||
|
date2 = date2.getFullYear() + "-" + (date2.getMonth() + 1) + "-" + date2.getDate();
|
||||||
|
date3 = date3.getFullYear() + "-" + (date3.getMonth() + 1) + "-" + date3.getDate();
|
||||||
|
res += params[0].seriesName + "~" + params[1].seriesName + ":</br>" + date0 + "~" + date1 + "</br>"
|
||||||
|
res += params[2].seriesName + "~" + params[3].seriesName + ":</br>" + date2 + "~" + date3 + "</br>"
|
||||||
|
console.log(params[0]);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '计划开始时间',
|
||||||
|
type: 'bar',
|
||||||
|
stack: 'test1',
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: 'rgba(0,0,0,0)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '计划时间',
|
||||||
|
type: 'bar',
|
||||||
|
stack: 'test1',
|
||||||
|
//修改地方2
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: '#F98563'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '实际开始时间',
|
||||||
|
type: 'bar',
|
||||||
|
stack: 'test2',
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: 'rgba(0,0,0,0)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '实际时间',
|
||||||
|
type: 'bar',
|
||||||
|
stack: 'test2',
|
||||||
|
//修改地方3
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: '#A2E068'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
myEcharts.setOption(option);
|
||||||
|
}
|
||||||
|
return(
|
||||||
|
<div className="ganttBox">
|
||||||
|
<div id="main" style={{height:"500px"}}></div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Index;
|
|
@ -0,0 +1,5 @@
|
||||||
|
.ganttBox{
|
||||||
|
width: 1200px;
|
||||||
|
margin:0px auto;
|
||||||
|
padding:22px 0px;
|
||||||
|
}
|
|
@ -15,3 +15,7 @@ export const getHooks = async (id,params)=>{
|
||||||
export const getSubEntries = async (owner,projectsId,params)=>{
|
export const getSubEntries = async (owner,projectsId,params)=>{
|
||||||
return (await axios.get(`/${owner}/${projectsId}/sub_entries.json`,{params})).data;
|
return (await axios.get(`/${owner}/${projectsId}/sub_entries.json`,{params})).data;
|
||||||
}
|
}
|
||||||
|
// 获取用户信息
|
||||||
|
export const getUser = async (login)=>{
|
||||||
|
return (await axios.get(`/users/${login}/hovercard.json`)).data;
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
import React, { useState , forwardRef, useEffect } from 'react';
|
||||||
|
import { Form , Modal , Input , Radio } from 'antd';
|
||||||
|
import Axios from 'axios';
|
||||||
|
|
||||||
|
export default Form.create()(
|
||||||
|
forwardRef((props)=>{
|
||||||
|
const { getFieldDecorator, validateFields , setFieldsValue } = props && props.form;
|
||||||
|
const [ visible , setVisible ] = useState(false);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(!visible){
|
||||||
|
setFieldsValue({
|
||||||
|
code:undefined,
|
||||||
|
role:"developer"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},[visible])
|
||||||
|
|
||||||
|
function onOk() {
|
||||||
|
validateFields((error,values)=>{
|
||||||
|
if(!error){
|
||||||
|
const url = `/applied_projects.json`;
|
||||||
|
Axios.post(url,{
|
||||||
|
applied_project:{
|
||||||
|
...values
|
||||||
|
}
|
||||||
|
}).then(result=>{
|
||||||
|
if(result && result.data){
|
||||||
|
setVisible(false);
|
||||||
|
props.showNotification("申请加入项目成功,等待审核!");
|
||||||
|
}
|
||||||
|
}).catch(error=>{})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function checkValue(rule, value, callback){
|
||||||
|
if(!value){
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
if(value.length < 6 || value.length > 6){
|
||||||
|
callback("请输入6位数的邀请码");
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
return(
|
||||||
|
<React.Fragment>
|
||||||
|
<Modal
|
||||||
|
title="加入项目"
|
||||||
|
width="480px"
|
||||||
|
visible={visible}
|
||||||
|
centered={true}
|
||||||
|
onOk={onOk}
|
||||||
|
onCancel={()=>setVisible(false)}
|
||||||
|
>
|
||||||
|
<Form layout={'inline'} className="inviteForm">
|
||||||
|
<Form.Item label="项目邀请码">
|
||||||
|
{getFieldDecorator("code",{
|
||||||
|
rules:[
|
||||||
|
{required:true,message:"请输入6位项目邀请码"},
|
||||||
|
{validator:checkValue}
|
||||||
|
]
|
||||||
|
})(
|
||||||
|
<Input placeholder="请输入6位项目邀请码" autoComplete={"off"} maxLength="6" style={{width:"300px"}}/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="选择角色">
|
||||||
|
{getFieldDecorator("role",{
|
||||||
|
rules:[{required:true,message:"请选择角色"}]
|
||||||
|
})(
|
||||||
|
<Radio.Group defaultValue={"developer"}>
|
||||||
|
<Radio value="manager">管理员</Radio>
|
||||||
|
<Radio value="developer">开发者</Radio>
|
||||||
|
<Radio value="reporter">报告者</Radio>
|
||||||
|
</Radio.Group>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
<a onClick={()=>setVisible(true)}>加入项目</a>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
|
@ -0,0 +1,66 @@
|
||||||
|
import React, { useEffect , useState } from 'react';
|
||||||
|
import './header.scss';
|
||||||
|
|
||||||
|
function Footer(){
|
||||||
|
const [ value , setValue ] = useState(undefined);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
try {
|
||||||
|
var chromesettingArray = JSON.parse(localStorage.getItem('chromesetting'));
|
||||||
|
setValue(chromesettingArray.footer);
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
},[])
|
||||||
|
|
||||||
|
function showhtml(htmlString){
|
||||||
|
var html = {__html:htmlString};
|
||||||
|
return <div dangerouslySetInnerHTML={html}></div> ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div>
|
||||||
|
<div style={{height:"810px"}}></div>
|
||||||
|
<div className="newFooter edu-txt-center">
|
||||||
|
{value && showhtml(value)}
|
||||||
|
{/* <div className="footerInfos">
|
||||||
|
<ul>
|
||||||
|
<li>社区</li>
|
||||||
|
<li><a href={`/`} target="_blank">网站首页</a></li>
|
||||||
|
<li><a href={`https://www.trustie.net/agreement`} target="_blank">服务协议</a></li>
|
||||||
|
<li><a href={`https://forum.trustie.net/forums/1168/detail`} target="_blank">帮助中心</a></li>
|
||||||
|
<li><a href={`https://forum.trustie.net/`} target="_blank">问吧交流</a></li>
|
||||||
|
<li><a href={`https://www.trustie.net/cooperation`} target="_blank">合作伙伴</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>支持与服务</li>
|
||||||
|
<li><a href={`https://forgeplus.trustie.net/docs/api`} target="_blank">API文档</a></li>
|
||||||
|
<li><a href={`https://forum.trustie.net/forums/1168/detail`} target="_blank">帮助中心</a></li>
|
||||||
|
<li><a href={`https://git-scm.com`} target="_blank">Git常用命令</a></li>
|
||||||
|
<li><a href={`https://forum.trustie.net/forums/3080/detail`} target="_blank">DevOps使用文档</a></li>
|
||||||
|
<li><a href={`https://forgeplus.trustie.net/projects/jasder/forgeplus/tree/master/CHANGELOG.md`} target="_blank">日志更新</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>合作伙伴</li>
|
||||||
|
<li><a href={`http://www.sei.pku.edu.cn`} target="_blank">北京大学</a></li>
|
||||||
|
<li><a href={`http://scse.buaa.edu.cn`} target="_blank">北京航空航天大学</a></li>
|
||||||
|
<li><a href={`https://www.nju.edu.cn`} target="_blank">南京大学</a></li>
|
||||||
|
<li><a href={`https://www.xtu.edu.cn`} target="_blank">湘潭大学</a></li>
|
||||||
|
<li><a href={`http://www.iscas.ac.cn`} target="_blank">ISCAS</a></li>
|
||||||
|
<li><a href={`https://www.ucloud.cn`} target="_blank">UCloud优刻得</a></li>
|
||||||
|
<li><a href={`http://www.inforbus.com`} target="_blank">中创软件</a></li>
|
||||||
|
<li><a href={`https://www.inspur.com`} target="_blank">浪潮集团</a></li>
|
||||||
|
<li><a href={`http://www.copu.org.cn`} target="_blank">中国开源软件推进联盟</a></li>
|
||||||
|
<li><a href={`https://www.sjtu.edu.cn`} target="_blank">上海交通大学</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>合作伙伴</li>
|
||||||
|
<li><span>热线:</span></li>
|
||||||
|
<li><span>QQ群:1071514693</span></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<p className="footerCopy">© Copyright 2007~2021 国防科技大学Trustie团队 & IntelliDE <a href="https://beian.miit.gov.cn">湘ICP备 17009477号</a></p> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Footer;
|
|
@ -2,16 +2,11 @@ import React, { Component } from 'react';
|
||||||
import AccountProfile from "../../modules/user/AccountProfile";
|
import AccountProfile from "../../modules/user/AccountProfile";
|
||||||
import { getImageUrl } from 'educoder'
|
import { getImageUrl } from 'educoder'
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { Modal, Input, message, notification , Dropdown , Menu ,Divider } from 'antd';
|
import { Input , notification , Dropdown , Menu } from 'antd';
|
||||||
|
|
||||||
import LoginDialog from '../../modules/login/LoginDialog';
|
import LoginDialog from '../../modules/login/LoginDialog';
|
||||||
import GotoQQgroup from '../../modal/GotoQQgroup'
|
import AddProjectModal from './AddProjectModal';
|
||||||
// import 'antd/lib/modal/style/index.css';
|
|
||||||
// import 'antd/lib/checkbox/style/index.css';
|
|
||||||
// import 'antd/lib/radio/style/index.css';
|
|
||||||
// import 'antd/lib/input/style/index.css';
|
|
||||||
import '../../modules/tpm/TPMIndex.css';
|
import '../../modules/tpm/TPMIndex.css';
|
||||||
import logo from '../../modules/tpm/images/logo.png';
|
|
||||||
import './header.scss';
|
import './header.scss';
|
||||||
const $ = window.$
|
const $ = window.$
|
||||||
// TODO 这部分脚本从公共脚本中直接调用
|
// TODO 这部分脚本从公共脚本中直接调用
|
||||||
|
@ -35,11 +30,9 @@ class NewHeader extends Component {
|
||||||
Checkboxteachertype: false,
|
Checkboxteachertype: false,
|
||||||
Checkboxteachingtype: false,
|
Checkboxteachingtype: false,
|
||||||
code_notice: false,
|
code_notice: false,
|
||||||
checked_notice: false,
|
|
||||||
RadioGroupvalue: undefined,
|
RadioGroupvalue: undefined,
|
||||||
submitapplications: false,
|
submitapplications: false,
|
||||||
isRender: false,
|
isRender: false,
|
||||||
showSearchOpentype: false,
|
|
||||||
showTrial: false,
|
showTrial: false,
|
||||||
setevaluatinghides: false,
|
setevaluatinghides: false,
|
||||||
occupation: 0,
|
occupation: 0,
|
||||||
|
@ -47,13 +40,11 @@ class NewHeader extends Component {
|
||||||
headtypesonClickbool: false,
|
headtypesonClickbool: false,
|
||||||
headtypess: "/",
|
headtypess: "/",
|
||||||
settings: null,
|
settings: null,
|
||||||
goshowqqgtounp: false,
|
|
||||||
visiblemyss: false,
|
visiblemyss: false,
|
||||||
openSearch:false,
|
openSearch:false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
// this.getAppdata();
|
|
||||||
this.geturlsdata();
|
this.geturlsdata();
|
||||||
window._header_componentHandler = this;
|
window._header_componentHandler = this;
|
||||||
|
|
||||||
|
@ -96,22 +87,23 @@ class NewHeader extends Component {
|
||||||
}, 300)
|
}, 300)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Search placeholder="实践课程/教学课堂/实践项目/交流问答"
|
<Search placeholder="请输入搜索关键字"
|
||||||
className={`search-input mr20`}
|
className={`search-input mr20`}
|
||||||
onSearch={(value)=>this.onGlobalSearch(value,item)}
|
onSearch={(value)=>this.onGlobalSearch(value,item)}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
|
style={{width:"260px"}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}else{
|
}else{
|
||||||
return <i className="iconfont icon-sousuo font-18 color-grey-6 ml30" onClick={() => {
|
return <i className="iconfont icon-sousuo font-18 color-white ml30" onClick={() => {
|
||||||
this.setState({openSearch:true})
|
this.setState({openSearch:true})
|
||||||
}} />
|
}} />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onGlobalSearch=(value,item)=>{
|
onGlobalSearch=(value,item)=>{
|
||||||
window.location.href=`${item && item.url}?value=` + value;
|
window.location.href=`${item}?value=` + value;
|
||||||
}
|
}
|
||||||
|
|
||||||
openNotification = (messge) => {
|
openNotification = (messge) => {
|
||||||
|
@ -132,158 +124,8 @@ class NewHeader extends Component {
|
||||||
old_url = newProps.Headertop.old_url
|
old_url = newProps.Headertop.old_url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getCookie = (key) => {
|
|
||||||
var arr, reg = RegExp('(^| )' + key + '=([^;]+)(;|$)');
|
|
||||||
if (arr === document.cookie.match(reg))
|
|
||||||
return decodeURIComponent(arr[2]);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
delCookie = (name) => {
|
|
||||||
var exp = new Date();
|
|
||||||
exp.setTime(exp.getTime() - 1);
|
|
||||||
var cval = this.getCookie(name);
|
|
||||||
if (cval != null) {
|
|
||||||
document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onLogout = () => {
|
|
||||||
const url = `/accounts/logout.json`
|
|
||||||
this.delCookie("autologin_trustie")
|
|
||||||
axios.get(url, {
|
|
||||||
}).then((response) => {
|
|
||||||
if (response.data.status === 1) {
|
|
||||||
this.setState({
|
|
||||||
user: undefined
|
|
||||||
})
|
|
||||||
window.location.href = "/login"
|
|
||||||
message.success('退出成功');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
tojoinclass = () => {
|
|
||||||
let { user } = this.state;
|
|
||||||
if (user === undefined) {
|
|
||||||
this.setState({
|
|
||||||
isRender: true
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (user && user.login === "") {
|
|
||||||
this.setState({
|
|
||||||
isRender: true
|
|
||||||
})
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (user && user.profile_completed === false) {
|
|
||||||
this.setState({
|
|
||||||
AccountProfiletype: true
|
|
||||||
})
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
Addcoursestypes: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
tojoinitem = () => {
|
|
||||||
if (this.props.user && this.props.user.email === undefined || this.props.user && this.props.user.email === null || this.props.user && this.props.user.email === "") {
|
|
||||||
this.openNotification("请先绑定邮箱,谢谢");
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let { user } = this.state;
|
|
||||||
if (user === undefined) {
|
|
||||||
this.setState({
|
|
||||||
isRender: true
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (user && user.login === "") {
|
|
||||||
this.setState({
|
|
||||||
isRender: true
|
|
||||||
})
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user && user.profile_completed === false) {
|
|
||||||
this.setState({
|
|
||||||
AccountProfiletype: true
|
|
||||||
})
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
tojoinitemtype: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
submitstatevalue = (sum, value, data) => {
|
|
||||||
this.setState({
|
|
||||||
Addcoursestypes: false,
|
|
||||||
tojoinitemtype: false,
|
|
||||||
tojoinclasstitle: undefined,
|
|
||||||
rolearr: ["", ""],
|
|
||||||
Checkboxteacherchecked: false,
|
|
||||||
Checkboxstudentchecked: false,
|
|
||||||
Checkboxteachingchecked: false,
|
|
||||||
Checkboxteachertype: false,
|
|
||||||
Checkboxteachingtype: false,
|
|
||||||
code_notice: false,
|
|
||||||
checked_notice: false,
|
|
||||||
submitapplicationssum: sum,
|
|
||||||
submitapplications: true,
|
|
||||||
submitapplicationsvalue: value,
|
|
||||||
submitapplicationsvaluedata: data,
|
|
||||||
RadioGroupvalue: undefined
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onChangeRadioGroup = (e) => {
|
|
||||||
this.setState({
|
|
||||||
RadioGroupvalue: e.target.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
submitsubmitapplications = () => {
|
|
||||||
let {
|
|
||||||
submitapplicationssum,
|
|
||||||
submitapplicationsvaluedata
|
|
||||||
} = this.state;
|
|
||||||
this.setState({
|
|
||||||
submitapplications: false,
|
|
||||||
RadioGroupvalue: undefined
|
|
||||||
})
|
|
||||||
if (submitapplicationssum === 0) {
|
|
||||||
if (submitapplicationsvaluedata !== undefined) {
|
|
||||||
window.location.href = "/courses/" + submitapplicationsvaluedata;
|
|
||||||
}
|
|
||||||
} else if (submitapplicationssum === 1) {
|
|
||||||
if (submitapplicationsvaluedata !== undefined) {
|
|
||||||
window.location.href = "/projects/" + submitapplicationsvaluedata;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hidesubmitapplications = () => {
|
|
||||||
this.setState({
|
|
||||||
Addcoursestypes: false,
|
|
||||||
tojoinitemtype: false,
|
|
||||||
tojoinclasstitle: undefined,
|
|
||||||
rolearr: ["", ""],
|
|
||||||
Checkboxteacherchecked: false,
|
|
||||||
Checkboxstudentchecked: false,
|
|
||||||
Checkboxteachingchecked: false,
|
|
||||||
Checkboxteachertype: false,
|
|
||||||
Checkboxteachingtype: false,
|
|
||||||
code_notice: false,
|
|
||||||
checked_notice: false,
|
|
||||||
submitapplications: false,
|
|
||||||
RadioGroupvalue: undefined
|
|
||||||
})
|
|
||||||
}
|
|
||||||
educoderlogin = () => {
|
educoderlogin = () => {
|
||||||
//登录账号
|
//登录账号
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -322,23 +164,6 @@ class NewHeader extends Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
hidetojoinclass = () => {
|
|
||||||
this.setState({
|
|
||||||
tojoinclasstype: false,
|
|
||||||
tojoinitemtype: false,
|
|
||||||
tojoinclasstitle: undefined,
|
|
||||||
rolearr: ["", ""],
|
|
||||||
Checkboxteacherchecked: false,
|
|
||||||
Checkboxstudentchecked: false,
|
|
||||||
Checkboxteachingchecked: false,
|
|
||||||
Checkboxteachertype: false,
|
|
||||||
Checkboxteachingtype: false,
|
|
||||||
code_notice: false,
|
|
||||||
checked_notice: false,
|
|
||||||
RadioGroupvalue: undefined
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭
|
// 关闭
|
||||||
cancelModulationModels = () => {
|
cancelModulationModels = () => {
|
||||||
this.setState({ isRenders: false })
|
this.setState({ isRenders: false })
|
||||||
|
@ -404,39 +229,13 @@ class NewHeader extends Component {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getAppdata = () => {
|
|
||||||
try {
|
|
||||||
var chromesettingArray = JSON.parse(localStorage.getItem('chromesetting'));
|
|
||||||
var chromesettingresponseArray = JSON.parse(localStorage.getItem('chromesettingresponse'));
|
|
||||||
this.setState({
|
|
||||||
settings: chromesettingArray
|
|
||||||
});
|
|
||||||
if (chromesettingArray.tab_logo_url) {
|
|
||||||
this.gettablogourldata(chromesettingresponseArray);
|
|
||||||
} else {
|
|
||||||
this.gettablogourlnull();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.geturlsdata();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
geturlsdata = () => {
|
geturlsdata = () => {
|
||||||
let url = "/setting.json";
|
let url = "/setting.json";
|
||||||
axios.get(url).then((response) => {
|
axios.get(url).then((response) => {
|
||||||
if (response && response.data) {
|
if (response && response.data) {
|
||||||
this.setState({ settings: response.data.setting });
|
this.setState({ settings: response.data.setting });
|
||||||
// localStorage.setItem('chromesetting', JSON.stringify(response.data.setting));
|
localStorage.setItem('chromesetting', JSON.stringify(response.data.setting));
|
||||||
// localStorage.setItem('chromesettingresponse', JSON.stringify(response));
|
localStorage.setItem('chromesettingresponse', JSON.stringify(response));
|
||||||
try {
|
|
||||||
if (response.data.setting.tab_logo_url) {
|
|
||||||
this.gettablogourldata(response);
|
|
||||||
} else {
|
|
||||||
this.gettablogourlnull();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.gettablogourlnull();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.gettablogourlnull();
|
this.gettablogourlnull();
|
||||||
}
|
}
|
||||||
|
@ -456,18 +255,10 @@ class NewHeader extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 处理弹框
|
|
||||||
setgoshowqqgtounp = (bool) => {
|
|
||||||
this.setState({
|
|
||||||
goshowqqgtounp: bool
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
addMenu=(list)=>{
|
addMenu=(list)=>{
|
||||||
return(
|
return(
|
||||||
list && list.length >0 &&
|
list && list.length >0 &&
|
||||||
<div className="dropdownFlex">
|
<div className="dropdownFlex double">
|
||||||
<Menu>
|
<Menu>
|
||||||
{
|
{
|
||||||
list.map((item,key)=>{
|
list.map((item,key)=>{
|
||||||
|
@ -476,10 +267,29 @@ class NewHeader extends Component {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
<Menu.Item><AddProjectModal showNotification={this.props.showNotification}/></Menu.Item>
|
||||||
</Menu>
|
</Menu>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
renderMenu=(personal)=>{
|
||||||
|
const { current_user } = this.props;
|
||||||
|
return(
|
||||||
|
<Menu className="currentMenu">
|
||||||
|
<Menu.Item>
|
||||||
|
<span title={current_user && current_user.username}>{current_user && current_user.username}</span>
|
||||||
|
</Menu.Item>
|
||||||
|
{
|
||||||
|
personal && personal.length > 0 && personal.map((item,key)=>{
|
||||||
|
return(
|
||||||
|
<li key={key}><a href={item.url} target="_blank">{item.name}</a></li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
<Menu.Item><a onClick={() => this.educoderloginysl()}>退出</a></Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { match} = this.props;
|
const { match} = this.props;
|
||||||
|
@ -488,17 +298,12 @@ class NewHeader extends Component {
|
||||||
tojoinitemtype,
|
tojoinitemtype,
|
||||||
tojoinclasstitle,
|
tojoinclasstitle,
|
||||||
code_notice,
|
code_notice,
|
||||||
checked_notice,
|
|
||||||
AccountProfiletype,
|
AccountProfiletype,
|
||||||
submitapplications,
|
|
||||||
submitapplicationsvalue,
|
|
||||||
user,
|
user,
|
||||||
isRender,
|
isRender,
|
||||||
showSearchOpentype,
|
|
||||||
headtypesonClickbool,
|
headtypesonClickbool,
|
||||||
headtypess,
|
headtypess,
|
||||||
settings,
|
settings,
|
||||||
goshowqqgtounp,
|
|
||||||
openSearch,
|
openSearch,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
/*用户名称 用户头像url*/
|
/*用户名称 用户头像url*/
|
||||||
|
@ -557,7 +362,7 @@ class NewHeader extends Component {
|
||||||
let shixun = "/shixuns";
|
let shixun = "/shixuns";
|
||||||
let paths = "/paths";
|
let paths = "/paths";
|
||||||
let courses = "/courses";
|
let courses = "/courses";
|
||||||
this.props.mygetHelmetapi.navbar.map((item, key) => {
|
this.props.mygetHelmetapi && this.props.mygetHelmetapi.navbar && this.props.mygetHelmetapi.navbar.map((item, key) => {
|
||||||
var reg = RegExp(item.link);
|
var reg = RegExp(item.link);
|
||||||
if (shixun.match(reg)) {
|
if (shixun.match(reg)) {
|
||||||
if (item.hidden === true) {
|
if (item.hidden === true) {
|
||||||
|
@ -577,8 +382,8 @@ class NewHeader extends Component {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let search_url = settings && settings.common && settings.common.length> 0 && settings.common.filter(item=>item.name==="搜索");
|
let search_url = settings && settings.common && settings.common.search;
|
||||||
let notice_url = settings && settings.common && settings.common.length> 0 && settings.common.filter(item=>item.name==="通知");
|
let notice_url = settings && settings.common && settings.common.notice;
|
||||||
return (
|
return (
|
||||||
<div className="newHeaders" id="nHeader">
|
<div className="newHeaders" id="nHeader">
|
||||||
<div className="headerContent">
|
<div className="headerContent">
|
||||||
|
@ -595,19 +400,14 @@ class NewHeader extends Component {
|
||||||
{...this.props}
|
{...this.props}
|
||||||
{...this.state}
|
{...this.state}
|
||||||
/> : ""}
|
/> : ""}
|
||||||
{
|
|
||||||
goshowqqgtounp === true ?
|
|
||||||
<GotoQQgroup {...this.state} {...this.props} setgoshowqqgtounp={(bool) => this.setgoshowqqgtounp(bool)}></GotoQQgroup>
|
|
||||||
:""
|
|
||||||
}
|
|
||||||
<a href={settings && settings.new_course.default_url} className={"fl mr30"} style={{minWidth:"45px"}}>
|
|
||||||
{
|
{
|
||||||
settings && settings.nav_logo_url ?
|
settings && settings.nav_logo_url ?
|
||||||
<img alt="可控开源社区" className="logoimg" style={{ heigth: "40px" }} src={getImageUrl(settings.nav_logo_url)}></img>
|
<a href={settings && settings.new_course.default_url} className={"fl mr50"} style={{minWidth:"45px"}}>
|
||||||
|
<img alt="可控开源社区" className="logoimg" style={{ heigth: "40px" }} src={getImageUrl(`/${settings.nav_logo_url}`)}></img>
|
||||||
|
</a>
|
||||||
:
|
:
|
||||||
<img alt="可控开源社区" className="logoimg" style={{ heigth: "40px" }} src={logo}></img>
|
""
|
||||||
}
|
}
|
||||||
</a>
|
|
||||||
<div className="head-nav pr" id={"head-navpre1"}>
|
<div className="head-nav pr" id={"head-navpre1"}>
|
||||||
{
|
{
|
||||||
settings && settings.navbar && settings.navbar.length > 0 ?
|
settings && settings.navbar && settings.navbar.length > 0 ?
|
||||||
|
@ -636,7 +436,7 @@ class NewHeader extends Component {
|
||||||
var wl = waiLian && waiLian.length>0;
|
var wl = waiLian && waiLian.length>0;
|
||||||
return (
|
return (
|
||||||
<li key={key} onClick={() => this.headtypesonClick(item.link, true)} className={`${this.matchpaths(item.link) === true ? 'pr active' : 'pr'}`} style={!is_hidden ? { display: 'flex' } : { display: 'none' }}>
|
<li key={key} onClick={() => this.headtypesonClick(item.link, true)} className={`${this.matchpaths(item.link) === true ? 'pr active' : 'pr'}`} style={!is_hidden ? { display: 'flex' } : { display: 'none' }}>
|
||||||
<a href={new_link} target={wl ? "_self":"_blank"}>{item.name}</a>
|
<a href={new_link} target={wl ? "_self":"_blank"}><div dangerouslySetInnerHTML={{ __html: item.name }}></div></a>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -646,81 +446,40 @@ class NewHeader extends Component {
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className="head-right">
|
<div className="head-right">
|
||||||
{search_url && search_url.length>0 ? this.SearchInput(openSearch,search_url[0]):""}
|
{search_url ? this.SearchInput(openSearch,search_url):""}
|
||||||
{
|
{
|
||||||
current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)?
|
current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)?
|
||||||
<Dropdown overlay={this.addMenu(settings && settings.add)} placement="bottomRight">
|
<Dropdown overlay={this.addMenu(settings && settings.add)} placement="bottomRight">
|
||||||
<i className="iconfont icon-tianjiafangda color-grey-6 ml30"></i>
|
<i className="iconfont icon-tianjiafangda color-white ml30"></i>
|
||||||
</Dropdown>:""
|
</Dropdown>:""
|
||||||
}
|
}
|
||||||
|
|
||||||
{this.props.user && this.props.user.login && (notice_url && notice_url.length>0) ?
|
{this.props.user && this.props.user.login && notice_url ?
|
||||||
<div className="ml30 edu-menu-panel">
|
<div className="ml30 edu-menu-panel">
|
||||||
{user && user.login &&
|
{user && user.login &&
|
||||||
<a href={`${notice_url[0].url}`} style={{ position: 'relative' }}>
|
<a href={`${notice_url}`} style={{ position: 'relative' }}>
|
||||||
<i className="iconfont icon-xiaoxilingdang color-grey-6"></i>
|
<i className="iconfont icon-xiaoxilingdang color-white"></i>
|
||||||
<span className="newslight" style={{ display: this.props.Headertop === undefined ? "none" : this.props.Headertop.new_message === true ? "block" : "none" }}>
|
<span className="newslight" style={{ display: this.props.Headertop === undefined ? "none" : this.props.Headertop.new_message === true ? "block" : "none" }}>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
</div>:""
|
</div>:""
|
||||||
}
|
}
|
||||||
<Modal
|
|
||||||
keyboard={false}
|
|
||||||
title="提示"
|
|
||||||
visible={submitapplications}
|
|
||||||
closable={false}
|
|
||||||
footer={null}
|
|
||||||
>
|
|
||||||
<div className="task_popup_con ml30">
|
|
||||||
<div className="mr15">
|
|
||||||
<ul>
|
|
||||||
<div className="task-popup-content">
|
|
||||||
<p className="task-popup-text-center font-16">
|
|
||||||
{submitapplicationsvalue}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<li className="clearfix mt10 edu-txt-center">
|
|
||||||
<a className="task-btn mr10"
|
|
||||||
onClick={this.hidesubmitapplications}>取消</a>
|
|
||||||
<a
|
|
||||||
className="task-btn task-btn-orange ml20"
|
|
||||||
onClick={this.submitsubmitapplications}>确定</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
</div>
|
||||||
{!user || (user && !user.login) ?
|
{!user || (user && !user.login) ?
|
||||||
<span className="font-15 ml30">
|
<span className="font-15 ml30">
|
||||||
<a onClick={() => this.educoderlogin()} className="mr5 color-grey-6">登录</a>
|
<a onClick={() => this.educoderlogin()} className="mr5 color-white">登录</a>
|
||||||
{
|
{
|
||||||
settings && settings.new_course && settings.new_course.register_url &&
|
settings && settings.common && settings.common.register &&
|
||||||
<span><em className="vertical-line"></em><a className="ml5 color-grey-6" href={`${settings.new_course.register_url}`} target="_blank">注册</a></span>
|
<span><em className="vertical-line"></em><a className="ml5 color-white" href={`${settings.common.register}`} target="_blank">注册</a></span>
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
:
|
:
|
||||||
<div className="ml30 edu-menu-panel" style={{ height: "70px", lineHeight: "70px" }}>
|
<Dropdown placement={`bottomRight`} overlay={this.renderMenu(settings && settings.personal)}>
|
||||||
<a href={`/users/${this.props.current_user === undefined ? "" : this.props.current_user.login}/courses`}>
|
<a href={`/users/${this.props.current_user && this.props.current_user.login}`}>
|
||||||
<img alt="头像" className="radius" height="34" id="nh_user_logo" name="avatar_image"
|
<img alt="头像" src={getImageUrl(`/${user.image_url}`)} className="currentImg"></img>
|
||||||
src={getImageUrl(`images/` + user.image_url)} width="34">
|
|
||||||
</img>
|
|
||||||
</a>
|
</a>
|
||||||
<ul className="edu-menu-list" style={{ top: '60px', textAlign: 'center' }}>
|
</Dropdown>
|
||||||
<li className="bor-bottom-greyE" style={{cursor:"default",background:"#fff"}}>{this.props.current_user.username}</li>
|
|
||||||
{
|
|
||||||
settings && settings.personal && settings.personal.length > 0 && settings.personal.map((item,key)=>{
|
|
||||||
return(
|
|
||||||
<li key={key}><a href={item.url} target="_blank">{item.name}</a></li>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
<li className="bor-top-greyE">
|
|
||||||
<a onClick={() => this.educoderloginysl()}>退出</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,155 @@
|
||||||
|
.dropdownFlex.double{
|
||||||
.dropdownFlex{
|
width: 232px;
|
||||||
display:flex;
|
.ant-menu{
|
||||||
padding:5px;
|
height: 145px;
|
||||||
background:#fff;
|
.ant-menu-item:nth-child(-n+4){
|
||||||
border-radius: 3px;
|
border-right: 1px solid #eee;
|
||||||
.ant-menu-vertical > .ant-menu-item{
|
}
|
||||||
border:none
|
.ant-menu-item{
|
||||||
|
padding:0px 5px;
|
||||||
|
}
|
||||||
|
.ant-menu-item:hover a{
|
||||||
|
color: #fff!important;
|
||||||
|
background-color: #1890ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.headmenus{
|
||||||
|
.ant-dropdown-menu-item:hover{
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dropdownFlex{
|
||||||
|
display:flex;
|
||||||
|
background:#fff;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding:5px 0px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
.ant-menu{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
line-height: 45px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.ant-menu > .ant-menu-item{
|
||||||
|
border:none;
|
||||||
|
height: 35px;
|
||||||
|
line-height: 35px;
|
||||||
|
margin:0px;
|
||||||
|
width: 116px;
|
||||||
|
&.ant-menu-item-selected{
|
||||||
|
background-color: #fff;
|
||||||
|
a{color: rgba(0, 0, 0, 0.65)!important;}
|
||||||
|
}
|
||||||
|
a{
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
&.ant-menu-item-active{
|
||||||
|
a{color: #4cacff!important;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-menu-vertical{
|
||||||
|
border:none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.currentImg{
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-left: 30px;
|
||||||
|
}
|
||||||
|
.currentMenu{
|
||||||
|
width: 120px;
|
||||||
|
text-align: center;
|
||||||
|
padding:0px;
|
||||||
|
li{
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
padding:0px!important;
|
||||||
|
cursor: default;
|
||||||
|
&:hover{
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
&:first-child{
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
&:last-child{
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
a{
|
||||||
|
border-radius: 0px 0px 4px 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a{
|
||||||
|
padding:0px;
|
||||||
|
margin:0px;
|
||||||
|
display: block;
|
||||||
|
color: #666;
|
||||||
|
&:hover{
|
||||||
|
color: #fff;
|
||||||
|
background: #4CACFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.newFooter {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
background: #323232;
|
||||||
|
clear: both;
|
||||||
|
min-width: 1200px;
|
||||||
|
z-index: 8;
|
||||||
|
left: 0px;
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom:0px !important;
|
||||||
|
}
|
||||||
|
.footerInfos{
|
||||||
|
display: flex;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin:0px auto;
|
||||||
|
justify-content: space-around;
|
||||||
|
padding:60px 0px;
|
||||||
|
& >ul{
|
||||||
|
padding:0px 40px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
max-width: 25%;
|
||||||
|
text-align: left;
|
||||||
|
li{
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 300;
|
||||||
|
&:first-child{
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
&>a,&>span{
|
||||||
|
color: #bbb;
|
||||||
|
}
|
||||||
|
&>a:hover{
|
||||||
|
color: #4cacff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.footerCopy{
|
||||||
|
color: #bbb;
|
||||||
|
border-top: 1px solid #4e4e4e;
|
||||||
|
padding:10px 0px;
|
||||||
|
a{
|
||||||
|
color: #bbb;
|
||||||
|
&:hover{
|
||||||
|
color: #4cacff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.inviteForm{
|
||||||
|
.ant-form-item{
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
.ant-form-item-label{
|
||||||
|
width: 110px;
|
||||||
|
text-align: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
Binary file not shown.
After Width: | Height: | Size: 212 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
|
@ -6,7 +6,6 @@ import { withRouter } from "react-router";
|
||||||
import { SnackbarHOC } from "educoder";
|
import { SnackbarHOC } from "educoder";
|
||||||
import { CNotificationHOC } from "../modules/courses/common/CNotificationHOC";
|
import { CNotificationHOC } from "../modules/courses/common/CNotificationHOC";
|
||||||
import { TPMIndexHOC } from "../modules/tpm/TPMIndexHOC";
|
import { TPMIndexHOC } from "../modules/tpm/TPMIndexHOC";
|
||||||
import Handbook from './Component/Handbook';
|
|
||||||
import "./css/index.scss";
|
import "./css/index.scss";
|
||||||
|
|
||||||
import Loadable from "react-loadable";
|
import Loadable from "react-loadable";
|
||||||
|
@ -27,15 +26,18 @@ const ProjectDetail = Loadable({
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
});
|
});
|
||||||
|
|
||||||
const Infos = Loadable({
|
|
||||||
loader: () => import("./users/Infos"),
|
|
||||||
loading: Loading,
|
|
||||||
});
|
|
||||||
class Index extends Component {
|
class Index extends Component {
|
||||||
|
componentDidUpdate=(preProps)=>{
|
||||||
|
this.props.history.listen(()=>{
|
||||||
|
if (document.body.scrollTop || document.documentElement.scrollTop > 0) {
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="newMain clearfix">
|
<div className="newMain clearfix">
|
||||||
<Handbook />
|
|
||||||
<Switch {...this.props}>
|
<Switch {...this.props}>
|
||||||
<Route
|
<Route
|
||||||
path="/projects/:projectsType/new/:OIdentifier"
|
path="/projects/:projectsType/new/:OIdentifier"
|
||||||
|
@ -68,12 +70,8 @@ class Index extends Component {
|
||||||
)}
|
)}
|
||||||
></Route>
|
></Route>
|
||||||
<Route
|
<Route
|
||||||
exact
|
|
||||||
path="/"
|
path="/"
|
||||||
render={(props) => (
|
render={(props) => (
|
||||||
this.props.current_user && this.props.current_user.login ?
|
|
||||||
<Infos {...this.props} {...props} />
|
|
||||||
:
|
|
||||||
<ProjectIndex {...this.props} {...props} />
|
<ProjectIndex {...this.props} {...props} />
|
||||||
)}
|
)}
|
||||||
></Route>
|
></Route>
|
||||||
|
|
|
@ -19,10 +19,27 @@ import LanguagePower from '../Component/LanguagePower';
|
||||||
import DrawerPanel from '../Component/DrawerPanel';
|
import DrawerPanel from '../Component/DrawerPanel';
|
||||||
import UpdateDescModal from './sub/UpdateDescModal';
|
import UpdateDescModal from './sub/UpdateDescModal';
|
||||||
import Nodata from '../Nodata';
|
import Nodata from '../Nodata';
|
||||||
|
import Invite from './sub/Invite';
|
||||||
|
/**
|
||||||
|
* projectDetail.type:0是托管项目,1是镜像项目,2是同步镜像项目(为2时不支持在线创建、在线上传、在线修改、在线删除、创建合并请求等功能)
|
||||||
|
*/
|
||||||
|
|
||||||
|
function turnbar(str){
|
||||||
|
if(str && str.length>0 && str.indexOf("/")>-1){
|
||||||
|
return str.replaceAll('/','%2F');
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
function returnbar(str){
|
||||||
|
if(str && str.length>0 && str.indexOf("%2F")>-1){
|
||||||
|
return str.replaceAll('%2F','/');
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
function CoderDepot(props){
|
function CoderDepot(props){
|
||||||
const [ projectDetail , setProjectDetail ]= useState(undefined);
|
const [ projectDetail , setProjectDetail ]= useState(undefined);
|
||||||
|
const [ inviteCode , setInviteCode ] = useState(undefined);
|
||||||
const [ treeValue , setTreeValue ] = useState(undefined);
|
const [ treeValue , setTreeValue ] = useState(undefined);
|
||||||
const [ treeValuePath , setTreeValuePath ] = useState(undefined);
|
const [ treeValuePath , setTreeValuePath ] = useState(undefined);
|
||||||
const [ lastCommit,setLastCommit ] = useState(undefined);
|
const [ lastCommit,setLastCommit ] = useState(undefined);
|
||||||
|
@ -42,19 +59,28 @@ function CoderDepot(props){
|
||||||
const [ openModal , setOpenModal ] = useState(false);
|
const [ openModal , setOpenModal ] = useState(false);
|
||||||
const [ desc , setDesc ] = useState(undefined);
|
const [ desc , setDesc ] = useState(undefined);
|
||||||
const [ website , setWebsite ] = useState(undefined);
|
const [ website , setWebsite ] = useState(undefined);
|
||||||
|
const [ lesson_url , setLessonUrl ] = useState(undefined);
|
||||||
|
const [ readme , setReadme ] = useState(undefined);
|
||||||
|
const [ defaultBranch , setDefaultBranch ] = useState(undefined);
|
||||||
|
const [ editReadme , setEditReadme ] = useState(false);
|
||||||
|
|
||||||
const owner = props.match.params.owner;
|
const owner = props.match.params.owner;
|
||||||
const projectsId = props.match.params.projectsId;
|
const projectsId = props.match.params.projectsId;
|
||||||
const branchName = props.match.params.branchName;
|
let branchName = props.match.params.branchName;
|
||||||
|
branchName = returnbar(branchName);
|
||||||
|
const details = props.projectDetail;
|
||||||
let pathname = props.history.location.pathname;
|
let pathname = props.history.location.pathname;
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if(props.projectDetail){
|
if(details){
|
||||||
setProjectDetail(props.projectDetail);
|
setProjectDetail(details);
|
||||||
setDesc(props.projectDetail.description);
|
setDesc(details.description);
|
||||||
setWebsite(props.projectDetail.website);
|
setWebsite(details.website);
|
||||||
|
setLessonUrl(details.lesson_url);
|
||||||
|
setDefaultBranch(details.default_branch);
|
||||||
|
setInviteCode(details.invite_code);
|
||||||
}
|
}
|
||||||
},[props])
|
},[details])
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if(treeValue){
|
if(treeValue){
|
||||||
|
@ -64,23 +90,28 @@ function CoderDepot(props){
|
||||||
}
|
}
|
||||||
},[treeValue])
|
},[treeValue])
|
||||||
|
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if (pathname){
|
if (projectsId && owner && defaultBranch){
|
||||||
if(pathname.indexOf(`/projects/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${branchName}/`) > -1) {
|
let b = turnbar(branchName) ;
|
||||||
let url = pathname.split(`/tree/${branchName}/`)[1];
|
if(pathname.indexOf(`/projects/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${b}/`) > -1) {
|
||||||
|
let url = pathname.split(`/tree/${b}/`)[1];
|
||||||
setTreeValue(url);
|
setTreeValue(url);
|
||||||
getFileInfo(url,branchName);
|
getFileInfo(url,branchName);
|
||||||
|
setType("file");
|
||||||
}else{
|
}else{
|
||||||
setTreeValue(undefined);
|
setTreeValue(undefined);
|
||||||
getDirInfo(branchName ||(projectDetail && projectDetail.default_branch));
|
getDirInfo(branchName || defaultBranch);
|
||||||
|
setType("dir");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},[pathname])
|
},[projectsId,owner,pathname,defaultBranch])
|
||||||
|
|
||||||
// 获取主目录列表
|
// 获取主目录列表
|
||||||
function getDirInfo(branch){
|
function getDirInfo(branch){
|
||||||
setIsSpin(true);
|
setIsSpin(true);
|
||||||
const url = `/${owner}/${projectsId}/entries.json`;
|
const url = `/${owner}/${projectsId}/entries.json`;
|
||||||
|
|
||||||
axios.get(url, {
|
axios.get(url, {
|
||||||
params: { ref: branch }
|
params: { ref: branch }
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
|
@ -92,8 +123,12 @@ function CoderDepot(props){
|
||||||
setZip_url(result.data.zip_url);
|
setZip_url(result.data.zip_url);
|
||||||
let c = result.data.last_commit
|
let c = result.data.last_commit
|
||||||
setLastCommit(c && c.commit);
|
setLastCommit(c && c.commit);
|
||||||
setLastCommitAuthor(c && (c.author || (c.commit && c.commit.author)));
|
setLastCommitAuthor(c && c.committer);
|
||||||
setMainFlag(true);
|
setMainFlag(true);
|
||||||
|
setReadOnly(true);
|
||||||
|
setReadme(result.data.readme);
|
||||||
|
setEditReadme(false);
|
||||||
|
setHide(true);
|
||||||
}
|
}
|
||||||
setTimeout(function(){setIsSpin(false);},500);
|
setTimeout(function(){setIsSpin(false);},500);
|
||||||
}).catch(error=>{setIsSpin(false);})
|
}).catch(error=>{setIsSpin(false);})
|
||||||
|
@ -105,7 +140,7 @@ function CoderDepot(props){
|
||||||
let ele = document.getElementById("ptxt");
|
let ele = document.getElementById("ptxt");
|
||||||
if(ele){
|
if(ele){
|
||||||
let h = ele.offsetHeight;
|
let h = ele.offsetHeight;
|
||||||
if( h > 18 ) setHideBtn(true)
|
if( h > 18 ) setHideBtn(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},[projectDetail,lastCommit])
|
},[projectDetail,lastCommit])
|
||||||
|
@ -133,8 +168,10 @@ function CoderDepot(props){
|
||||||
}
|
}
|
||||||
let c = result.data.last_commit
|
let c = result.data.last_commit
|
||||||
setLastCommit(c && c.commit);
|
setLastCommit(c && c.commit);
|
||||||
setLastCommitAuthor(c && (c.author || (c.commit && c.commit.author)));
|
setLastCommitAuthor(c && c.committer);
|
||||||
setMainFlag(false);
|
setMainFlag(false);
|
||||||
|
setReadOnly(!editReadme);
|
||||||
|
setHide(true);
|
||||||
}
|
}
|
||||||
setTimeout(function(){setIsSpin(false);},500)
|
setTimeout(function(){setIsSpin(false);},500)
|
||||||
}).catch(error=>{setIsSpin(false);})
|
}).catch(error=>{setIsSpin(false);})
|
||||||
|
@ -142,17 +179,22 @@ function CoderDepot(props){
|
||||||
|
|
||||||
// 切换分支或者标签
|
// 切换分支或者标签
|
||||||
function changeBranch(value){
|
function changeBranch(value){
|
||||||
let url = `/projects/${owner}/${projectsId}${value && `/tree/${value}`}${treeValue ? `/${treeValue}`:""}`;
|
let checkvalue = turnbar(value);
|
||||||
|
let url = `/projects/${owner}/${projectsId}${value && `/tree/${checkvalue}`}${treeValue ? `/${treeValue}`:""}`;
|
||||||
props.history.push(url);
|
props.history.push(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 文件相关的下拉项
|
// 文件相关的下拉项
|
||||||
const fileMenu =(
|
function fileMenu(){
|
||||||
|
let b = branchName || defaultBranch;
|
||||||
|
let checkvalue = turnbar(b);
|
||||||
|
return (
|
||||||
<Menu>
|
<Menu>
|
||||||
<Menu.Item><a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/${branchName || (projectDetail && projectDetail.default_branch)}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件</a></Menu.Item>
|
<Menu.Item><a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/${checkvalue}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件</a></Menu.Item>
|
||||||
<Menu.Item><a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/${branchName || (projectDetail && projectDetail.default_branch)}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件</a></Menu.Item>
|
<Menu.Item><a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/${checkvalue}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件</a></Menu.Item>
|
||||||
</Menu>
|
</Menu>
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function getPathUrl(array,index){
|
function getPathUrl(array,index){
|
||||||
if(array && array.length>0 && index){
|
if(array && array.length>0 && index){
|
||||||
|
@ -166,27 +208,36 @@ function CoderDepot(props){
|
||||||
// 页面地址返回到主目录
|
// 页面地址返回到主目录
|
||||||
function returnMain(){
|
function returnMain(){
|
||||||
setTreeValue(undefined);
|
setTreeValue(undefined);
|
||||||
let branch = branchName || (projectDetail && projectDetail.default_branch);
|
let branch = branchName || defaultBranch;
|
||||||
props.history.push(`/projects/${owner}/${projectsId}/tree/${branch}`);
|
let checkvalue = turnbar(branch);
|
||||||
|
props.history.push(`/projects/${owner}/${projectsId}/tree/${checkvalue}`);
|
||||||
};
|
};
|
||||||
// 子目录路径返回链接
|
// 子目录路径返回链接
|
||||||
function returnUlr(url){
|
function returnUlr(url){
|
||||||
props.history.push(`/projects/${owner}/${projectsId}/tree${branchName?`/${branchName}`:""}/${url}`);
|
let enBranch = turnbar(branchName);
|
||||||
|
props.history.push(`/projects/${owner}/${projectsId}/tree${enBranch?`/${enBranch}`:""}/${url}`);
|
||||||
}
|
}
|
||||||
// 点击跳转到子目录
|
// 点击跳转到子目录
|
||||||
function goToSubRoot(path,type,filename){
|
function goToSubRoot(path,type,filename){
|
||||||
setType(type);
|
if(type!=="submodule"){
|
||||||
props.history.push(`/projects/${owner}/${projectsId}${`/tree/${branchName || (projectDetail && projectDetail.default_branch)}`}${path?`/${path}`:""}`);
|
let enBranch = branchName || defaultBranch;
|
||||||
|
let checkvalue = turnbar(enBranch);
|
||||||
|
setType(type);
|
||||||
|
props.history.push(`/projects/${owner}/${projectsId}${`/tree/${checkvalue}`}${path?`/${path}`:""}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEdit(readOnly){
|
function onEdit(readOnly){
|
||||||
setReadOnly(readOnly);
|
setReadOnly(readOnly);
|
||||||
|
setEditReadme(false);
|
||||||
}
|
}
|
||||||
function ChangeFile(path, readOnly){
|
function ChangeFile(path, readOnly){
|
||||||
//点击直接跳转页面 加载一次路由
|
//点击直接跳转页面 加载一次路由
|
||||||
props.history.push(`/projects/${owner}/${projectsId}/tree/${branchName || (projectDetail && projectDetail.default_branch)}/${path}`);
|
let enBranch = branchName || defaultBranch;
|
||||||
|
let checkvalue = turnbar(enBranch);
|
||||||
|
props.history.push(`/projects/${owner}/${projectsId}/tree/${checkvalue}/${path}`);
|
||||||
setType("file");
|
setType("file");
|
||||||
setReadOnly(readOnly);
|
setEditReadme(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
function changeHide(hide){
|
function changeHide(hide){
|
||||||
|
@ -214,20 +265,27 @@ function CoderDepot(props){
|
||||||
</Menu>
|
</Menu>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
function okUpdate(d,w){
|
// 确认修改简介、website、实践课程链接
|
||||||
|
function okUpdate(d,w,l){
|
||||||
const url = `/${owner}/${projectsId}.json`;
|
const url = `/${owner}/${projectsId}.json`;
|
||||||
axios.put(url,{
|
axios.put(url,{
|
||||||
description:d,website:w
|
description:d,website:w,lesson_url:l
|
||||||
}).then(result=>{
|
}).then(result=>{
|
||||||
if(result && result.data && result.data.id){
|
if(result && result.data && result.data.id){
|
||||||
setDesc(result.data.description);
|
setDesc(result.data.description);
|
||||||
setWebsite(result.data.website);
|
setWebsite(result.data.website);
|
||||||
|
setLessonUrl(result.data.lesson_url);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
let n = fileInfo && fileInfo.name;
|
||||||
|
const mdFlag = n && n.substring(n.length-3,n.length) === ".md";
|
||||||
|
|
||||||
|
const { current_user } = props;
|
||||||
|
const fileOperate = type === "dir" && projectDetail && projectDetail.type !== 2 && ((projectDetail.permission && projectDetail.permission !=="Reporter") || (current_user && current_user.admin));
|
||||||
return(
|
return(
|
||||||
<WhiteBack>
|
<WhiteBack>
|
||||||
<UpdateDescModal desc={desc} website={website} visible={openModal} onCancel={()=>setOpenModal(false)} onOk={okUpdate}/>
|
<UpdateDescModal desc={desc} website={website} lesson_url={lesson_url} visible={openModal} onCancel={()=>setOpenModal(false)} onOk={okUpdate}/>
|
||||||
<Spin spinning={isSpin}>
|
<Spin spinning={isSpin}>
|
||||||
{
|
{
|
||||||
(dirInfo || fileInfo) &&
|
(dirInfo || fileInfo) &&
|
||||||
|
@ -237,7 +295,7 @@ function CoderDepot(props){
|
||||||
owner={owner}
|
owner={owner}
|
||||||
projectsId={projectsId}
|
projectsId={projectsId}
|
||||||
name={projectDetail && projectDetail.name}
|
name={projectDetail && projectDetail.name}
|
||||||
branch={branchName || (projectDetail && projectDetail.default_branch)}
|
branch={branchName || defaultBranch}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
onClose={()=>setVisible(false)}
|
onClose={()=>setVisible(false)}
|
||||||
list = {mainFlag ? dirInfo : undefined}
|
list = {mainFlag ? dirInfo : undefined}
|
||||||
|
@ -262,14 +320,14 @@ function CoderDepot(props){
|
||||||
<SelectBranch
|
<SelectBranch
|
||||||
repo_id={projectDetail && projectDetail.repo_id}
|
repo_id={projectDetail && projectDetail.repo_id}
|
||||||
projectsId={projectsId}
|
projectsId={projectsId}
|
||||||
branch={branchName || (projectDetail && projectDetail.default_branch)}
|
branch={branchName || defaultBranch}
|
||||||
changeBranch={changeBranch}
|
changeBranch={changeBranch}
|
||||||
owner={owner}
|
owner={owner}
|
||||||
history={props.history}
|
history={props.history}
|
||||||
branchList={projectDetail && projectDetail.branches && projectDetail.branches.list}
|
branchList={projectDetail && projectDetail.branches && projectDetail.branches.list}
|
||||||
></SelectBranch>
|
></SelectBranch>
|
||||||
:
|
:
|
||||||
<span>分支:<span className="color-grey-6">{branchName || (projectDetail && projectDetail.default_branch)}</span></span>
|
<span>分支:<span className="color-grey-6">{branchName || defaultBranch}</span></span>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<AlignCenter className="mr20">
|
<AlignCenter className="mr20">
|
||||||
|
@ -287,15 +345,19 @@ function CoderDepot(props){
|
||||||
</AlignCenter>
|
</AlignCenter>
|
||||||
<AlignCenter>
|
<AlignCenter>
|
||||||
<div className="mr20 addOptionBtn">
|
<div className="mr20 addOptionBtn">
|
||||||
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/pulls/new`)} >+ 合并请求</a>
|
{
|
||||||
|
projectDetail.type !== 2 &&
|
||||||
|
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/pulls/new`)} >+ 合并请求</a>
|
||||||
|
}
|
||||||
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/issues/new`)} >+ 任务</a>
|
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/issues/new`)} >+ 任务</a>
|
||||||
</div>
|
</div>
|
||||||
{ type === "dir" &&
|
{ fileOperate &&
|
||||||
<Dropdown overlay={fileMenu} className="mr20">
|
<Dropdown overlay={fileMenu()} className="mr20" trigger={['click']}>
|
||||||
<Button type="default">文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-9"></i></Button>
|
<Button type="default">文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-9"></i></Button>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
}
|
}
|
||||||
<Dropdown overlay={downloadMenu} placement="bottomRight">
|
|
||||||
|
<Dropdown overlay={downloadMenu} placement="bottomRight" trigger={['click']}>
|
||||||
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white"></i></Button>
|
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white"></i></Button>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</AlignCenter>
|
</AlignCenter>
|
||||||
|
@ -306,8 +368,10 @@ function CoderDepot(props){
|
||||||
{
|
{
|
||||||
lastCommit &&
|
lastCommit &&
|
||||||
<div className="listtablehead">
|
<div className="listtablehead">
|
||||||
<User url={getImageUrl(`images/${lastCommitAuthor && lastCommitAuthor.image_url}`)} name={lastCommitAuthor && lastCommitAuthor.name} />
|
<User url={getImageUrl(`/${lastCommitAuthor && lastCommitAuthor.image_url}`)} name={lastCommitAuthor && lastCommitAuthor.name} id={lastCommitAuthor && lastCommitAuthor.id} login={lastCommitAuthor && lastCommitAuthor.login}/>
|
||||||
<div className={hideBtn && hide ? "ellipsistxt hide" :"ellipsistxt"}><p id="ptxt">{lastCommit && lastCommit.message}</p></div>
|
<div className={hideBtn && hide ? "ellipsistxt hidetxt" :"ellipsistxt"}>
|
||||||
|
<pre id="ptxt">{lastCommit && lastCommit.message}</pre>
|
||||||
|
</div>
|
||||||
{ hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> }
|
{ hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> }
|
||||||
|
|
||||||
<span className="ml12 color-grey-9 mt3">{lastCommit && lastCommit.time_from_now}</span>
|
<span className="ml12 color-grey-9 mt3">{lastCommit && lastCommit.time_from_now}</span>
|
||||||
|
@ -344,8 +408,10 @@ function CoderDepot(props){
|
||||||
{...props}
|
{...props}
|
||||||
detail={fileInfo}
|
detail={fileInfo}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
|
md={mdFlag}
|
||||||
onEdit={onEdit}
|
onEdit={onEdit}
|
||||||
currentBranch={branchName || (projectDetail && projectDetail.default_branch)}
|
currentBranch={branchName || defaultBranch}
|
||||||
|
type={projectDetail.type}
|
||||||
></CoderRootFileDetail>
|
></CoderRootFileDetail>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -356,7 +422,7 @@ function CoderDepot(props){
|
||||||
(dirInfo && dirInfo.length === 0) && (fileInfo && fileInfo.length === 0) ? <Nodata _html="暂未发现文件"/> :""
|
(dirInfo && dirInfo.length === 0) && (fileInfo && fileInfo.length === 0) ? <Nodata _html="暂未发现文件"/> :""
|
||||||
}
|
}
|
||||||
{/* readme文件显示(显示文件详情时不显示readme文件) */}
|
{/* readme文件显示(显示文件详情时不显示readme文件) */}
|
||||||
{ dirInfo && (projectDetail && projectDetail.readme) ? <ReadMe ChangeFile={ChangeFile} readme={projectDetail && projectDetail.readme} operate={props && (props.isManager || props.isDeveloper)} history={props.history} /> :"" }
|
{ dirInfo && (readme && readme.content) ? <ReadMe ChangeFile={ChangeFile} readme={readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
|
||||||
</div>
|
</div>
|
||||||
</LongWidth>
|
</LongWidth>
|
||||||
{
|
{
|
||||||
|
@ -372,7 +438,7 @@ function CoderDepot(props){
|
||||||
website &&
|
website &&
|
||||||
<p className="color-grey-6 df">
|
<p className="color-grey-6 df">
|
||||||
<i className="iconfont icon-lianjie2 font-15 mr10 color-grey-9"></i>
|
<i className="iconfont icon-lianjie2 font-15 mr10 color-grey-9"></i>
|
||||||
<span style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px"}}>{website}</span>
|
<a href={website} target="_blank" style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px",textDecoration:"underline"}}>{website}</a>
|
||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
<p>
|
<p>
|
||||||
|
@ -391,6 +457,21 @@ function CoderDepot(props){
|
||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
{
|
||||||
|
inviteCode &&
|
||||||
|
<div>
|
||||||
|
<Divider />
|
||||||
|
<Invite code={inviteCode} className={"detailsCode"}/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
lesson_url &&
|
||||||
|
<div>
|
||||||
|
<Divider />
|
||||||
|
<p className="font-16 color-grey-6">实践课程</p>
|
||||||
|
<a href={lesson_url} target="_blank" className="color-grey-6" style={{textDecoration:"underline"}}>{lesson_url}</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
{/* 发布 */}
|
{/* 发布 */}
|
||||||
{
|
{
|
||||||
projectDetail && projectDetail.release_versions &&
|
projectDetail && projectDetail.release_versions &&
|
||||||
|
@ -402,10 +483,7 @@ function CoderDepot(props){
|
||||||
{/* 贡献者 */}
|
{/* 贡献者 */}
|
||||||
{
|
{
|
||||||
projectDetail && projectDetail.contributors &&
|
projectDetail && projectDetail.contributors &&
|
||||||
<React.Fragment>
|
<Contributors contributors={projectDetail && projectDetail.contributors} owner={owner} projectsId={projectsId} />
|
||||||
<Divider />
|
|
||||||
<Contributors contributors={projectDetail && projectDetail.contributors} owner={owner} projectsId={projectsId}/>
|
|
||||||
</React.Fragment>
|
|
||||||
}
|
}
|
||||||
{/* 语言 */}
|
{/* 语言 */}
|
||||||
{ projectDetail && projectDetail.languages &&
|
{ projectDetail && projectDetail.languages &&
|
||||||
|
|
|
@ -2,12 +2,18 @@ import React from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { truncateCommitId } from '../common/util';
|
import { truncateCommitId } from '../common/util';
|
||||||
|
|
||||||
|
const typeIco = {
|
||||||
|
"submodule":"icon-file-submodule font-17",
|
||||||
|
"file":'icon-wenjia font-15',
|
||||||
|
"dir":"icon-wenjianjia1 font-15"
|
||||||
|
}
|
||||||
|
|
||||||
function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
|
function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
|
||||||
return(
|
return(
|
||||||
<li>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
<a onClick={()=>goToSubRoot(item.path,item.type,item.name)}>
|
<a onClick={()=>goToSubRoot(item.path,item.type,item.name)} className={item.type === "submodule" && "submoduleStyle"}>
|
||||||
<i className={item.type === 'dir' ? "iconfont icon-wenjianjia1 color-green-file font-15 mr5":"iconfont icon-wenjia color-green-file font-15 mr5"}></i>{item.name}
|
<i className={`iconfont ${typeIco[`${item.type}`]} color-green-file mr5`}></i>{item.name}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
<span title="init project">
|
<span title="init project">
|
||||||
|
|
|
@ -1,14 +1,63 @@
|
||||||
import React from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import RenderHtml from '../../components/render-html';
|
import RenderHtml from '../../components/render-html';
|
||||||
|
import { AlignCenter } from '../Component/layout';
|
||||||
|
import { Dropdown , Menu , Spin } from 'antd';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
const $ = window.$;
|
||||||
|
|
||||||
function CoderDepotReadme({ operate , history , readme , ChangeFile }){
|
function CoderDepotReadme({ operate , history , readme , ChangeFile }){
|
||||||
|
const [ menuList ,setMenuList ] = useState(undefined);
|
||||||
|
const [ content ,setContent ] = useState(undefined);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(readme && readme.content){
|
||||||
|
setContent(readme.content);
|
||||||
|
}else{
|
||||||
|
setContent(undefined);
|
||||||
|
}
|
||||||
|
},[readme])
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
let path = history.location.pathname;
|
||||||
|
const items = $.map($("#readme").find("h1,h2,h3,h4,h5,h6"), function (el, _) {
|
||||||
|
const anchor = el.id;
|
||||||
|
const level = el.tagName.replace("H", "");
|
||||||
|
const href = `#${anchor}`;
|
||||||
|
return { href:`${path}${href}`,text:el.textContent , level:level }
|
||||||
|
});
|
||||||
|
setMenuList(items);
|
||||||
|
},[content])
|
||||||
|
|
||||||
|
function menu(){
|
||||||
|
if(menuList && menuList.length > 0){
|
||||||
|
let hash = history.location.hash;
|
||||||
|
return(
|
||||||
|
<Menu className="menuslist">
|
||||||
|
{
|
||||||
|
menuList.map((item,key)=>{
|
||||||
|
return(
|
||||||
|
<Menu.Item key={item.id} className={decodeURI(hash).indexOf(item.text)>-1 ?"active":""}><Link to={`${item.href}`} style={{paddingLeft:`${item.level *10}px`}} title={item.text}>{item.text}</Link></Menu.Item>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</Menu>
|
||||||
|
)
|
||||||
|
}else{
|
||||||
|
return <Spin />
|
||||||
|
}
|
||||||
|
}
|
||||||
return(
|
return(
|
||||||
<div className="commonBox" id="readme">
|
<div className="commonBox" id="readme">
|
||||||
<div className="commonBox-title">
|
<div className="commonBox-title boxTitle">
|
||||||
<span className="mr10">
|
<AlignCenter>
|
||||||
<i className="iconfont icon-wenjian1 font-16 color-grey-9 fl mt3"></i>
|
<Dropdown overlay={menu()}>
|
||||||
</span>
|
<span className="catelogue">
|
||||||
<span className="commonBox-title-read">README.md</span>
|
<i className="iconfont icon-zhangjie1 font-14 mr5"></i>
|
||||||
|
<span>目录</span>
|
||||||
|
</span>
|
||||||
|
</Dropdown>
|
||||||
|
<span className="commonBox-title-read">README.md</span>
|
||||||
|
</AlignCenter>
|
||||||
{
|
{
|
||||||
operate ?
|
operate ?
|
||||||
<a className="ml20 pull-right" onClick={() =>ChangeFile(readme && readme.path, false)}>
|
<a className="ml20 pull-right" onClick={() =>ChangeFile(readme && readme.path, false)}>
|
||||||
|
@ -17,9 +66,12 @@ function CoderDepotReadme({ operate , history , readme , ChangeFile }){
|
||||||
:""
|
:""
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className="commonBox-info">
|
{
|
||||||
<RenderHtml className="break_word_comments imageLayerParent" value={readme && readme.content} url={history.location}/>
|
content &&
|
||||||
</div>
|
<div className="commonBox-info">
|
||||||
|
<RenderHtml className="break_word_comments imageLayerParent" value={content} url={history.location}/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,12 @@ import { getBranch } from '../GetData/getData';
|
||||||
import Nodata from '../Nodata';
|
import Nodata from '../Nodata';
|
||||||
import './list.css';
|
import './list.css';
|
||||||
|
|
||||||
|
function turnbar(str){
|
||||||
|
if(str && str.length>0 && str.indexOf("/")>-1){
|
||||||
|
return str.replaceAll('/','%2F');
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
export default ((props)=>{
|
export default ((props)=>{
|
||||||
const [ data , setData ] =useState(undefined);
|
const [ data , setData ] =useState(undefined);
|
||||||
const [ isSpin , setIsSpin ] =useState(true);
|
const [ isSpin , setIsSpin ] =useState(true);
|
||||||
|
@ -32,7 +38,7 @@ export default ((props)=>{
|
||||||
return(
|
return(
|
||||||
<li key={key}>
|
<li key={key}>
|
||||||
<div>
|
<div>
|
||||||
<Link to={`/projects/${owner}/${projectsId}/tree/${item.name}`} className="color-blue font-15" style={{"maxWidth":"100px"}}>{item.name}</Link>
|
<Link to={`/projects/${owner}/${projectsId}/tree/${turnbar(item.name)}`} className="color-blue font-15" style={{"maxWidth":"100px"}}>{item.name}</Link>
|
||||||
<p className="f-wrap-alignCenter mt15">
|
<p className="f-wrap-alignCenter mt15">
|
||||||
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.last_commit.sha}`)}`} className="mr5 commitKey" style={{marginLeft:0}}>{item.last_commit && truncateCommitId(item.last_commit.sha)}</Link>
|
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.last_commit.sha}`)}`} className="mr5 commitKey" style={{marginLeft:0}}>{item.last_commit && truncateCommitId(item.last_commit.sha)}</Link>
|
||||||
<span className="color-grey-3 hide-1 messages leftPoint">{item.last_commit && item.last_commit.message}</span>
|
<span className="color-grey-3 hide-1 messages leftPoint">{item.last_commit && item.last_commit.message}</span>
|
||||||
|
@ -40,7 +46,7 @@ export default ((props)=>{
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<span>
|
<span>
|
||||||
<Link to={`/projects/${owner}/${projectsId}/pulls/new`} className="mr20 color-blue mr30">创建合并请求</Link>
|
<Link to={`/projects/${owner}/${projectsId}/pulls/new/${item.name}`} className="mr20 color-blue mr30">创建合并请求</Link>
|
||||||
<Dropdown overlay={menu(item.zip_url,item.tar_url)} trigger={['click']} placement="bottomRight" className="color-green-file">
|
<Dropdown overlay={menu(item.zip_url,item.tar_url)} trigger={['click']} placement="bottomRight" className="color-green-file">
|
||||||
<a className="ant-dropdown-link">
|
<a className="ant-dropdown-link">
|
||||||
<Tooltip title={`下载分支${item.name}`}><Icon type="cloud-download" className="font-18"/></Tooltip>
|
<Tooltip title={`下载分支${item.name}`}><Icon type="cloud-download" className="font-18"/></Tooltip>
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React , { Component } from 'react';
|
||||||
import { Spin , Pagination } from 'antd';
|
import { Spin , Pagination } from 'antd';
|
||||||
import { getImageUrl } from 'educoder';
|
import { getImageUrl } from 'educoder';
|
||||||
import { truncateCommitId } from '../common/util';
|
import { truncateCommitId } from '../common/util';
|
||||||
|
import { AlignTop } from '../Component/layout';
|
||||||
import SelectBranch from '../Branch/Select';
|
import SelectBranch from '../Branch/Select';
|
||||||
import Nodata from '../Nodata';
|
import Nodata from '../Nodata';
|
||||||
|
|
||||||
|
@ -74,6 +75,7 @@ class CoderRootCommit extends Component{
|
||||||
array.push({
|
array.push({
|
||||||
name:item.author && item.author.name,
|
name:item.author && item.author.name,
|
||||||
login: item.author && item.author.login,
|
login: item.author && item.author.login,
|
||||||
|
id: item.author && item.author.id,
|
||||||
image_url:item.author && item.author.image_url,
|
image_url:item.author && item.author.image_url,
|
||||||
sha:item.sha,
|
sha:item.sha,
|
||||||
time_from_now:item.time_from_now,
|
time_from_now:item.time_from_now,
|
||||||
|
@ -131,15 +133,23 @@ class CoderRootCommit extends Component{
|
||||||
commitDatas && commitDatas.length > 0 && commitDatas.map((item,k)=>{
|
commitDatas && commitDatas.length > 0 && commitDatas.map((item,k)=>{
|
||||||
return(
|
return(
|
||||||
<div key={k}>
|
<div key={k}>
|
||||||
<p className="f-wrap-alignCenter">
|
<AlignTop>
|
||||||
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="commitKey" style={{marginLeft:0}}>{truncateCommitId(`${item.sha}`)}</Link>
|
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="commitKey" style={{marginLeft:0,marginTop:"3px"}}>{truncateCommitId(`${item.sha}`)}</Link>
|
||||||
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="flex1 ml20 font-16 color-grey-3">{item.message}</Link>
|
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="commitDesc">{item.message}</Link>
|
||||||
</p>
|
</AlignTop>
|
||||||
<p className="f-wrap-alignCenter mt15">
|
<p className="f-wrap-alignCenter mt15">
|
||||||
<Link to={`/users/${item.login}`} className="show-user-link">
|
{
|
||||||
{item.image_url?<img src={getImageUrl(`images/${item.image_url}`)} alt="" width="28px" height="28px" className="mr15 radius"/>:""}
|
item.id ?
|
||||||
<label className="font-14 color-grey-6" style={{verticalAlign:'middle'}}>{item.name ?`${item.name}:`:""}提交于 {item.time_from_now}</label>
|
<Link to={`/users/${item.login}`} className="show-user-link">
|
||||||
</Link>
|
{item.image_url?<img src={getImageUrl(`/${item.image_url}`)} alt="" width="28px" height="28px" className="mr15 radius"/>:""}
|
||||||
|
<label className="font-14 color-grey-6" style={{verticalAlign:'middle'}}>{item.name ?`${item.name}:`:""}提交于 {item.time_from_now}</label>
|
||||||
|
</Link>:
|
||||||
|
<span className="show-user-link">
|
||||||
|
{item.image_url?<img src={getImageUrl(`/${item.image_url}`)} alt="" width="28px" height="28px" className="mr15 radius"/>:""}
|
||||||
|
<label className="font-14 color-grey-6" style={{verticalAlign:'middle'}}>{item.name ?`${item.name}:`:""}提交于 {item.time_from_now}</label>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -31,6 +31,18 @@ class CoderRootFileDetail extends Component {
|
||||||
this.languages_total();
|
this.languages_total();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
componentDidUpdate=(prevProps)=>{
|
||||||
|
const { content } = this.props && this.props.detail;
|
||||||
|
const prevcontent = prevProps.detail && prevProps.detail.content;
|
||||||
|
if (content && prevcontent) {
|
||||||
|
if (prevcontent !== content){
|
||||||
|
this.setState({
|
||||||
|
description: content
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
languages_total = () => {
|
languages_total = () => {
|
||||||
const { detail } = this.props;
|
const { detail } = this.props;
|
||||||
const file_name = detail.path.split("/").pop().split(".").pop();
|
const file_name = detail.path.split("/").pop().split(".").pop();
|
||||||
|
@ -164,9 +176,9 @@ class CoderRootFileDetail extends Component {
|
||||||
current_user,
|
current_user,
|
||||||
isManager,
|
isManager,
|
||||||
isDeveloper,
|
isDeveloper,
|
||||||
md,
|
|
||||||
currentBranch,
|
currentBranch,
|
||||||
platform
|
platform,
|
||||||
|
md
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { language, languages, description } = this.state;
|
const { language, languages, description } = this.state;
|
||||||
let flag = current_user && current_user.login && (isManager || isDeveloper);
|
let flag = current_user && current_user.login && (isManager || isDeveloper);
|
||||||
|
@ -245,11 +257,7 @@ class CoderRootFileDetail extends Component {
|
||||||
<div>
|
<div>
|
||||||
{detail.image_type ? (
|
{detail.image_type ? (
|
||||||
<div className="edu-txt-center pt20 pb20">
|
<div className="edu-txt-center pt20 pb20">
|
||||||
<img
|
<img alt="" src={detail.download_url} style={{ maxWidth: "80%" }} />
|
||||||
alt=""
|
|
||||||
src={detail.download_url}
|
|
||||||
style={{ maxWidth: "80%" }}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
) : detail.direct_download ? (
|
) : detail.direct_download ? (
|
||||||
<div className="mt20 text-center">
|
<div className="mt20 text-center">
|
||||||
|
@ -268,10 +276,11 @@ class CoderRootFileDetail extends Component {
|
||||||
{...this.state}
|
{...this.state}
|
||||||
language={language ? language : "javascript"}
|
language={language ? language : "javascript"}
|
||||||
filepath={`/${detail.path}`}
|
filepath={`/${detail.path}`}
|
||||||
content={detail.content}
|
content={description}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
editorType="update"
|
editorType="update"
|
||||||
currentBranch={currentBranch}
|
currentBranch={currentBranch}
|
||||||
|
descName={detail && `Update ${detail.name}`}
|
||||||
></Meditor>
|
></Meditor>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -26,7 +26,7 @@ export default (( props, { projectDetail }) => {
|
||||||
}, [owner, projectsId]);
|
}, [owner, projectsId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="main">
|
<div className="main" style={{padding:"0px",border:"none"}}>
|
||||||
<Spin spinning={isSpin}>
|
<Spin spinning={isSpin}>
|
||||||
<div style={{minHeight:"400px"}}>
|
<div style={{minHeight:"400px"}}>
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Spin, Tooltip } from 'antd';
|
import { Spin, Tooltip , Button } from 'antd';
|
||||||
import { Link, Route, Switch } from 'react-router-dom';
|
import { Link, Route, Switch } from 'react-router-dom';
|
||||||
import { Content } from '../Component/layout';
|
import { Content , AlignTop } from '../Component/layout';
|
||||||
import DetailBanner from './sub/DetailBanner';
|
import DetailBanner from './sub/DetailBanner';
|
||||||
import '../css/index.scss'
|
import '../css/index.scss'
|
||||||
import './list.css';
|
import './list.css';
|
||||||
|
@ -101,6 +101,14 @@ const Contribute = Loadable({
|
||||||
loader: () => import('./sub/Contribute'),
|
loader: () => import('./sub/Contribute'),
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
})
|
})
|
||||||
|
const Gantt = Loadable({
|
||||||
|
loader: () => import('../Gantt/Index'),
|
||||||
|
loading: Loading,
|
||||||
|
})
|
||||||
|
const Sonar = Loadable({
|
||||||
|
loader: () => import('../Sonar/Index'),
|
||||||
|
loading: Loading,
|
||||||
|
})
|
||||||
|
|
||||||
const CoderRootCommit = Loadable({
|
const CoderRootCommit = Loadable({
|
||||||
loader: () => import('./CoderRootCommit'),
|
loader: () => import('./CoderRootCommit'),
|
||||||
|
@ -151,6 +159,10 @@ function checkPathname(projectsId,owner,pathname){
|
||||||
name="devops"
|
name="devops"
|
||||||
}else if(url.indexOf(`/source`)>-1){
|
}else if(url.indexOf(`/source`)>-1){
|
||||||
name="source"
|
name="source"
|
||||||
|
}else if(url.indexOf(`/gantt`)>-1){
|
||||||
|
name="gantt"
|
||||||
|
}else if(url.indexOf(`/sonar`)>-1){
|
||||||
|
name="sonar"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
|
@ -176,6 +188,7 @@ class Detail extends Component {
|
||||||
firstSync:false,
|
firstSync:false,
|
||||||
secondSync:false,
|
secondSync:false,
|
||||||
open_devops:false,
|
open_devops:false,
|
||||||
|
forkSpin:false,
|
||||||
// 默认分支
|
// 默认分支
|
||||||
defaultBranch:undefined,
|
defaultBranch:undefined,
|
||||||
|
|
||||||
|
@ -358,6 +371,9 @@ class Detail extends Component {
|
||||||
forkFunc = () => {
|
forkFunc = () => {
|
||||||
const { platform } = this.state;
|
const { platform } = this.state;
|
||||||
if(!platform)return;
|
if(!platform)return;
|
||||||
|
this.setState({
|
||||||
|
forkSpin:true
|
||||||
|
})
|
||||||
const { current_user } = this.props
|
const { current_user } = this.props
|
||||||
const { projectsId , owner } = this.props.match.params;
|
const { projectsId , owner } = this.props.match.params;
|
||||||
const url = `/${owner}/${projectsId}/forks.json`;
|
const url = `/${owner}/${projectsId}/forks.json`;
|
||||||
|
@ -366,8 +382,13 @@ class Detail extends Component {
|
||||||
this.props.history.push(`/projects/${current_user && current_user.login}/${result.data.identifier}`);
|
this.props.history.push(`/projects/${current_user && current_user.login}/${result.data.identifier}`);
|
||||||
this.props.showNotification(result.data.message);
|
this.props.showNotification(result.data.message);
|
||||||
}
|
}
|
||||||
|
this.setState({
|
||||||
|
forkSpin:false
|
||||||
|
})
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
console.log(error);
|
this.setState({
|
||||||
|
forkSpin:false
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,32 +410,33 @@ class Detail extends Component {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textFunc = (forked_from_project_id,fork_info)=>{
|
||||||
|
let type = fork_info && fork_info.fork_project_user_type;
|
||||||
|
return forked_from_project_id && fork_info ?
|
||||||
|
<div className="color-grey-9 df">
|
||||||
|
<span>复刻自</span>
|
||||||
|
<Link to={`${type ==="Organization" ? "/organize":'/users'}/${fork_info.fork_project_user_login}`} className="show-user-link color-grey-6 ml5">{fork_info.fork_project_user_name}</Link>
|
||||||
|
<span> / </span>
|
||||||
|
<Link to={`/projects/${fork_info.fork_project_user_login}/${fork_info.fork_project_identifier}`} className="color-grey-6 task-hide flex1" style={{maxWidth:"400px"}} title={fork_info.fork_form_name}>{fork_info.fork_form_name}</Link>
|
||||||
|
</div> : ""
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { projectDetail, watchers_count, praises_count,
|
const { projectDetail, watchers_count, praises_count,
|
||||||
forked_count, firstSync , secondSync ,
|
forked_count, firstSync , secondSync ,
|
||||||
isManager, watched, praised,
|
isManager, watched, praised,
|
||||||
project , open_devops , platform , defaultBranch , bannerList } = this.state;
|
project , open_devops , platform , defaultBranch , bannerList , forkSpin } = this.state;
|
||||||
const url = this.props.history.location.pathname;
|
const url = this.props.history.location.pathname;
|
||||||
const urlArr = url.split("/");
|
const urlArr = url.split("/");
|
||||||
const urlFlag = (urlArr.length === 3);
|
const urlFlag = (urlArr.length === 3);
|
||||||
|
|
||||||
const { projectsId , owner } = this.props.match.params;
|
const { projectsId , owner } = this.props.match.params;
|
||||||
|
const { current_user } = this.props;
|
||||||
let pathname = checkPathname(projectsId,owner,url);
|
let pathname = checkPathname(projectsId,owner,url);
|
||||||
|
|
||||||
const { state } = this.props.history.location;
|
const { state } = this.props.history.location;
|
||||||
|
|
||||||
const text = (
|
|
||||||
projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ?
|
|
||||||
<React.Fragment>
|
|
||||||
<span>forked from </span>
|
|
||||||
<Link to={`/users/${projectDetail.fork_info.fork_project_user_login}`} className="show-user-link color-grey-ccc">{projectDetail.fork_info.fork_project_user_name}</Link>
|
|
||||||
<span> / </span>
|
|
||||||
<Link to={`/projects/${projectDetail.fork_info.fork_project_user_login}/${projectDetail.fork_info.fork_project_identifier}`} className="color-grey-ccc">{projectDetail.fork_info.fork_form_name}</Link>
|
|
||||||
</React.Fragment> : ""
|
|
||||||
);
|
|
||||||
|
|
||||||
const common = {
|
const common = {
|
||||||
getDetail: this.getDetail,
|
getDetail: this.getDetail,
|
||||||
changeOpenDevops:this.changeOpenDevops,
|
changeOpenDevops:this.changeOpenDevops,
|
||||||
|
@ -424,98 +446,95 @@ class Detail extends Component {
|
||||||
<div>
|
<div>
|
||||||
<div className="detailHeader-wrapper">
|
<div className="detailHeader-wrapper">
|
||||||
<div className="normal">
|
<div className="normal">
|
||||||
<div className="f-wrap-between pb15" style={{ position: "relative" }}>
|
<AlignTop style={{padding:"20px 0px 10px",justifyContent:"space-between"}}>
|
||||||
<p className="font-22 df flex-1 lineH2 mt15" style={{ alignItems: "center" }}>
|
<div>
|
||||||
{project && project.author &&
|
<AlignTop>
|
||||||
<Link to={`${project.author.type ==="Organization" ? "/organize":'/users'}/${project.author.login}`} className="show-user-link">
|
<div className="projectallName">
|
||||||
{project.author.name}
|
{project && project.author &&
|
||||||
</Link>
|
<Link to={`${project.author.type ==="Organization" ? "/organize":'/users'}/${project.author.login}`}>{project.author.name}</Link>
|
||||||
}
|
}
|
||||||
<span className="ml5 mr5">/</span>
|
<span className="ml5 mr5">/</span>
|
||||||
<span className="hide-1 flex-1 df">
|
<Link to={`/projects/${owner}/${projectsId}`} className="projectN mt6">{project && project.name}</Link>
|
||||||
<Link to={`/projects/${owner}/${projectsId}`} className="font-22">{project && project.name}</Link>
|
</div>
|
||||||
|
{ projectDetail && projectDetail.private && <span className="privateTag mt6">私有</span>}
|
||||||
|
</AlignTop>
|
||||||
|
<div className="mt8">
|
||||||
{
|
{
|
||||||
projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ?
|
projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ?
|
||||||
<Tooltip placement={'right'} title={text}>
|
this.textFunc(projectDetail.forked_from_project_id,projectDetail.fork_info)
|
||||||
<Link to={`/projects/${projectDetail.fork_info.fork_project_user_login}/${projectDetail.fork_info.fork_project_identifier}`}
|
:""
|
||||||
className="ml10" >
|
|
||||||
<i className="iconfont icon-fork font-18 fl mt6" style={{ color: "#8D90E3" }}></i>
|
|
||||||
</Link>
|
|
||||||
</Tooltip> : ""
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
projectDetail && projectDetail.type && projectDetail.type !== 0 ?
|
projectDetail && projectDetail.type && projectDetail.type !== 0 ?
|
||||||
projectDetail.type === 2 ?
|
<span className="color-grey-9">镜像自 <a className="color-grey-6" target="_blank" href={projectDetail.mirror_url}>{projectDetail.mirror_url}</a></span>
|
||||||
<Tooltip title={"镜像自: " + projectDetail.mirror_url} className="ml5" placement={'right'}>
|
|
||||||
<i className="iconfont icon-banbenku font-18 mt6" style={{ color: "#8D90E3" }}/>
|
|
||||||
</Tooltip>
|
|
||||||
:
|
|
||||||
<Tooltip title={"镜像自: " + projectDetail.mirror_url} className="ml5" placement={'right'}>
|
|
||||||
<i className="iconfont icon-jingxiang font-18 color-green mt6" />
|
|
||||||
</Tooltip>
|
|
||||||
:""
|
:""
|
||||||
}
|
}
|
||||||
</span>
|
</div>
|
||||||
</p>
|
</div>
|
||||||
{
|
<div>
|
||||||
firstSync ? "":
|
{
|
||||||
<span className="df mt25">
|
firstSync ? "":
|
||||||
{
|
<span className="df">
|
||||||
projectDetail && projectDetail.type && projectDetail.type === 2 ?
|
{
|
||||||
|
((current_user && current_user.admin) || isManager) && (projectDetail && projectDetail.type && projectDetail.type === 2) ?
|
||||||
<a className="synchronism ml30" onClick={this.synchronismMirror}>同步镜像</a> : ""
|
<a className="synchronism ml30" onClick={this.synchronismMirror}>同步镜像</a> : ""
|
||||||
}
|
|
||||||
<span className="detail_tag_btn">
|
|
||||||
<a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={() => this.focusFunc(watched)}>
|
|
||||||
<i className={watched ? "iconfont icon-shixing color-orange font-16 mr3":"iconfont icon-kongxing color-grey-9 font-16 mr3"}></i>
|
|
||||||
<span>{watched ? '取消关注' : '关注'}</span>
|
|
||||||
</a>
|
|
||||||
{
|
|
||||||
watchers_count > 0 ?
|
|
||||||
platform ?
|
|
||||||
<Link className="detail_tag_btn_count" style={{color:`${watched?"#2878FF":"#666"}`}} to={platform?{ pathname: `/projects/${owner}/${projectsId}/watchers`, state }:""}>
|
|
||||||
{watchers_count}
|
|
||||||
</Link>
|
|
||||||
:
|
|
||||||
<span className="detail_tag_btn_count">{watchers_count}</span>
|
|
||||||
:""
|
|
||||||
}
|
}
|
||||||
|
<Button className="detail_tag_btn">
|
||||||
|
<a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={() => this.focusFunc(watched)}>
|
||||||
|
<i className={watched ? "iconfont icon-shixing color-orange font-16 mr3":"iconfont icon-kongxing color-grey-9 font-16 mr3"}></i>
|
||||||
|
<span>{watched ? '取消关注' : '关注'}</span>
|
||||||
|
</a>
|
||||||
|
{
|
||||||
|
watchers_count > 0 ?
|
||||||
|
platform ?
|
||||||
|
<Link className="detail_tag_btn_count" style={{color:`${watched?"#2878FF":"#666"}`}} to={platform?{ pathname: `/projects/${owner}/${projectsId}/watchers`, state }:""}>
|
||||||
|
{watchers_count}
|
||||||
|
</Link>
|
||||||
|
:
|
||||||
|
<span className="detail_tag_btn_count">{watchers_count}</span>
|
||||||
|
:""
|
||||||
|
}
|
||||||
|
</Button>
|
||||||
|
<Button className="detail_tag_btn">
|
||||||
|
<a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={() => this.pariseFunc(praised)}>
|
||||||
|
<i className={praised ? "iconfont icon-weibiaoti105 color-orange font-14 mr3":"iconfont icon-guanzhu color-grey-9 font-14 mr3"}></i>
|
||||||
|
<span>{praised ? '取消点赞' : '点赞'}</span>
|
||||||
|
</a>
|
||||||
|
{
|
||||||
|
praises_count > 0 ?
|
||||||
|
platform ?
|
||||||
|
<Link className="detail_tag_btn_count" style={{color:`${praised?"#2878FF":"#666"}`}} to={{ pathname: `/projects/${owner}/${projectsId}/stargazers`, state }}>
|
||||||
|
{praises_count}
|
||||||
|
</Link>:
|
||||||
|
<span className="detail_tag_btn_count">{praises_count}</span>
|
||||||
|
:""
|
||||||
|
}
|
||||||
|
</Button>
|
||||||
|
<Button className="detail_tag_btn" loading={forkSpin}>
|
||||||
|
<Tooltip title="复刻是fork的中文名,即复制代码仓库" placement="bottom">
|
||||||
|
<a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={this.forkFunc}>
|
||||||
|
<i className="iconfont icon-fork color-grey-9 mr3"></i>复刻
|
||||||
|
</a>
|
||||||
|
</Tooltip>
|
||||||
|
{
|
||||||
|
forked_count > 0 ?
|
||||||
|
platform ?
|
||||||
|
<Link className="detail_tag_btn_count" to={{ pathname: `/projects/${owner}/${projectsId}/fork_users`, state }}>
|
||||||
|
{forked_count}
|
||||||
|
</Link>
|
||||||
|
:
|
||||||
|
<span className="detail_tag_btn_count">{forked_count}</span>
|
||||||
|
:""
|
||||||
|
}
|
||||||
|
</Button>
|
||||||
</span>
|
</span>
|
||||||
<span className="detail_tag_btn">
|
}
|
||||||
<a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={() => this.pariseFunc(praised)}>
|
</div>
|
||||||
<i className={praised ? "iconfont icon-weibiaoti105 color-orange font-14 mr3":"iconfont icon-guanzhu color-grey-9 font-14 mr3"}></i>
|
</AlignTop>
|
||||||
<span>{praised ? '取消点赞' : '点赞'}</span>
|
|
||||||
</a>
|
|
||||||
{
|
|
||||||
praises_count > 0 ?
|
|
||||||
platform ?
|
|
||||||
<Link className="detail_tag_btn_count" style={{color:`${praised?"#2878FF":"#666"}`}} to={{ pathname: `/projects/${owner}/${projectsId}/stargazers`, state }}>
|
|
||||||
{praises_count}
|
|
||||||
</Link>:
|
|
||||||
<span className="detail_tag_btn_count">{praises_count}</span>
|
|
||||||
:""
|
|
||||||
}
|
|
||||||
</span>
|
|
||||||
<span className="detail_tag_btn">
|
|
||||||
<a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={this.forkFunc}>
|
|
||||||
<i className="iconfont icon-fork color-grey-9 mr3"></i>复刻 (Fork)
|
|
||||||
</a>
|
|
||||||
{
|
|
||||||
forked_count > 0 ?
|
|
||||||
platform ?
|
|
||||||
<Link className="detail_tag_btn_count" to={{ pathname: `/projects/${owner}/${projectsId}/fork_users`, state }}>
|
|
||||||
{forked_count}
|
|
||||||
</Link>
|
|
||||||
:
|
|
||||||
<span className="detail_tag_btn_count">{forked_count}</span>
|
|
||||||
:""
|
|
||||||
}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
{
|
{
|
||||||
firstSync ? "" :
|
firstSync ? "" :
|
||||||
<DetailBanner
|
<DetailBanner
|
||||||
|
history={this.props.history}
|
||||||
list={bannerList}
|
list={bannerList}
|
||||||
owner={owner}
|
owner={owner}
|
||||||
projectsId={projectsId}
|
projectsId={projectsId}
|
||||||
|
@ -635,6 +654,11 @@ class Detail extends Component {
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
{/* 新建合并请求 */}
|
{/* 新建合并请求 */}
|
||||||
|
<Route path="/projects/:owner/:projectsId/pulls/new/:branch"
|
||||||
|
render={
|
||||||
|
(props) => (<CreateMerge {...this.props} {...props} {...this.state} {...common} is_fork={true} />)
|
||||||
|
}
|
||||||
|
></Route>
|
||||||
<Route path="/projects/:owner/:projectsId/pulls/new"
|
<Route path="/projects/:owner/:projectsId/pulls/new"
|
||||||
render={
|
render={
|
||||||
(props) => (<CreateMerge {...this.props} {...props} {...this.state} {...common} is_fork={true} />)
|
(props) => (<CreateMerge {...this.props} {...props} {...this.state} {...common} is_fork={true} />)
|
||||||
|
@ -661,6 +685,20 @@ class Detail extends Component {
|
||||||
(props) => (<MergeIndexDetail {...this.props} {...props} {...this.state} {...common} />)
|
(props) => (<MergeIndexDetail {...this.props} {...props} {...this.state} {...common} />)
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
|
|
||||||
|
{/* 甘特图 */}
|
||||||
|
<Route path="/projects/:owner/:projectsId/gantt"
|
||||||
|
render={
|
||||||
|
(props) => (<Gantt {...this.props} {...props} {...this.state} {...common} />)
|
||||||
|
}
|
||||||
|
></Route>
|
||||||
|
{/* 甘特图 */}
|
||||||
|
<Route path="/projects/:owner/:projectsId/sonar"
|
||||||
|
render={
|
||||||
|
(props) => (<Sonar {...this.props} {...props} {...this.state} {...common} />)
|
||||||
|
}
|
||||||
|
></Route>
|
||||||
|
|
||||||
<Route path="/projects/:owner/:projectsId/watchers"
|
<Route path="/projects/:owner/:projectsId/watchers"
|
||||||
render={
|
render={
|
||||||
(props) => (<WatchUsers {...this.props} {...props} {...this.state} {...common} />)
|
(props) => (<WatchUsers {...this.props} {...props} {...this.state} {...common} />)
|
||||||
|
|
|
@ -51,7 +51,7 @@ export default ({ match , history }) => {
|
||||||
}
|
}
|
||||||
}, [projectsId , owner, sha]);
|
}, [projectsId , owner, sha]);
|
||||||
return (
|
return (
|
||||||
<div className="main">
|
<div className="main" style={{padding:"0px",border:"none"}}>
|
||||||
<Spin spinning={isSpin}>
|
<Spin spinning={isSpin}>
|
||||||
<Infos>
|
<Infos>
|
||||||
<div className="commitinfos">
|
<div className="commitinfos">
|
||||||
|
@ -65,7 +65,7 @@ export default ({ match , history }) => {
|
||||||
<div className="f-wrap-between" style={{ alignItems: "center" }}>
|
<div className="f-wrap-between" style={{ alignItems: "center" }}>
|
||||||
<ul className="df">
|
<ul className="df">
|
||||||
<User
|
<User
|
||||||
url={(committer && getImageUrl(`images/${committer.image_url}`))|| "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"}
|
url={(committer && getImageUrl(`/${committer.image_url}`))|| "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"}
|
||||||
name={committer && committer.name}
|
name={committer && committer.name}
|
||||||
/>
|
/>
|
||||||
{committer && committer.time_from_now && <li className="ml20 mt2">{committer.time_from_now}</li>}
|
{committer && committer.time_from_now && <li className="ml20 mt2">{committer.time_from_now}</li>}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { Menu, Input , Spin, Pagination , Popover , Select } from 'antd';
|
import { Menu, Input , Spin, Pagination , Popover , Select , Button } from 'antd';
|
||||||
import { getUrl } from 'educoder';
|
import { getImageUrl } from 'educoder';
|
||||||
import '../css/index.scss'
|
import '../css/index.scss'
|
||||||
import './list.css';
|
import './list.css';
|
||||||
import './Index.scss';
|
import './Index.scss';
|
||||||
|
@ -9,7 +9,8 @@ import ListItem from './IndexItem'
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import img_new from '../Images/new.png';
|
import img_new from '../Images/new.png';
|
||||||
import img_array from '../Images/array.png';
|
import img_array from '../Images/array.png';
|
||||||
import banner from '../Images/banner_list.jpg';
|
import banner from '../Images/banner.png';
|
||||||
|
import AddProjectModal from '../Head/AddProjectModal';
|
||||||
const Search = Input.Search;
|
const Search = Input.Search;
|
||||||
|
|
||||||
class Index extends Component {
|
class Index extends Component {
|
||||||
|
@ -260,9 +261,24 @@ class Index extends Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p className="t_project_banner">
|
<div className="subjectBanner">
|
||||||
<img src={banner} width="100%" alt=""/>
|
<img src={banner} alt=""/>
|
||||||
</p>
|
<div className="bannerBox">
|
||||||
|
<div class="subjectleft">
|
||||||
|
<span>开源社区</span>
|
||||||
|
<span>面向高校的教学开源</span>
|
||||||
|
</div>
|
||||||
|
<Button type={"primary"} size={"large"}>
|
||||||
|
<Link to={`/projects/deposit/new`}>新建项目</Link>
|
||||||
|
</Button>
|
||||||
|
<Button type={"primary"} size={"large"}>
|
||||||
|
<AddProjectModal showNotification={this.props.showNotification}/>
|
||||||
|
</Button>
|
||||||
|
{/* <Button type={"primary"} size={"large"} style={{backgroundColor:"rgb(47, 163, 79)",borderColor:"rgb(47, 163, 79)"}}>
|
||||||
|
<a href={`https://data.educoder.net/api/attachments/1955244?disposition=inline`} target="_blank">新手指引</a>
|
||||||
|
</Button> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{
|
{
|
||||||
recommendList && recommendList.length>0 &&
|
recommendList && recommendList.length>0 &&
|
||||||
<div className="recommandProjects">
|
<div className="recommandProjects">
|
||||||
|
@ -271,7 +287,7 @@ class Index extends Component {
|
||||||
return(
|
return(
|
||||||
<div onClick={()=>this.getoDetail(item.author && item.author.login,item.identifier)}>
|
<div onClick={()=>this.getoDetail(item.author && item.author.login,item.identifier)}>
|
||||||
<div className="mainInfo">
|
<div className="mainInfo">
|
||||||
<img src={getUrl(`/images/${item.author && item.author.image_url}`)} alt=""/>
|
<img src={getImageUrl(`/${item.author && item.author.image_url}`)} alt=""/>
|
||||||
<p className="school">{item.name}</p>
|
<p className="school">{item.name}</p>
|
||||||
<p className="name">{item.author && item.author.name}</p>
|
<p className="name">{item.author && item.author.name}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -73,7 +73,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// coderDepot
|
// coderDepot
|
||||||
.Panels{
|
.Panels{
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
|
@ -129,9 +128,7 @@
|
||||||
height: 7px;
|
height: 7px;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
span{
|
span{
|
||||||
border-left: 1px solid #fff;
|
|
||||||
&:first-child{
|
&:first-child{
|
||||||
border-left: none;
|
|
||||||
border-radius: 10px 0px 0px 10px;
|
border-radius: 10px 0px 0px 10px;
|
||||||
}
|
}
|
||||||
&:last-child{
|
&:last-child{
|
||||||
|
@ -177,27 +174,33 @@
|
||||||
border-radius: 4px 4px 0px 0px;
|
border-radius: 4px 4px 0px 0px;
|
||||||
background-color: #FAFBFC;
|
background-color: #FAFBFC;
|
||||||
.ellipsistxt{
|
.ellipsistxt{
|
||||||
|
margin-top: 6px;
|
||||||
|
#ptxt{
|
||||||
|
margin-bottom: 0px;
|
||||||
|
word-break: break-all;
|
||||||
|
overflow: unset;
|
||||||
|
white-space:pre-wrap; /* css3.0 */
|
||||||
|
white-space:-moz-pre-wrap; /* Firefox */
|
||||||
|
white-space:-pre-wrap; /* Opera 4-6 */
|
||||||
|
white-space:-o-pre-wrap; /* Opera 7 */
|
||||||
|
word-wrap:break-word;
|
||||||
|
}
|
||||||
margin-left: 13px;
|
margin-left: 13px;
|
||||||
line-height:18px;
|
line-height:18px;
|
||||||
margin-top:6px;
|
|
||||||
flex:1;
|
flex:1;
|
||||||
width: 0;
|
width: 0;
|
||||||
color: #666;
|
color: #666;
|
||||||
&>p{
|
&.hidetxt{
|
||||||
word-break:break-all;
|
|
||||||
}
|
|
||||||
&.hide{
|
|
||||||
height: 18px;
|
height: 18px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-right:8px;
|
padding-right:8px;
|
||||||
}
|
&::after{
|
||||||
&.hide::after{
|
position: absolute;
|
||||||
position: absolute;
|
right: 0px;
|
||||||
right: 0px;
|
bottom: 0px;
|
||||||
bottom: 0px;
|
content:"...";
|
||||||
content:"...";
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ellipsis{
|
.ellipsis{
|
||||||
|
@ -220,8 +223,11 @@
|
||||||
.listtablebody{
|
.listtablebody{
|
||||||
li.listtablepath{
|
li.listtablepath{
|
||||||
a{color: #40a9ff;}
|
a{color: #40a9ff;}
|
||||||
|
p{
|
||||||
|
margin-bottom: 0px!important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
li{
|
& > li{
|
||||||
height: 42px;
|
height: 42px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
@ -283,4 +289,52 @@
|
||||||
.downMenu{
|
.downMenu{
|
||||||
box-shadow: 0px 0px 9px rgba(134, 134, 134,0.4);
|
box-shadow: 0px 0px 9px rgba(134, 134, 134,0.4);
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
.ant-menu-vertical .ant-menu-item:hover{
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuslist{
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding:10px 15px;
|
||||||
|
border-radius: 4px;
|
||||||
|
.ant-dropdown-menu-item{
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: left!important;
|
||||||
|
a{
|
||||||
|
width: 350px;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-dropdown-menu-item.active{
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.catelogue{
|
||||||
|
border:1px solid rgb(211, 211, 211);
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: normal;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-right: 10px;
|
||||||
|
padding:0px 10px;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
color: #666!important;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
span{
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.submoduleStyle{
|
||||||
|
cursor: default;
|
||||||
|
i{
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
color: #05101a;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Tooltip } from 'antd';
|
import { Tooltip } from 'antd';
|
||||||
import { getImageUrl } from 'educoder';
|
import { getImageUrl } from 'educoder';
|
||||||
|
import { AlignCenter } from '../Component/layout';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import '../css/index.scss';
|
import '../css/index.scss';
|
||||||
import Nodata from '../Nodata';
|
import Nodata from '../Nodata';
|
||||||
|
@ -17,7 +18,7 @@ class IndexItem extends Component {
|
||||||
render() {
|
render() {
|
||||||
const { projects } = this.props;
|
const { projects } = this.props;
|
||||||
return (
|
return (
|
||||||
<div className="project-list minH-670">
|
<div className="project-list minH-670" style={{padding:"0px 20px"}}>
|
||||||
{ projects && projects.length > 0 ? projects.map((item, key) => {
|
{ projects && projects.length > 0 ? projects.map((item, key) => {
|
||||||
return (
|
return (
|
||||||
<div className="p-r-Item" key={key}>
|
<div className="p-r-Item" key={key}>
|
||||||
|
@ -27,14 +28,17 @@ class IndexItem extends Component {
|
||||||
<img className="p-r-photo" alt="" src={item.author && item.author.image_url} ></img>
|
<img className="p-r-photo" alt="" src={item.author && item.author.image_url} ></img>
|
||||||
</a>
|
</a>
|
||||||
:
|
:
|
||||||
<Link to={`/users/${item.author.login}`} className="show-user-link">
|
<Link to={item.author && (item.author.type === "Organization" ? `/organize/${item.author.login}`:`/users/${item.author.login}`)} className="show-user-link">
|
||||||
<img className="p-r-photo" alt="" src={getImageUrl(`${item.author && item.author.image_url}`)} ></img>
|
<img className="p-r-photo" alt="" src={getImageUrl(`/${item.author && item.author.image_url}`)} ></img>
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
<div className="p-r-Infos">
|
<div className="p-r-Infos">
|
||||||
<div className="p-r-name">
|
<div className="p-r-name">
|
||||||
<Link to={`/projects/${item.author.login}/${item.identifier}`} className="hide-1 color-grey-3 font-18 task-hide " style={{ whiteSpace: "wrap", display: 'flex', width: 400 }}>
|
<AlignCenter>
|
||||||
{item.author.name}/{item.name}
|
<Link to={`/projects/${item.author.login}/${item.identifier}`} title={`${item.author.name}/${item.name}`} className="color-grey-3 font-18 task-hide " style={{maxWidth: 470 }}>
|
||||||
|
{item.author.name}/{item.name}
|
||||||
|
</Link>
|
||||||
|
{ !item.is_public && <span className="privateTag">私有</span> }
|
||||||
{
|
{
|
||||||
item.forked_from_project_id ?
|
item.forked_from_project_id ?
|
||||||
<span className="ml5">
|
<span className="ml5">
|
||||||
|
@ -52,10 +56,20 @@ class IndexItem extends Component {
|
||||||
<i className="iconfont icon-jingxiang font-18 color-green" />
|
<i className="iconfont icon-jingxiang font-18 color-green" />
|
||||||
</span>:""
|
</span>:""
|
||||||
}
|
}
|
||||||
</Link>
|
</AlignCenter>
|
||||||
<span className="p-r-tags">
|
<span className="p-r-tags">
|
||||||
<span className="pariseTag"><img src={img_parise} alt="" className="pariseImg" />赞 {item.praises_count}</span>
|
{
|
||||||
<span><i className="iconfont icon-fork mr3 font-16" style={{ color: "#1B8FFF" }} />fork {item.forked_count}</span>
|
item.praises_count && item.praises_count>0 ?
|
||||||
|
<span className="pariseTag">
|
||||||
|
<img src={img_parise} alt="" className="pariseImg" />赞 {item.praises_count}
|
||||||
|
</span>:""
|
||||||
|
}
|
||||||
|
{
|
||||||
|
item.forked_count && item.forked_count>0 ?
|
||||||
|
<span>
|
||||||
|
<i className="iconfont icon-fork mr3 font-16" style={{ color: "#1B8FFF" }} />fork {item.forked_count}
|
||||||
|
</span>:""
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="break_word task-hide-2 mt10" style={{ maxHeight: "44px",lineHeight:"22px" }}>{item.description}</p>
|
<p className="break_word task-hide-2 mt10" style={{ maxHeight: "44px",lineHeight:"22px" }}>{item.description}</p>
|
||||||
|
|
|
@ -1,10 +1,51 @@
|
||||||
|
|
||||||
.lineH2{line-height:2}
|
.lineH2{line-height:2}
|
||||||
.t_project_banner {
|
.subjectBanner {
|
||||||
/* height: 260px;
|
height: 160px;
|
||||||
background: url(../Images/banner_list.jpg) no-repeat center; */
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
background-color: #050d34;
|
background-color: #050d34;
|
||||||
}
|
}
|
||||||
|
.subjectleft{
|
||||||
|
margin-top: 40px;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.bannerBox{
|
||||||
|
width: 1200px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
left: 50%;
|
||||||
|
top: 0;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
.subjectleft span:first-child{
|
||||||
|
width: 140px;
|
||||||
|
height: 30px;
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 30px;
|
||||||
|
letter-spacing: 4px;
|
||||||
|
}
|
||||||
|
.subjectleft span:last-child{
|
||||||
|
height: 16px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
letter-spacing: 4px;
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
.bannerBox .ant-btn{
|
||||||
|
margin-top: 30px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 16px;
|
||||||
|
width: 120px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-right: 40px;
|
||||||
|
}
|
||||||
.ProjectListIndex{
|
.ProjectListIndex{
|
||||||
width: 1200px;
|
width: 1200px;
|
||||||
margin:20px auto;
|
margin:20px auto;
|
||||||
|
@ -91,6 +132,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
border-bottom:1px solid rgba(238,238,238,1);
|
border-bottom:1px solid rgba(238,238,238,1);
|
||||||
padding:22px 0px;
|
padding:22px 0px;
|
||||||
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
.boxShandow{
|
.boxShandow{
|
||||||
box-shadow:0px 2px 20px 10px rgba(0,0,0,0.03);
|
box-shadow:0px 2px 20px 10px rgba(0,0,0,0.03);
|
||||||
|
@ -100,6 +142,7 @@
|
||||||
height: 60px;
|
height: 60px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
margin-right: 22px;
|
margin-right: 22px;
|
||||||
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
.p-r-Infos{
|
.p-r-Infos{
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
@ -108,6 +151,7 @@
|
||||||
.p-r-name{
|
.p-r-name{
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
.p-r-name > p{
|
.p-r-name > p{
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
@ -261,7 +305,10 @@
|
||||||
border:1px solid #f1f1f1;
|
border:1px solid #f1f1f1;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-left: 30px
|
margin-left: 30px;
|
||||||
|
padding:0px;
|
||||||
|
background-color: transparent;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
.ant-tooltip {
|
.ant-tooltip {
|
||||||
max-width: fit-content!important;
|
max-width: fit-content!important;
|
||||||
|
@ -281,7 +328,6 @@
|
||||||
height:100%;
|
height:100%;
|
||||||
}
|
}
|
||||||
.files-md{
|
.files-md{
|
||||||
border:1px solid #eee;
|
|
||||||
padding:20px;
|
padding:20px;
|
||||||
}
|
}
|
||||||
/* 详情-代码 */
|
/* 详情-代码 */
|
||||||
|
@ -437,9 +483,6 @@
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
border-bottom: 1px solid #d9d9d9;
|
border-bottom: 1px solid #d9d9d9;
|
||||||
}
|
}
|
||||||
.branchUl{
|
|
||||||
padding:0px 30px;
|
|
||||||
}
|
|
||||||
.branchUl li{
|
.branchUl li{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
@ -565,6 +608,10 @@
|
||||||
border-bottom: 1px solid #d9d9d9;
|
border-bottom: 1px solid #d9d9d9;
|
||||||
border-radius: 4px 4px 0px 0px;
|
border-radius: 4px 4px 0px 0px;
|
||||||
}
|
}
|
||||||
|
.commonBox .commonBox-title.boxTitle{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
.synchronism{
|
.synchronism{
|
||||||
display: block;
|
display: block;
|
||||||
height: 26px;
|
height: 26px;
|
||||||
|
|
|
@ -50,7 +50,7 @@ function Contribute(props){
|
||||||
list.map((item,key)=>{
|
list.map((item,key)=>{
|
||||||
return(
|
return(
|
||||||
<AlignCenter>
|
<AlignCenter>
|
||||||
<img alt="" style={{borderRadius:"50%",marginRight:"10px"}} src={getImageUrl(`images/${item.image_url}`)} width="50px" height="50px"/>
|
<img alt="" style={{borderRadius:"50%",marginRight:"10px"}} src={getImageUrl(`/${item.image_url}`)} width="50px" height="50px"/>
|
||||||
<div>
|
<div>
|
||||||
<Link to={`/users/${item.login}`} className="font-16">{item.name}</Link>
|
<Link to={`/users/${item.login}`} className="font-16">{item.name}</Link>
|
||||||
<p className="font-12 color-grey-9">提交{item.contributions}次</p>
|
<p className="font-12 color-grey-9">提交{item.contributions}次</p>
|
||||||
|
|
|
@ -1,18 +1,25 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Skeleton } from 'antd';
|
import { Skeleton , Tooltip } from 'antd';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
function DetailBanner({ list , owner , projectsId , isManager , url , pathname , state , urlFlag , projectDetail , platform ,open_devops }){
|
function DetailBanner({ history,list , owner , projectsId , isManager , url , pathname , state , urlFlag , projectDetail , platform ,open_devops }){
|
||||||
const [ menuName , setMenuName ] = useState(undefined);
|
const [ menuName , setMenuName ] = useState(undefined);
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if(list){
|
if(list){
|
||||||
|
// 没有资源库banner但是通过连接进资源库页面时
|
||||||
|
if(pathname && pathname==="source"){
|
||||||
|
let a = list.filter(item=>item.menu_name === "resources");
|
||||||
|
if(a && a.length === 0){
|
||||||
|
history.push(`/projects/${owner}/${projectsId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
setMenuName(list);
|
setMenuName(list);
|
||||||
}
|
}
|
||||||
},[list]);
|
},[list]);
|
||||||
return(
|
return(
|
||||||
<div className="f-wrap-between mt15">
|
<div className="f-wrap-between mt15">
|
||||||
{
|
{
|
||||||
menuName && projectDetail ?
|
menuName && menuName.length> 0 && projectDetail ?
|
||||||
<ul className="headerMenu-wrapper">
|
<ul className="headerMenu-wrapper">
|
||||||
{
|
{
|
||||||
menuName.map((item,key)=>{
|
menuName.map((item,key)=>{
|
||||||
|
@ -32,18 +39,20 @@ function DetailBanner({ list , owner , projectsId , isManager , url , pathname ,
|
||||||
<li className={(pathname==="" || urlFlag) ? "active" : ""}>
|
<li className={(pathname==="" || urlFlag) ? "active" : ""}>
|
||||||
<Link to={{ pathname: `/projects/${owner}/${projectsId}`, state }}>
|
<Link to={{ pathname: `/projects/${owner}/${projectsId}`, state }}>
|
||||||
<i className={(pathname==="" || urlFlag) ? "iconfont icon-daimaku color-grey-3 mr5 font-14":"iconfont icon-daimaku color-grey-6 font-14 mr5"}></i>
|
<i className={(pathname==="" || urlFlag) ? "iconfont icon-daimaku color-grey-3 mr5 font-14":"iconfont icon-daimaku color-grey-6 font-14 mr5"}></i>
|
||||||
<span>代码库</span>
|
<span>代码</span>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
item.menu_name === "issues" &&
|
item.menu_name === "issues" &&
|
||||||
<li className={pathname==="issues" ? "active" : ""}>
|
<li className={pathname==="issues" ? "active" : ""}>
|
||||||
<Link to={{ pathname: `/projects/${owner}/${projectsId}/issues`, state }}>
|
<Tooltip title="易修是Issue的中文名,即问题列表" placement="bottom">
|
||||||
<i className={pathname==="issues" ? "iconfont icon-renwu color-grey-3 mr5 font-14":"iconfont icon-renwu color-grey-6 font-14 mr5"}></i>
|
<Link to={{ pathname: `/projects/${owner}/${projectsId}/issues`, state }}>
|
||||||
<span>易修 (Issue)</span>
|
<i className={pathname==="issues" ? "iconfont icon-renwu color-grey-3 mr5 font-14":"iconfont icon-renwu color-grey-6 font-14 mr5"}></i>
|
||||||
{projectDetail && projectDetail.issues_count ? <span className="num">{projectDetail.issues_count}</span> : ""}
|
<span>易修</span>
|
||||||
</Link>
|
{projectDetail && projectDetail.issues_count ? <span className="num">{projectDetail.issues_count}</span> : ""}
|
||||||
|
</Link>
|
||||||
|
</Tooltip>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
@ -60,14 +69,14 @@ function DetailBanner({ list , owner , projectsId , isManager , url , pathname ,
|
||||||
item.menu_name === "devops" && platform ?
|
item.menu_name === "devops" && platform ?
|
||||||
<li className={pathname==="devops" ? "active" : ""}>
|
<li className={pathname==="devops" ? "active" : ""}>
|
||||||
<Link to={{ pathname: `/projects/${owner}/${projectsId}/devops${open_devops ? `/dispose`:""}`, state }}>
|
<Link to={{ pathname: `/projects/${owner}/${projectsId}/devops${open_devops ? `/dispose`:""}`, state }}>
|
||||||
<i className="iconfont icon-gongzuoliu font-13 mr8"></i>工作流(beta版)
|
<i className="iconfont icon-gongzuoliu font-13 mr8"></i>工作流
|
||||||
{projectDetail && projectDetail.ops_count ? <span>{projectDetail.ops_count}</span> : ""}
|
{projectDetail && projectDetail.ops_count ? <span>{projectDetail.ops_count}</span> : ""}
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
:""
|
:""
|
||||||
}
|
}
|
||||||
{
|
{/* {
|
||||||
item.menu_name === "source" &&
|
item.menu_name === "resources" &&
|
||||||
<li className={pathname==="source" ? "active" : ""}>
|
<li className={pathname==="source" ? "active" : ""}>
|
||||||
<Link to={{ pathname: `/projects/${owner}/${projectsId}/source`, state }}>
|
<Link to={{ pathname: `/projects/${owner}/${projectsId}/source`, state }}>
|
||||||
<i className={pathname==="source" ? "iconfont icon-ziyuanpaihanghetuijian color-grey-3 mr5 font-14":"iconfont icon-ziyuanpaihanghetuijian color-grey-6 font-14 mr5"}></i>
|
<i className={pathname==="source" ? "iconfont icon-ziyuanpaihanghetuijian color-grey-3 mr5 font-14":"iconfont icon-ziyuanpaihanghetuijian color-grey-6 font-14 mr5"}></i>
|
||||||
|
@ -75,7 +84,7 @@ function DetailBanner({ list , owner , projectsId , isManager , url , pathname ,
|
||||||
{projectDetail && projectDetail.source_count ? <span className="num">{projectDetail.source_count}</span> :""}
|
{projectDetail && projectDetail.source_count ? <span className="num">{projectDetail.source_count}</span> :""}
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
}
|
} */}
|
||||||
{
|
{
|
||||||
item.menu_name === "versions" &&
|
item.menu_name === "versions" &&
|
||||||
<li className={pathname==="milestones" ? "active" : ""}>
|
<li className={pathname==="milestones" ? "active" : ""}>
|
||||||
|
@ -95,19 +104,37 @@ function DetailBanner({ list , owner , projectsId , isManager , url , pathname ,
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
item.menu_name === "setting" &&
|
||||||
|
<li className={pathname === "setting" ? "active" : ""}>
|
||||||
|
<Link to={`/projects/${owner}/${projectsId}/setting`}>
|
||||||
|
<i className={url && url.indexOf("/setting") > 0 ? "iconfont icon-cangku color-grey-3 mr5 font-14":"iconfont icon-cangku color-grey-6 font-14 mr5"}></i>
|
||||||
|
<span>设置</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
item.menu_name === "gantt" &&
|
||||||
|
<li className={pathname === "gantt" ? "active" : ""}>
|
||||||
|
<Link to={`/projects/${owner}/${projectsId}/gantt`}>
|
||||||
|
<i className={url && url.indexOf("/gantt") > 0 ? "iconfont icon-zuzhi color-grey-3 mr5 font-14":"iconfont icon-zuzhi color-grey-6 font-14 mr5"}></i>
|
||||||
|
<span>甘特图</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
item.menu_name === "sonar" &&
|
||||||
|
<li className={pathname === "sonar" ? "active" : ""}>
|
||||||
|
<Link to={`/projects/${owner}/${projectsId}/sonar`}>
|
||||||
|
<i className={url && url.indexOf("/sonar") > 0 ? "iconfont icon-tijiao color-grey-3 mr5 font-18":"iconfont icon-tijiao color-grey-6 font-18 mr5"}></i>
|
||||||
|
<span>质量分析/检测</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
{
|
|
||||||
isManager && platform ?
|
|
||||||
<li className={pathname === "setting" ? "active" : ""}>
|
|
||||||
<Link to={`/projects/${owner}/${projectsId}/setting`}>
|
|
||||||
<i className={url && url.indexOf("/setting") > 0 ? "iconfont icon-cangku color-grey-3 mr5 font-14":"iconfont icon-cangku color-grey-6 font-14 mr5"}></i>
|
|
||||||
<span>仓库设置</span>
|
|
||||||
</Link>
|
|
||||||
</li>:""
|
|
||||||
}
|
|
||||||
</ul>
|
</ul>
|
||||||
:
|
:
|
||||||
<Skeleton paragraph={false} active={true}/>
|
<Skeleton paragraph={false} active={true}/>
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Tooltip , message } from 'antd';
|
||||||
|
import './sub.scss';
|
||||||
|
|
||||||
|
function Invite({code,className}) {
|
||||||
|
|
||||||
|
function jsCopy(id) {
|
||||||
|
const copyEle = document.querySelector(id); // 获取要复制的节点
|
||||||
|
const range = document.createRange(); // 创造range
|
||||||
|
window.getSelection().removeAllRanges(); //清除页面中已有的selection
|
||||||
|
range.selectNode(copyEle); // 选中需要复制的节点
|
||||||
|
window.getSelection().addRange(range); // 执行选中元素
|
||||||
|
document.execCommand("Copy"); // 执行copy操作
|
||||||
|
message.success('复制成功');
|
||||||
|
}
|
||||||
|
return(
|
||||||
|
<div className={className}>
|
||||||
|
<span className="font-16 color-grey-6">邀请码</span>
|
||||||
|
<div>
|
||||||
|
<span id="devitecode">{code}</span>
|
||||||
|
<Tooltip title={<p className="edu-txt-center">可以通过邀请码邀请成员加入项目<br/>点击复制邀请码。</p>} placement={"bottom"}>
|
||||||
|
<i className="iconfont icon-fuzhi2 font-16 color-blue ml8" onClick={()=>jsCopy("#devitecode")}></i>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Invite;
|
|
@ -2,13 +2,13 @@ import React , { forwardRef, useEffect } from 'react';
|
||||||
import {Form , Modal , Input } from 'antd';
|
import {Form , Modal , Input } from 'antd';
|
||||||
import "./sub.scss";
|
import "./sub.scss";
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
function UpdateDescModal({form , visible , onCancel , onOk,desc,website}){
|
function UpdateDescModal({form , visible , onCancel , onOk,desc,website,lesson_url}){
|
||||||
const { getFieldDecorator, validateFields , setFieldsValue } = form;
|
const { getFieldDecorator, validateFields , setFieldsValue } = form;
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if(desc || website){
|
if(desc || website){
|
||||||
setFieldsValue({
|
setFieldsValue({
|
||||||
website,desc
|
website,desc,lesson_url
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},[desc,website])
|
},[desc,website])
|
||||||
|
@ -17,7 +17,7 @@ function UpdateDescModal({form , visible , onCancel , onOk,desc,website}){
|
||||||
validateFields((err,values)=>{
|
validateFields((err,values)=>{
|
||||||
if(!err){
|
if(!err){
|
||||||
onCancel();
|
onCancel();
|
||||||
onOk(values.desc,values.website)
|
onOk(values.desc,values.website,values.lesson_url)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -35,11 +35,11 @@ function UpdateDescModal({form , visible , onCancel , onOk,desc,website}){
|
||||||
className={"descmodal"}
|
className={"descmodal"}
|
||||||
>
|
>
|
||||||
<Form>
|
<Form>
|
||||||
<Form.Item label="仓库描述">
|
<Form.Item label="项目简介">
|
||||||
{getFieldDecorator("desc",{
|
{getFieldDecorator("desc",{
|
||||||
rules:[]
|
rules:[]
|
||||||
})(
|
})(
|
||||||
<TextArea placeholder="仓库描述" rows={4} maxLength={200}/>
|
<TextArea placeholder="请输入项目简介" rows={4} maxLength={200}/>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="website">
|
<Form.Item label="website">
|
||||||
|
@ -49,6 +49,13 @@ function UpdateDescModal({form , visible , onCancel , onOk,desc,website}){
|
||||||
<Input placeholder="website链接"/>
|
<Input placeholder="website链接"/>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item label="实践课程">
|
||||||
|
{getFieldDecorator("lesson_url",{
|
||||||
|
rules:[]
|
||||||
|
})(
|
||||||
|
<Input placeholder="实践课程链接"/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,3 +21,8 @@
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.detailsCode{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ function Commits({ commits , projectsId , owner }){
|
||||||
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(item.sha)}`} className="color-blue">浏览代码</Link>
|
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(item.sha)}`} className="color-blue">浏览代码</Link>
|
||||||
</FlexAJ>
|
</FlexAJ>
|
||||||
<AlignCenter className="mt15">
|
<AlignCenter className="mt15">
|
||||||
<User url={getImageUrl(`images/${item.committer && item.committer.image_url}`)} name={`${item.committer && item.committer.name}`}></User><span>:提交于{item.time_from_now}</span>
|
<User url={getImageUrl(`/${item.committer && item.committer.image_url}`)} name={`${item.committer && item.committer.name}`}></User><span>:提交于{item.time_from_now}</span>
|
||||||
</AlignCenter>
|
</AlignCenter>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
.i_open{
|
||||||
|
color: #28BD6C!important;
|
||||||
|
}
|
||||||
|
.i_merged{
|
||||||
|
color: #4C9ED3!important;
|
||||||
|
}
|
||||||
|
.i_closed{
|
||||||
|
color: #FA6400!important;
|
||||||
|
}
|
||||||
|
.pr_tags_open{
|
||||||
|
border:1px solid #28BD6C;
|
||||||
|
color: #28BD6C;
|
||||||
|
}
|
||||||
|
.pr_tags_merged{
|
||||||
|
border:1px solid #4C9ED3;
|
||||||
|
color: #4C9ED3;
|
||||||
|
}
|
||||||
|
.pr_tags_closed{
|
||||||
|
border:1px solid #FA6400;
|
||||||
|
color: #FA6400;
|
||||||
|
}
|
|
@ -1,9 +1,16 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { Popconfirm, Tag } from "antd";
|
import { Tag } from "antd";
|
||||||
|
import { AlignCenter } from '../Component/layout';
|
||||||
import { getImageUrl } from "educoder";
|
import { getImageUrl } from "educoder";
|
||||||
import "./merge.css";
|
import "./merge.css";
|
||||||
|
|
||||||
|
function turnbar(str){
|
||||||
|
if(str && str.length>0 && str.indexOf("/")>-1){
|
||||||
|
return str.replaceAll('/','%2F');
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
class MergeItem extends Component {
|
class MergeItem extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -42,16 +49,18 @@ class MergeItem extends Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { issues, project_name, project_author_name } = this.props;
|
const { issues, project_name, project_author_name , user_admin_or_member} = this.props;
|
||||||
const { projectsId , owner } = this.props.match.params;
|
const { projectsId , owner } = this.props.match.params;
|
||||||
const { current_user } = this.props;
|
const { current_user } = this.props;
|
||||||
const renderList = () => {
|
const renderList = () => {
|
||||||
if (issues && issues.length > 0) {
|
if (issues && issues.length > 0) {
|
||||||
return issues.map((item, key) => {
|
return issues.map((item, key) => {
|
||||||
|
let status = item.pull_request_staus;
|
||||||
return (
|
return (
|
||||||
<div className="issueItem">
|
<div className="issueItem">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<p className="mb15 df" style={{ alignItems: "center" }}>
|
<p className="mb15 df" style={{ alignItems: "center" }}>
|
||||||
|
<i className={`iconfont icon-hebingqingqiu1 font-14 mr3 i_${status}`}></i>
|
||||||
<Link
|
<Link
|
||||||
to={`/projects/${owner}/${projectsId}/pulls/${item.pull_request_id}/Messagecount`}
|
to={`/projects/${owner}/${projectsId}/pulls/${item.pull_request_id}/Messagecount`}
|
||||||
className="hide-1 font-15 color-grey-3 fwb lineh-30 mr10"
|
className="hide-1 font-15 color-grey-3 fwb lineh-30 mr10"
|
||||||
|
@ -59,10 +68,10 @@ class MergeItem extends Component {
|
||||||
>
|
>
|
||||||
{item.name}
|
{item.name}
|
||||||
</Link>
|
</Link>
|
||||||
<Tag className={`pr_tags_${item.pull_request_staus}`}>
|
<Tag className={`pr_tags_${status}`}>
|
||||||
{item.pull_request_staus === "merged"
|
{status === "merged"
|
||||||
? "已合并"
|
? "已合并"
|
||||||
: item.pull_request_staus === "closed"
|
: status === "closed"
|
||||||
? "已拒绝"
|
? "已拒绝"
|
||||||
: "开启的"}
|
: "开启的"}
|
||||||
</Tag>
|
</Tag>
|
||||||
|
@ -74,13 +83,13 @@ class MergeItem extends Component {
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
className="radius"
|
className="radius"
|
||||||
src={getImageUrl(`images/${item && item.avatar_url}`)}
|
src={getImageUrl(`/${item && item.avatar_url}`)}
|
||||||
alt=""
|
alt=""
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<span>
|
<AlignCenter>
|
||||||
<Link
|
<Link
|
||||||
to={`/users/${item && item.author_login}`}
|
to={`/users/${item && item.author_login}`}
|
||||||
className="show-user-link color-grey-8 ml5"
|
className="show-user-link color-grey-8 ml5"
|
||||||
|
@ -96,35 +105,45 @@ class MergeItem extends Component {
|
||||||
</span>
|
</span>
|
||||||
<span className="color-grey-8">{item.pr_time}</span>
|
<span className="color-grey-8">{item.pr_time}</span>
|
||||||
<span className="ml15">
|
<span className="ml15">
|
||||||
<Tag className="pr-branch-tag">
|
{
|
||||||
<Link
|
item.pull_request_head &&
|
||||||
to={`/projects/${item.is_original ? item.fork_project_user : owner}/${ item.is_original ? item.fork_project_identifier : projectsId }/tree/${item.pull_request_head}`}
|
<Tag className="pr-branch-tag">
|
||||||
className="maxW200px hide-1 ver-middle"
|
<Link
|
||||||
>
|
to={`/projects/${item.is_original ? item.fork_project_user : owner}/${ item.is_original ? item.fork_project_identifier : projectsId }/tree/${turnbar(item.pull_request_head)}`}
|
||||||
{item.is_original
|
className="maxW200px hide-1 ver-middle"
|
||||||
? item.fork_project_user
|
>
|
||||||
: project_author_name}
|
{item.is_original
|
||||||
:{item.pull_request_head}
|
? item.fork_project_user
|
||||||
</Link>
|
: project_author_name}
|
||||||
</Tag>
|
:{item.pull_request_head}
|
||||||
<span className="mr8 ver-middle">
|
</Link>
|
||||||
<i
|
</Tag>
|
||||||
className={
|
}
|
||||||
"iconfont icon-youjiang color-grey-c font-16"
|
{
|
||||||
}
|
item.pull_request_base &&
|
||||||
></i>
|
<span className="mr8 ver-middle">
|
||||||
</span>
|
<i
|
||||||
<Tag className="pr-branch-tag">
|
className={
|
||||||
<Link
|
"iconfont icon-youjiang color-grey-c font-16"
|
||||||
to={`/projects/${owner}/${projectsId}/tree/${item.pull_request_base}`}
|
}
|
||||||
className="maxW200px hide-1 ver-middle"
|
></i>
|
||||||
>
|
</span>
|
||||||
{/* {item.is_fork ? item.pull_request_base : `${item.author_name}:${item.pull_request_base}`} */}
|
}
|
||||||
{project_author_name}:{item.pull_request_base}
|
{
|
||||||
</Link>
|
item.pull_request_base &&
|
||||||
</Tag>
|
<Tag className="pr-branch-tag">
|
||||||
|
<Link
|
||||||
|
to={`/projects/${owner}/${projectsId}/tree/${turnbar(item.pull_request_base)}`}
|
||||||
|
className="maxW200px hide-1 ver-middle"
|
||||||
|
>
|
||||||
|
{/* {item.is_fork ? item.pull_request_base : `${item.author_name}:${item.pull_request_base}`} */}
|
||||||
|
{project_author_name}:{item.pull_request_base}
|
||||||
|
</Link>
|
||||||
|
</Tag>
|
||||||
|
}
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</AlignCenter>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
|
@ -164,7 +183,7 @@ class MergeItem extends Component {
|
||||||
) : (
|
) : (
|
||||||
""
|
""
|
||||||
)}
|
)}
|
||||||
{current_user && current_user.login ? (
|
{user_admin_or_member ? (
|
||||||
<div
|
<div
|
||||||
className="milepostleft"
|
className="milepostleft"
|
||||||
style={{
|
style={{
|
||||||
|
@ -177,7 +196,7 @@ class MergeItem extends Component {
|
||||||
>
|
>
|
||||||
<div className="grid-item mr15 color-grey-9">
|
<div className="grid-item mr15 color-grey-9">
|
||||||
<Link
|
<Link
|
||||||
to={`/projects/${owner}/${projectsId}/merge/${item.pull_request_id}/updatemerge`}
|
to={`/projects/${owner}/${projectsId}/pulls/${item.pull_request_id}/updatemerge`}
|
||||||
className="color-grey-9"
|
className="color-grey-9"
|
||||||
>
|
>
|
||||||
<i className="iconfont icon-bianji3 font-14 mr5"></i>
|
<i className="iconfont icon-bianji3 font-14 mr5"></i>
|
||||||
|
|
|
@ -101,7 +101,7 @@ class MergeSubmit extends Component{
|
||||||
render: (text,item) => (
|
render: (text,item) => (
|
||||||
<span className="f-wrap-alignCenter">
|
<span className="f-wrap-alignCenter">
|
||||||
<Link to={`/users/${item.login}`} className="show-user-link">
|
<Link to={`/users/${item.login}`} className="show-user-link">
|
||||||
<img src={getImageUrl(`images/${item.image_url}`)} alt="" width="28px" height="28px" className="mr3 radius"/>
|
<img src={getImageUrl(`/${item.image_url}`)} alt="" width="28px" height="28px" className="mr3 radius"/>
|
||||||
<label className="hide-1" style={{maxWidth:"75px",'vertical-align':'middle'}}>{text}</label>
|
<label className="hide-1" style={{maxWidth:"75px",'vertical-align':'middle'}}>{text}</label>
|
||||||
</Link>
|
</Link>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -24,6 +24,12 @@ import MergeFooter from "./merge_footer";
|
||||||
const Option = Select.Option;
|
const Option = Select.Option;
|
||||||
const TextArea = Input.TextArea;
|
const TextArea = Input.TextArea;
|
||||||
|
|
||||||
|
function turnbar(str){
|
||||||
|
if(str && str.length>0 && str.indexOf("/")>-1){
|
||||||
|
return str.replaceAll('/','%2F');
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
class MessageCount extends Component {
|
class MessageCount extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -41,6 +47,7 @@ class MessageCount extends Component {
|
||||||
edit_spin: false,
|
edit_spin: false,
|
||||||
pr_status: undefined,
|
pr_status: undefined,
|
||||||
pull_request:undefined,
|
pull_request:undefined,
|
||||||
|
conflict_files:[],
|
||||||
|
|
||||||
copyVisible:false,
|
copyVisible:false,
|
||||||
};
|
};
|
||||||
|
@ -75,7 +82,8 @@ class MessageCount extends Component {
|
||||||
data: result.data,
|
data: result.data,
|
||||||
SpinFlag: false,
|
SpinFlag: false,
|
||||||
pr_status: result.data.pull_request && result.data.pull_request.status,
|
pr_status: result.data.pull_request && result.data.pull_request.status,
|
||||||
pull_request:result.data.pull_request
|
pull_request:result.data.pull_request,
|
||||||
|
conflict_files:result.data.conflict_files
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.setState({ SpinFlag: false });
|
this.setState({ SpinFlag: false });
|
||||||
|
@ -102,6 +110,8 @@ class MessageCount extends Component {
|
||||||
isSpin: false,
|
isSpin: false,
|
||||||
pr_status: 2,
|
pr_status: 2,
|
||||||
});
|
});
|
||||||
|
const { getDetail } = this.props;
|
||||||
|
getDetail && getDetail();
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
isSpin: false,
|
isSpin: false,
|
||||||
|
@ -138,6 +148,8 @@ class MessageCount extends Component {
|
||||||
SpinMerge: false,
|
SpinMerge: false,
|
||||||
pr_status: 1,
|
pr_status: 1,
|
||||||
});
|
});
|
||||||
|
const { getDetail } = this.props;
|
||||||
|
getDetail && getDetail();
|
||||||
} else {
|
} else {
|
||||||
this.setState({ SpinMerge: false });
|
this.setState({ SpinMerge: false });
|
||||||
}
|
}
|
||||||
|
@ -241,6 +253,49 @@ class MessageCount extends Component {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 点击按钮复制功能
|
||||||
|
jsCopy = () => {
|
||||||
|
const copyEle = document.querySelector('#descContent') // 获取要复制的节点
|
||||||
|
const range = document.createRange(); // 创造range
|
||||||
|
window.getSelection().removeAllRanges(); //清除页面中已有的selection
|
||||||
|
range.selectNode(copyEle); // 选中需要复制的节点
|
||||||
|
window.getSelection().addRange(range); // 执行选中元素
|
||||||
|
document.execCommand("Copy"); // 执行copy操作
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeabledMes=()=>{
|
||||||
|
return(
|
||||||
|
<div className="clearfix">
|
||||||
|
<p className="fl">该分支存在冲突,无法自动合并,你可以尝试通过如下命令手动合并</p>
|
||||||
|
<i className="iconfont icon-fuzhi font-16 fr" onClick={()=>this.jsCopy()}></i>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
mergeabledDesc=(base,head,conflict_files)=>{
|
||||||
|
return(
|
||||||
|
<div>
|
||||||
|
<ul id="descContent">
|
||||||
|
<li>git fetch origin</li>
|
||||||
|
<li>git checkout -b {`${base}`} origin/{`${base}`}</li>
|
||||||
|
<li>git merge {`${head}`}</li>
|
||||||
|
</ul>
|
||||||
|
{
|
||||||
|
conflict_files && conflict_files.length>0 &&
|
||||||
|
<div>
|
||||||
|
<p className="mt10 font-16 pt10" style={{borderTop:"1px solid #f9d7d5"}}>如下文件有代码冲突:</p>
|
||||||
|
<p>
|
||||||
|
{
|
||||||
|
conflict_files.map((i,k)=>{
|
||||||
|
return <p>{i}</p>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { projectsId, mergeId , owner } = this.props.match.params;
|
const { projectsId, mergeId , owner } = this.props.match.params;
|
||||||
|
|
||||||
|
@ -252,7 +307,8 @@ class MessageCount extends Component {
|
||||||
ismesrge,
|
ismesrge,
|
||||||
SpinFlag,
|
SpinFlag,
|
||||||
copyVisible,
|
copyVisible,
|
||||||
pull_request
|
pull_request,
|
||||||
|
conflict_files
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const { current_user, projectDetail } = this.props;
|
const { current_user, projectDetail } = this.props;
|
||||||
const menu = (
|
const menu = (
|
||||||
|
@ -305,10 +361,10 @@ class MessageCount extends Component {
|
||||||
<div className="mt15">
|
<div className="mt15">
|
||||||
<Tag className="pr-branch-tag">
|
<Tag className="pr-branch-tag">
|
||||||
<Link
|
<Link
|
||||||
to={`/projects/${owner}/${data.pull_request.is_original?data.project_identifier:projectsId}/tree/${data.pull_request.head}`}
|
to={`/projects/${data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}/${data.pull_request.is_original?data.project_identifier:projectsId}/tree/${turnbar(data.pull_request && data.pull_request.head)}`}
|
||||||
className="ver-middle"
|
className="ver-middle"
|
||||||
>
|
>
|
||||||
{data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}:{data.pull_request.head}
|
{data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}: {turnbar(data.pull_request && data.pull_request.head)}
|
||||||
</Link>
|
</Link>
|
||||||
</Tag>
|
</Tag>
|
||||||
<span className="mr8 ver-middle">
|
<span className="mr8 ver-middle">
|
||||||
|
@ -323,7 +379,6 @@ class MessageCount extends Component {
|
||||||
to={`/projects/${owner}/${projectsId}/tree/${data.pull_request.base}`}
|
to={`/projects/${owner}/${projectsId}/tree/${data.pull_request.base}`}
|
||||||
className="ver-middle"
|
className="ver-middle"
|
||||||
>
|
>
|
||||||
{/* {data.pull_request.is_fork ? data.pull_request.base : `${data.pull_request.pull_request_user}:${data.pull_request.base}`} */}
|
|
||||||
{data.issue.project_author_name}:{data.pull_request.base}
|
{data.issue.project_author_name}:{data.pull_request.base}
|
||||||
</Link>
|
</Link>
|
||||||
</Tag>
|
</Tag>
|
||||||
|
@ -331,26 +386,14 @@ class MessageCount extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
<div className="mt15">
|
<div className="mt15">
|
||||||
<Link
|
<Link to={`/users/${data.issue.author_login}`} className="show-user-link">
|
||||||
to={`/users/${data.issue.author_login}`}
|
<img className="mr5" src={getImageUrl(`/${data.issue.author_picture}`)}
|
||||||
className="show-user-link"
|
alt="" width="24" height="24" style={{borderRadius:"50%"}}
|
||||||
>
|
|
||||||
<img
|
|
||||||
className="mr5"
|
|
||||||
src={getImageUrl(
|
|
||||||
`images/${data.issue.author_picture}`
|
|
||||||
)}
|
|
||||||
alt=""
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<span className="ver-middle">
|
<span className="ver-middle">
|
||||||
<span className="color-grey-8 mr5">由</span>
|
<span className="color-grey-8 mr5">由</span>
|
||||||
<Link
|
<Link to={`/users/${data.issue.author_login}`} className="show-user-link color-blue">
|
||||||
to={`/users/${data.issue.author_login}`}
|
|
||||||
className="show-user-link color-blue"
|
|
||||||
>
|
|
||||||
{data.issue.author_name}
|
{data.issue.author_name}
|
||||||
</Link>
|
</Link>
|
||||||
<span className="ml5 color-grey-8">
|
<span className="ml5 color-grey-8">
|
||||||
|
@ -400,12 +443,6 @@ class MessageCount extends Component {
|
||||||
</div>
|
</div>
|
||||||
<div className="ml10">
|
<div className="ml10">
|
||||||
<div className="mt15 text-right" style={{display:"flex",justifyContent:"flex-end"}}>
|
<div className="mt15 text-right" style={{display:"flex",justifyContent:"flex-end"}}>
|
||||||
{/* <span className="composeButton">
|
|
||||||
<Dropdown overlay={this.copyItem()} visible={copyVisible} onClick={(e)=>this.setCopyVisible(e)}>
|
|
||||||
<span>复制</span>
|
|
||||||
</Dropdown>
|
|
||||||
<span>下载为<i className="iconfont icon-sanjiaoxing-down color-blue"></i></span>
|
|
||||||
</span> */}
|
|
||||||
{operate && (
|
{operate && (
|
||||||
<Button
|
<Button
|
||||||
type="green"
|
type="green"
|
||||||
|
@ -452,35 +489,40 @@ class MessageCount extends Component {
|
||||||
type="success"
|
type="success"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{pr_status === 0 && projectDetail && projectDetail.permission !=="Reporter" && (
|
{operate && (
|
||||||
<Spin spinning={SpinFlag}>
|
<Spin spinning={SpinFlag}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display:
|
display:
|
||||||
this.state.mergekey === "rebase"
|
this.state.mergekey === "rebase"
|
||||||
? this.state.buttonshow === "none"
|
? this.state.buttonshow === "none" ? "block" : "none"
|
||||||
? "block"
|
: !ismesrge ? "block" : "none",
|
||||||
: "none"
|
|
||||||
: !ismesrge
|
|
||||||
? "block"
|
|
||||||
: "none",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p className="mb15">
|
<Dropdown.Button
|
||||||
<Dropdown.Button
|
overlay={menu}
|
||||||
overlay={menu}
|
type="primary"
|
||||||
type="primary"
|
onClick={this.submitmerge}
|
||||||
onClick={this.submitmerge}
|
className="mb15"
|
||||||
icon={<Icon type="caret-down" />}
|
icon={<Icon type="caret-down" />}
|
||||||
>
|
disabled={!pull_request || (pull_request && !pull_request.mergeable) }
|
||||||
{this.state.mergename}
|
>
|
||||||
</Dropdown.Button>
|
{this.state.mergename}
|
||||||
</p>
|
</Dropdown.Button>
|
||||||
<Alert
|
{pull_request && pull_request.mergeable
|
||||||
message="该合并请求可以进行自动合并操作"
|
?
|
||||||
type="success"
|
<Alert
|
||||||
showIcon
|
message="该合并请求可以进行自动合并操作"
|
||||||
/>
|
type="success"
|
||||||
|
showIcon
|
||||||
|
/>:
|
||||||
|
<Alert
|
||||||
|
message={this.mergeabledMes()}
|
||||||
|
type="error"
|
||||||
|
description={this.mergeabledDesc(pull_request.base,pull_request.head,conflict_files)}
|
||||||
|
showIcon
|
||||||
|
/>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -9,13 +9,14 @@ const Option = Select.Option;
|
||||||
class NewMerge extends Component {
|
class NewMerge extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
const { branch } = this.props.match.params;
|
||||||
this.state = {
|
this.state = {
|
||||||
data: undefined,
|
data: undefined,
|
||||||
branches: undefined,
|
branches: undefined,
|
||||||
merge_branches: undefined,
|
merge_branches: undefined,
|
||||||
merge_projects: undefined,
|
merge_projects: undefined,
|
||||||
merge: "master",
|
merge: "master",
|
||||||
pull: "master",
|
pull: branch,
|
||||||
id: undefined,
|
id: undefined,
|
||||||
is_fork: false,
|
is_fork: false,
|
||||||
projects_names: undefined,
|
projects_names: undefined,
|
||||||
|
@ -104,6 +105,18 @@ class NewMerge extends Component {
|
||||||
}
|
}
|
||||||
axios.get(url).then(result=>{
|
axios.get(url).then(result=>{
|
||||||
if(result){
|
if(result){
|
||||||
|
if (result.data.status === 0) {
|
||||||
|
this.setState({
|
||||||
|
isSpin: false,
|
||||||
|
show_message: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
isSpin: false,
|
||||||
|
show_message: true,
|
||||||
|
default_message: result.data.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
comparesData:result.data
|
comparesData:result.data
|
||||||
})
|
})
|
||||||
|
@ -113,16 +126,19 @@ class NewMerge extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
set_default_pull = (branches) => {
|
set_default_pull = (branches) => {
|
||||||
if(branches && branches.length>0){
|
const { branch } = this.props.match.params;
|
||||||
let default_pull = branches.filter((e) => e.name === "master")
|
if(!branch){
|
||||||
if (default_pull.length > 0){
|
if(branches && branches.length>0){
|
||||||
this.setState({
|
let default_pull = branches.filter((e) => e.name === "master")
|
||||||
pull:default_pull[0].name
|
if (default_pull.length > 0){
|
||||||
})
|
this.setState({
|
||||||
}else{
|
pull:default_pull[0].name
|
||||||
this.setState({
|
})
|
||||||
pull:"master"
|
}else{
|
||||||
})
|
this.setState({
|
||||||
|
pull:"master"
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,7 +155,7 @@ class NewMerge extends Component {
|
||||||
merge:"master"
|
merge:"master"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.ischeckmerge();
|
// this.ischeckmerge();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,10 +179,12 @@ class NewMerge extends Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
selectBrach = (type, value) => {
|
selectBrach = (type, value) => {
|
||||||
|
const { projectsId , owner } = this.props.match.params;
|
||||||
this.state[type] = value;
|
this.state[type] = value;
|
||||||
this.ischeckmerge();
|
// this.ischeckmerge();
|
||||||
let { id ,merge , pull } = this.state;
|
let { id ,merge , pull } = this.state;
|
||||||
if(type==="pull"){
|
if(type==="pull"){
|
||||||
|
this.props.history.push(`/projects/${owner}/${projectsId}/pulls/new/${pull}`)
|
||||||
this.compareProject(id,value,merge);
|
this.compareProject(id,value,merge);
|
||||||
}else{
|
}else{
|
||||||
this.compareProject(id,pull,value);
|
this.compareProject(id,pull,value);
|
||||||
|
@ -178,7 +196,7 @@ class NewMerge extends Component {
|
||||||
let arr = projects_names && projects_names.filter(item=>item.id===value);
|
let arr = projects_names && projects_names.filter(item=>item.id===value);
|
||||||
let identifier = arr && arr[0].project_id;
|
let identifier = arr && arr[0].project_id;
|
||||||
let login = arr && arr[0].project_user_login;
|
let login = arr && arr[0].project_user_login;
|
||||||
let is_fork_id = parseInt(value) !== parseInt(id)
|
let is_fork_id = parseInt(value) !== parseInt(id);
|
||||||
this.setState({
|
this.setState({
|
||||||
isSpin: true,
|
isSpin: true,
|
||||||
merge_head: is_fork_id,
|
merge_head: is_fork_id,
|
||||||
|
@ -193,7 +211,6 @@ class NewMerge extends Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
//判断2分支是否可以合并
|
//判断2分支是否可以合并
|
||||||
|
|
||||||
ischeckmerge = () => {
|
ischeckmerge = () => {
|
||||||
this.setState({ isSpin: true });
|
this.setState({ isSpin: true });
|
||||||
const { projectsId , owner } = this.props.match.params;
|
const { projectsId , owner } = this.props.match.params;
|
||||||
|
|
|
@ -168,6 +168,7 @@ form .ant-cascader-picker, form .ant-select {
|
||||||
}
|
}
|
||||||
.linesContent > p{
|
.linesContent > p{
|
||||||
flex:1;
|
flex:1;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
.linesContent .lines{
|
.linesContent .lines{
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -5,6 +5,7 @@ import "../Order/order.css";
|
||||||
import "../Order/index.scss";
|
import "../Order/index.scss";
|
||||||
import NoneData from "./no_data";
|
import NoneData from "./no_data";
|
||||||
import OrderItem from "./MergeItem";
|
import OrderItem from "./MergeItem";
|
||||||
|
import './Index.scss';
|
||||||
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ class merge extends Component {
|
||||||
// page: 1,
|
// page: 1,
|
||||||
search_count: undefined,
|
search_count: undefined,
|
||||||
issue_type: undefined,
|
issue_type: undefined,
|
||||||
status_type: undefined,
|
status_type: "1",
|
||||||
//设置选择高亮
|
//设置选择高亮
|
||||||
openselect: 1,
|
openselect: 1,
|
||||||
closeselect: undefined,
|
closeselect: undefined,
|
||||||
|
@ -47,7 +48,7 @@ class merge extends Component {
|
||||||
paix: "排序",
|
paix: "排序",
|
||||||
priority_ids: "优先级",
|
priority_ids: "优先级",
|
||||||
select_params: {
|
select_params: {
|
||||||
status_type: undefined, //开启中和关闭中,默认为开启中的
|
status_type: "1", //开启中和关闭中,默认为开启中的
|
||||||
assigned_to_id: undefined, // 指派人
|
assigned_to_id: undefined, // 指派人
|
||||||
fixed_version_id: undefined,
|
fixed_version_id: undefined,
|
||||||
priority_id: undefined,
|
priority_id: undefined,
|
||||||
|
@ -154,7 +155,7 @@ class merge extends Component {
|
||||||
|
|
||||||
renderMenu = (array, name, id) => {
|
renderMenu = (array, name, id) => {
|
||||||
return (
|
return (
|
||||||
<Menu>
|
<Menu className="orderCondition">
|
||||||
<Menu.Item key={"all"} onClick={(e) => this.getOption(e, id, name)}>
|
<Menu.Item key={"all"} onClick={(e) => this.getOption(e, id, name)}>
|
||||||
{name}
|
{name}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
@ -206,23 +207,16 @@ class merge extends Component {
|
||||||
paix: "排序",
|
paix: "排序",
|
||||||
priority_ids: "优先级",
|
priority_ids: "优先级",
|
||||||
});
|
});
|
||||||
this.state.select_params = {
|
this.state.select_params.status_type = type;
|
||||||
status_type: type,
|
this.state.select_params.page=1;
|
||||||
search: undefined,
|
this.state.select_params.limit=15;
|
||||||
page: 1,
|
|
||||||
limit: 15,
|
|
||||||
};
|
|
||||||
this.getIssueList();
|
this.getIssueList();
|
||||||
};
|
};
|
||||||
|
|
||||||
islogin() {
|
checkOperation() {
|
||||||
const { projectsId,owner } = this.props.match.params;
|
const { projectsId,owner } = this.props.match.params;
|
||||||
if (this.props.checkIfLogin() === false) {
|
this.props.history.push(`/projects/${owner}/${projectsId}/pulls/new`);
|
||||||
this.props.showLoginDialog();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
this.props.history.push(`/projects/${owner}/${projectsId}/pulls/new`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
const { projectsId , owner } = this.props.match.params;
|
const { projectsId , owner } = this.props.match.params;
|
||||||
|
@ -253,24 +247,6 @@ class merge extends Component {
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
|
||||||
const Paginations = (
|
|
||||||
<React.Fragment>
|
|
||||||
{search_count > limit ? (
|
|
||||||
<div className="mt30 mb50 edu-txt-center">
|
|
||||||
<Pagination
|
|
||||||
simple
|
|
||||||
defaultCurrent={page}
|
|
||||||
total={search_count}
|
|
||||||
pageSize={limit}
|
|
||||||
onChange={this.ChangePage}
|
|
||||||
></Pagination>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
""
|
|
||||||
)}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<div className="main" style={{padding:"0px"}}>
|
<div className="main" style={{padding:"0px"}}>
|
||||||
<div className="topWrapper" style={{borderBottom:"none",padding:"20px"}}>
|
<div className="topWrapper" style={{borderBottom:"none",padding:"20px"}}>
|
||||||
|
@ -282,9 +258,12 @@ class merge extends Component {
|
||||||
style={{ width: 300 }}
|
style={{ width: 300 }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<a className="topWrapper_btn ml10" onClick={() => this.islogin()}>
|
{
|
||||||
+ 新建合并请求
|
data && data.user_admin_or_member &&
|
||||||
</a>
|
<a className="topWrapper_btn ml10" onClick={() => this.checkOperation()}>
|
||||||
|
+ 新建合并请求
|
||||||
|
</a>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className="f-wrap-between screenWrap">
|
<div className="f-wrap-between screenWrap">
|
||||||
<div className="df">
|
<div className="df">
|
||||||
|
@ -300,6 +279,7 @@ class merge extends Component {
|
||||||
className={status_type === "1" ? "active" : ""}
|
className={status_type === "1" ? "active" : ""}
|
||||||
onClick={() => this.openorder("1")}
|
onClick={() => this.openorder("1")}
|
||||||
>
|
>
|
||||||
|
<i className="iconfont icon-hebingqingqiu1 font-14 mr3 i_open"></i>
|
||||||
<label>开启的</label>
|
<label>开启的</label>
|
||||||
<span>{data && data.open_count}</span>
|
<span>{data && data.open_count}</span>
|
||||||
</li>
|
</li>
|
||||||
|
@ -307,6 +287,7 @@ class merge extends Component {
|
||||||
className={status_type === "11" ? "active" : ""}
|
className={status_type === "11" ? "active" : ""}
|
||||||
onClick={() => this.openorder("11")}
|
onClick={() => this.openorder("11")}
|
||||||
>
|
>
|
||||||
|
<i className="iconfont icon-hebingqingqiu1 font-14 mr3 i_merged"></i>
|
||||||
<label>已合并</label>
|
<label>已合并</label>
|
||||||
<span>{data && data.merged_issues_size}</span>
|
<span>{data && data.merged_issues_size}</span>
|
||||||
</li>
|
</li>
|
||||||
|
@ -314,6 +295,7 @@ class merge extends Component {
|
||||||
className={status_type === "2" ? "active" : ""}
|
className={status_type === "2" ? "active" : ""}
|
||||||
onClick={() => this.openorder("2")}
|
onClick={() => this.openorder("2")}
|
||||||
>
|
>
|
||||||
|
<i className="iconfont icon-hebingqingqiu1 font-14 mr3 i_closed"></i>
|
||||||
<label>已拒绝</label>
|
<label>已拒绝</label>
|
||||||
<span>{data && data.close_count}</span>
|
<span>{data && data.close_count}</span>
|
||||||
</li>
|
</li>
|
||||||
|
@ -418,10 +400,23 @@ class merge extends Component {
|
||||||
project_author_name={data.project_author_name}
|
project_author_name={data.project_author_name}
|
||||||
{...this.props}
|
{...this.props}
|
||||||
{...this.state}
|
{...this.state}
|
||||||
|
user_admin_or_member={data && data.user_admin_or_member}
|
||||||
></OrderItem>
|
></OrderItem>
|
||||||
{Paginations}
|
|
||||||
</div>
|
</div>
|
||||||
):""}
|
):""}
|
||||||
|
{search_count > select_params.limit ? (
|
||||||
|
<div className="mt30 mb50 edu-txt-center">
|
||||||
|
<Pagination
|
||||||
|
simple
|
||||||
|
current={select_params.page}
|
||||||
|
total={search_count}
|
||||||
|
pageSize={select_params.limit}
|
||||||
|
onChange={this.ChangePage}
|
||||||
|
></Pagination>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
{ data && data.issues && data.issues.length === 0 ? <NoneData _html="暂时还没有相关数据!" projectsId={projectsId} owner={owner} /> :""}
|
{ data && data.issues && data.issues.length === 0 ? <NoneData _html="暂时还没有相关数据!" projectsId={projectsId} owner={owner} /> :""}
|
||||||
</Spin>
|
</Spin>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -34,17 +34,19 @@ class MergeForm extends Component {
|
||||||
this.set_defatul();
|
this.set_defatul();
|
||||||
};
|
};
|
||||||
componentDidUpdate=(prevPros)=>{
|
componentDidUpdate=(prevPros)=>{
|
||||||
|
const { projectsId ,owner } = this.props.match.params;
|
||||||
|
const pId = prevPros.match.params.projectsId;
|
||||||
|
const oId = prevPros.match.params.owner;
|
||||||
|
if(pId !== projectsId || oId !== owner ){
|
||||||
|
// console.log("切换了项目分支···········");
|
||||||
|
this.get_default_selects();
|
||||||
|
}
|
||||||
if(prevPros && this.props && !this.props.checkIfLogin()){
|
if(prevPros && this.props && !this.props.checkIfLogin()){
|
||||||
this.props.history.push("/403")
|
this.props.history.push("/403")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check_is_login =() =>{
|
|
||||||
// if(!this.props.checkIfLogin()){
|
|
||||||
// this.props.history.push("/403")
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
get_default_selects = () => {
|
get_default_selects = () => {
|
||||||
const { projectsId ,owner } = this.props.match.params;
|
const { projectsId ,owner } = this.props.match.params;
|
||||||
this.setState({ isSpin: true });
|
this.setState({ isSpin: true });
|
||||||
|
|
|
@ -43,7 +43,8 @@ class Index extends Component {
|
||||||
project_language_name: undefined,
|
project_language_name: undefined,
|
||||||
project_category_name: undefined,
|
project_category_name: undefined,
|
||||||
license_name: undefined,
|
license_name: undefined,
|
||||||
ignore_name: undefined
|
ignore_name: undefined,
|
||||||
|
descNum:0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
componentDidMount = () => {
|
componentDidMount = () => {
|
||||||
|
@ -67,24 +68,30 @@ class Index extends Component {
|
||||||
|
|
||||||
getOwner=()=>{
|
getOwner=()=>{
|
||||||
const { OIdentifier } = this.props.match.params;
|
const { OIdentifier } = this.props.match.params;
|
||||||
|
const { user_id } = this.props && this.props.current_user;
|
||||||
const url = `/owners.json`;
|
const url = `/owners.json`;
|
||||||
axios.get(url).then(result=>{
|
axios.get(url).then(result=>{
|
||||||
if(result && result.data){
|
if(result && result.data){
|
||||||
let owner = result.data.owners;
|
let owner = result.data.owners;
|
||||||
|
this.setState({
|
||||||
|
OwnerList: owner,
|
||||||
|
})
|
||||||
if(OIdentifier){
|
if(OIdentifier){
|
||||||
owner = owner.filter(item=>item.name === OIdentifier);
|
owner = owner.filter(item=>item.name === OIdentifier);
|
||||||
this.props.form.setFieldsValue({
|
this.props.form.setFieldsValue({
|
||||||
user_id:OIdentifier
|
user_id:OIdentifier
|
||||||
})
|
})
|
||||||
owner && this.setState({
|
}else if(user_id){
|
||||||
owners_id:owner[0].id,
|
owner = owner.filter(item=>item.id === user_id);
|
||||||
owners_name:owner[0].name
|
this.props.form.setFieldsValue({
|
||||||
|
user_id:owner && owner[0].name
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.setOptionsList(owner, 'owners');
|
owner && this.setState({
|
||||||
this.setState({
|
owners_id:owner[0].id,
|
||||||
OwnerList: owner,
|
owners_name:owner[0].name
|
||||||
})
|
})
|
||||||
|
this.setOptionsList(owner, 'owners');
|
||||||
}
|
}
|
||||||
}).catch(error=>{})
|
}).catch(error=>{})
|
||||||
}
|
}
|
||||||
|
@ -180,7 +187,7 @@ class Index extends Component {
|
||||||
isSpin: false
|
isSpin: false
|
||||||
})
|
})
|
||||||
this.props.showNotification(`${projectsType && projectsType === "mirror" ? "镜像" : "托管"}项目创建成功!`);
|
this.props.showNotification(`${projectsType && projectsType === "mirror" ? "镜像" : "托管"}项目创建成功!`);
|
||||||
this.props.history.push(`/projects/${owners_name}/${result.data.identifier}`);
|
this.props.history.push(`/projects/${result.data.login}/${result.data.identifier}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
|
@ -254,6 +261,13 @@ class Index extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeDesc=(e)=>{
|
||||||
|
let value = e.target.value;
|
||||||
|
this.setState({
|
||||||
|
descNum:value ? value.length :0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { getFieldDecorator } = this.props.form;
|
const { getFieldDecorator } = this.props.form;
|
||||||
// 项目类型:deposit-托管项目,mirror-镜像项目
|
// 项目类型:deposit-托管项目,mirror-镜像项目
|
||||||
|
@ -273,7 +287,9 @@ class Index extends Component {
|
||||||
license_list,
|
license_list,
|
||||||
ignore_list,
|
ignore_list,
|
||||||
|
|
||||||
mirrorCheck
|
mirrorCheck,
|
||||||
|
|
||||||
|
descNum
|
||||||
} = this.state;
|
} = this.state;
|
||||||
return (
|
return (
|
||||||
<div className="main back-white" style={{padding:"0px",border:"none"}}>
|
<div className="main back-white" style={{padding:"0px",border:"none"}}>
|
||||||
|
@ -361,21 +377,23 @@ class Index extends Component {
|
||||||
required: true, message: '请填写项目名称'
|
required: true, message: '请填写项目名称'
|
||||||
}],
|
}],
|
||||||
})(
|
})(
|
||||||
<Input placeholder="例如:团队协作方法与研究" />
|
<Input placeholder="例如:团队协作方法与研究" maxLength={50}/>
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label="项目简介"
|
|
||||||
>
|
|
||||||
{getFieldDecorator('description', {
|
|
||||||
rules: [{
|
|
||||||
required: true, message: '请填写项目简介'
|
|
||||||
}],
|
|
||||||
})(
|
|
||||||
<Input.TextArea placeholder="项目的介绍" autoSize={{ minRows: 2, maxRows: 6 }} />
|
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<div className="pr">
|
||||||
|
<span className="toprightNum">{descNum}/200</span>
|
||||||
|
<Form.Item
|
||||||
|
label="项目简介"
|
||||||
|
>
|
||||||
|
{getFieldDecorator('description', {
|
||||||
|
rules: [{
|
||||||
|
required: true, message: '请填写项目简介'
|
||||||
|
}],
|
||||||
|
})(
|
||||||
|
<Input.TextArea maxLength={200} placeholder="项目的介绍" autoSize={{ minRows: 2, maxRows: 6 }} onChange={this.changeDesc}/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="仓库名称"
|
label="仓库名称"
|
||||||
>
|
>
|
||||||
|
@ -384,7 +402,7 @@ class Index extends Component {
|
||||||
required: true, message: '请填写仓库名称'
|
required: true, message: '请填写仓库名称'
|
||||||
}],
|
}],
|
||||||
})(
|
})(
|
||||||
<Input placeholder="仓库名称请使用与项目相关的英文关键字" />
|
<Input placeholder="仓库名称请使用与项目相关的英文关键字" maxLength={100} />
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
|
|
|
@ -73,6 +73,7 @@ class Index extends Component {
|
||||||
content={undefined}
|
content={undefined}
|
||||||
readOnly={false}
|
readOnly={false}
|
||||||
editorType="new"
|
editorType="new"
|
||||||
|
descName={filename && `Add ${filename}`}
|
||||||
></Meditor>
|
></Meditor>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,6 +6,20 @@ import "./index.css";
|
||||||
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
const TextArea = Input.TextArea;
|
const TextArea = Input.TextArea;
|
||||||
|
|
||||||
|
|
||||||
|
function turnbar(str){
|
||||||
|
if(str && str.length>0 && str.indexOf("/")>-1){
|
||||||
|
return str.replaceAll('/','%2F');
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
function returnbar(str){
|
||||||
|
if(str && str.length>0 && str.indexOf("%2F")>-1){
|
||||||
|
return str.replaceAll('%2F','/');
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
class UserSubmitComponent extends Component {
|
class UserSubmitComponent extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -16,6 +30,24 @@ class UserSubmitComponent extends Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount=()=>{
|
||||||
|
const { descName } = this.props;
|
||||||
|
if(descName){
|
||||||
|
this.props.form.setFieldsValue({
|
||||||
|
desc:descName
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate=(preProps)=>{
|
||||||
|
const { descName } = this.props;
|
||||||
|
if(preProps && descName && preProps.descName !== descName ){
|
||||||
|
this.props.form.setFieldsValue({
|
||||||
|
desc:descName
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
changeSubmittype = (e) => {
|
changeSubmittype = (e) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
submitType: e.target.value,
|
submitType: e.target.value,
|
||||||
|
@ -41,7 +73,7 @@ class UserSubmitComponent extends Component {
|
||||||
const url = `/${owner}/${projectsId}/create_file.json`;
|
const url = `/${owner}/${projectsId}/create_file.json`;
|
||||||
axios.post(url, {
|
axios.post(url, {
|
||||||
filepath: filename ? filename : path,
|
filepath: filename ? filename : path,
|
||||||
branch: branch,
|
branch: returnbar(branch),
|
||||||
new_branch: submitType === "1" ? values.branchname : undefined,
|
new_branch: submitType === "1" ? values.branchname : undefined,
|
||||||
content,
|
content,
|
||||||
message: values.desc,
|
message: values.desc,
|
||||||
|
@ -54,7 +86,7 @@ class UserSubmitComponent extends Component {
|
||||||
const { getTopCount } = this.props;
|
const { getTopCount } = this.props;
|
||||||
getTopCount && getTopCount(values.branchname);
|
getTopCount && getTopCount(values.branchname);
|
||||||
}
|
}
|
||||||
let url = `/projects/${owner}/${projectsId}${values.branchname ? `/tree/${values.branchname}`: (branch ? `/tree/${branch}` : "")}`;
|
let url = `/projects/${owner}/${projectsId}${values.branchname ? `/tree/${turnbar(values.branchname)}`: (branch ? `/tree/${turnbar(branch)}` : "")}`;
|
||||||
this.props.history.push(url);
|
this.props.history.push(url);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -75,12 +107,13 @@ class UserSubmitComponent extends Component {
|
||||||
const { projectsId , owner } = this.props.match.params;
|
const { projectsId , owner } = this.props.match.params;
|
||||||
const { submitType } = this.state;
|
const { submitType } = this.state;
|
||||||
const url = `/${owner}/${projectsId}/update_file.json`;
|
const url = `/${owner}/${projectsId}/update_file.json`;
|
||||||
|
let b = currentBranch || branch;
|
||||||
this.props.form.validateFieldsAndScroll((err, values) => {
|
this.props.form.validateFieldsAndScroll((err, values) => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
axios
|
axios
|
||||||
.put(url, {
|
.put(url, {
|
||||||
filepath: detail.path,
|
filepath: detail.path,
|
||||||
branch: submitType === "1" ? undefined : (currentBranch || branch),
|
branch: submitType === "1" ? undefined : returnbar(b),
|
||||||
new_branch: submitType === "1" ? values.branchname : undefined,
|
new_branch: submitType === "1" ? values.branchname : undefined,
|
||||||
content: content,
|
content: content,
|
||||||
sha: detail.sha,
|
sha: detail.sha,
|
||||||
|
@ -89,7 +122,8 @@ class UserSubmitComponent extends Component {
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.setState({ isSpin: false });
|
this.setState({ isSpin: false });
|
||||||
if (result.data && result.data.status === 1) {
|
if (result.data && result.data.status === 1) {
|
||||||
let url = `/projects/${owner}/${projectsId}${(values.branchname ? `/tree/${values.branchname}` : ((currentBranch || branch) ? `/tree/${currentBranch || branch}`:""))}`;
|
let b = currentBranch || branch;
|
||||||
|
let url = `/projects/${owner}/${projectsId}${(values.branchname ? `/tree/${turnbar(values.branchname)}` : (b ? `/tree/${turnbar(b)}`:""))}`;
|
||||||
this.props.history.push(url);
|
this.props.history.push(url);
|
||||||
this.props.showNotification("文件修改成功!");
|
this.props.showNotification("文件修改成功!");
|
||||||
}
|
}
|
||||||
|
@ -112,12 +146,13 @@ class UserSubmitComponent extends Component {
|
||||||
|
|
||||||
const { current_user, filepath, projectDetail , currentBranch } = this.props;
|
const { current_user, filepath, projectDetail , currentBranch } = this.props;
|
||||||
const { editor_type } = this.props;
|
const { editor_type } = this.props;
|
||||||
|
let b = currentBranch || branch;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<span className="df" style={{ alignItems: "center" }}>
|
<span className="df" style={{ alignItems: "center" }}>
|
||||||
<Link to={`/users/${current_user && current_user.login}`} className="show-user-link" >
|
<Link to={`/users/${current_user && current_user.login}`} className="show-user-link" >
|
||||||
<img
|
<img
|
||||||
src={getImageUrl(`images/${current_user && current_user.image_url}`)}
|
src={getImageUrl(`/${current_user && current_user.image_url}`)}
|
||||||
alt=""
|
alt=""
|
||||||
className="screwImg"
|
className="screwImg"
|
||||||
/>
|
/>
|
||||||
|
@ -170,7 +205,7 @@ class UserSubmitComponent extends Component {
|
||||||
>
|
>
|
||||||
<Radio value="0" className="mb10">
|
<Radio value="0" className="mb10">
|
||||||
<i className="iconfont icon-banbenku font-16 mr5"></i>
|
<i className="iconfont icon-banbenku font-16 mr5"></i>
|
||||||
直接提交至<span className="color-orange">{currentBranch || branch}</span>分支
|
直接提交至<span className="color-orange">{returnbar(b)}</span>分支
|
||||||
</Radio>
|
</Radio>
|
||||||
<Radio value="1">
|
<Radio value="1">
|
||||||
<Icon type="pull-request" className="mr5" />
|
<Icon type="pull-request" className="mr5" />
|
||||||
|
|
|
@ -12,6 +12,13 @@ class m_editor extends Component {
|
||||||
editorValue: this.props.content,
|
editorValue: this.props.content,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
componentDidUpdate=(prevProps)=>{
|
||||||
|
if(prevProps && this.props && this.props.content !== prevProps.content){
|
||||||
|
this.setState({
|
||||||
|
editorValue:this.props.content
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
changeEditor = (editorValue) => {
|
changeEditor = (editorValue) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
editorValue,
|
editorValue,
|
||||||
|
@ -20,7 +27,7 @@ class m_editor extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { editorValue } = this.state;
|
const { editorValue } = this.state;
|
||||||
const { readOnly, editorType, language , currentBranch } = this.props;
|
const { readOnly, editorType, language , currentBranch , descName } = this.props;
|
||||||
const editor_options = {
|
const editor_options = {
|
||||||
lineNumbers: "on",
|
lineNumbers: "on",
|
||||||
wordWrap: true, //强制换行
|
wordWrap: true, //强制换行
|
||||||
|
@ -44,7 +51,7 @@ class m_editor extends Component {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div>
|
<div>
|
||||||
<div className="branchTable">
|
<div className="branchTable" style={{border:"1px solid #eee"}}>
|
||||||
<Editor
|
<Editor
|
||||||
height="400px"
|
height="400px"
|
||||||
language={language ? language : "plaintext"}
|
language={language ? language : "plaintext"}
|
||||||
|
@ -57,7 +64,7 @@ class m_editor extends Component {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{!readOnly && (
|
{!readOnly && (
|
||||||
<div style={{padding:"20px",marginTop:"20px",borderTop:"1px solid #d9d9d9"}}>
|
<div style={{marginTop:"20px",padding:"20px"}}>
|
||||||
<UserSubmitComponent
|
<UserSubmitComponent
|
||||||
{...this.props}
|
{...this.props}
|
||||||
{...this.state}
|
{...this.state}
|
||||||
|
@ -65,6 +72,7 @@ class m_editor extends Component {
|
||||||
content={editorValue}
|
content={editorValue}
|
||||||
editor_type={editorType}
|
editor_type={editorType}
|
||||||
currentBranch={currentBranch}
|
currentBranch={currentBranch}
|
||||||
|
descName={descName}
|
||||||
></UserSubmitComponent>
|
></UserSubmitComponent>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -60,6 +60,7 @@ class UploadFile extends Component {
|
||||||
filepath={file_path}
|
filepath={file_path}
|
||||||
content={editorValue}
|
content={editorValue}
|
||||||
editor_type={"upload"}
|
editor_type={"upload"}
|
||||||
|
descName={`ADD file via upload`}
|
||||||
></UserSubmitComponent>
|
></UserSubmitComponent>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
import React, { useEffect , useState } from 'react';
|
||||||
|
import Axios from 'axios';
|
||||||
|
import { Pagination , Spin , Popconfirm }from 'antd';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { getImageUrl } from 'educoder';
|
||||||
|
import Nodata from '../Nodata';
|
||||||
|
import { FlexAJ } from '../Component/layout';
|
||||||
|
|
||||||
|
const limit = 15;
|
||||||
|
function Apply(props) {
|
||||||
|
const username = props.match.params.username;
|
||||||
|
const [ list , setList ] = useState(undefined);
|
||||||
|
const [ page , setPage ] = useState(1);
|
||||||
|
const [ total , setTotal ] = useState(0);
|
||||||
|
const [ isSpin , setIsSpin ] = useState(true);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(username){
|
||||||
|
setIsSpin(true);
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
},[username])
|
||||||
|
|
||||||
|
function getList() {
|
||||||
|
const url = `/users/${username}/applied_projects.json`;
|
||||||
|
Axios.get(url).then(result=>{
|
||||||
|
if(result){
|
||||||
|
setList(result.data.applied_projects);
|
||||||
|
setTotal(result.data.total_count);
|
||||||
|
setIsSpin(false);
|
||||||
|
}
|
||||||
|
}).catch(error=>{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接受
|
||||||
|
function acceptDivert(id){
|
||||||
|
const url = `/users/${username}/applied_projects/${id}/accept.json`;
|
||||||
|
Axios.post(url).then(result=>{
|
||||||
|
if(result && result.data){
|
||||||
|
getList();
|
||||||
|
props && props.deleteEvent("apply",1);
|
||||||
|
}
|
||||||
|
}).catch(error=>{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拒绝
|
||||||
|
function revertDivert(id){
|
||||||
|
const url = `/users/${username}/applied_projects/${id}/refuse.json`;
|
||||||
|
Axios.post(url).then(result=>{
|
||||||
|
if(result && result.data){
|
||||||
|
getList();
|
||||||
|
props && props.deleteEvent("apply",1);
|
||||||
|
}
|
||||||
|
}).catch(error=>{})
|
||||||
|
}
|
||||||
|
return(
|
||||||
|
<div>
|
||||||
|
<Spin spinning={isSpin}>
|
||||||
|
<div style={{minHeight:"400px"}}>
|
||||||
|
{
|
||||||
|
list && list.length > 0 ?
|
||||||
|
<ul className="notifyList">
|
||||||
|
{
|
||||||
|
list.map((i,k)=>{
|
||||||
|
return(
|
||||||
|
<li>
|
||||||
|
<Link to={`/users/${i.user && i.user.login}`}><img src={getImageUrl(`/${i.user && i.user.image_url}`)} alt="" className="notifyImg"/></Link>
|
||||||
|
<div className="notifyFlex">
|
||||||
|
<p className="notifyInfos">
|
||||||
|
<Link to={`/users/${i.user && i.user.login}`} className="font-15 mr20">{i.user && i.user.name}</Link>
|
||||||
|
<span className="color-grey-9">{i.time_ago}</span>
|
||||||
|
</p>
|
||||||
|
<FlexAJ>
|
||||||
|
<p>申请以【{i.role === "developer" ?"开发者":i.role === "manager" ? "管理者":"报告者"}】身份加入【{i.project && i.project.name}】项目。是否同意?</p>
|
||||||
|
{
|
||||||
|
i.status === "common" &&
|
||||||
|
<span>
|
||||||
|
<Popconfirm title={`确定同意${i.user && i.user.name}加入【${i.project && i.project.name}】项目?`} okText="确定" cancelText="取消" onConfirm={()=>acceptDivert(i.id)}>
|
||||||
|
<a className="color-blue">同意</a>
|
||||||
|
</Popconfirm>
|
||||||
|
<Popconfirm title={`确定拒绝${i.user && i.user.name}加入【${i.project && i.project.name}】项目?`} okText="确定" cancelText="取消" onConfirm={()=>revertDivert(i.id)}>
|
||||||
|
<a className="color-red ml20">拒绝</a>
|
||||||
|
</Popconfirm>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
i.status === "accepted" && <span className="color-grey-9">已接受</span>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
i.status === "refused" && <span className="color-grey-9">已拒绝</span>
|
||||||
|
}
|
||||||
|
</FlexAJ>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
:
|
||||||
|
""
|
||||||
|
}
|
||||||
|
{list && list.length === 0 && <Nodata _html="暂无成员申请" />}
|
||||||
|
{
|
||||||
|
total > limit &&
|
||||||
|
<div className="edu-txt-center pt20 pb20">
|
||||||
|
<Pagination simple pageSize={limit} total={total} current={page} onChange={(p)=>{setPage(p)}}/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Apply;
|
|
@ -0,0 +1,128 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import './Index.scss';
|
||||||
|
|
||||||
|
import Loadable from "react-loadable";
|
||||||
|
import Loading from "../../Loading";
|
||||||
|
import { Route, Switch } from "react-router-dom";
|
||||||
|
|
||||||
|
const Apply = Loadable({
|
||||||
|
loader: () => import("./Apply"),
|
||||||
|
loading: Loading,
|
||||||
|
});
|
||||||
|
const Notify = Loadable({
|
||||||
|
loader: () => import("./Notify"),
|
||||||
|
loading: Loading,
|
||||||
|
});
|
||||||
|
const UndoEvent = Loadable({
|
||||||
|
loader: () => import("./UndoEvent"),
|
||||||
|
loading: Loading,
|
||||||
|
});
|
||||||
|
function Index(props){
|
||||||
|
const username = props.match.params.username;
|
||||||
|
const pathname = props.history.location.pathname;
|
||||||
|
const user = props.user;
|
||||||
|
|
||||||
|
const [ menu , setMenu ] = useState("notify");
|
||||||
|
const [ messagesCount , setMessagesCount ] = useState(0);
|
||||||
|
const [ transferCount , setTransferCount ] = useState(0);
|
||||||
|
const [ applyCount , setApplyCount ] = useState(0);
|
||||||
|
|
||||||
|
const [ flag , setFlag ] = useState(true);
|
||||||
|
const { current_user } = props;
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if((username && current_user && (current_user.login !== username))){
|
||||||
|
props.history.push(`/users/${username}`);
|
||||||
|
}
|
||||||
|
},[current_user,username])
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(user){
|
||||||
|
setTransferCount(user.undo_transfer_projects);
|
||||||
|
setApplyCount(user.undo_join_projects);
|
||||||
|
setMessagesCount(user.undo_messages);
|
||||||
|
}
|
||||||
|
},[user])
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(pathname && username){
|
||||||
|
if(pathname === `/users/${username}/notice`){
|
||||||
|
setMenu("notify");
|
||||||
|
changeNum(user.undo_messages);
|
||||||
|
}
|
||||||
|
if(pathname === `/users/${username}/notice/undo`){
|
||||||
|
setMenu("undo");
|
||||||
|
}
|
||||||
|
if(pathname === `/users/${username}/notice/apply`){
|
||||||
|
setMenu("apply");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},[pathname,user])
|
||||||
|
|
||||||
|
function changeNum(){
|
||||||
|
if(flag){
|
||||||
|
messagesCount && props.deleteUndoEvent(messagesCount);
|
||||||
|
setFlag(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteEvent(type,count) {
|
||||||
|
let c = count;
|
||||||
|
if(type==="apply"){
|
||||||
|
setApplyCount(applyCount-count);
|
||||||
|
}else if(type==="undo"){
|
||||||
|
setTransferCount(applyCount-count);
|
||||||
|
}else{
|
||||||
|
setMessagesCount(0);
|
||||||
|
c = messagesCount;
|
||||||
|
}
|
||||||
|
(c || c===0) && props.deleteUndoEvent(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ul className="noticeMenu">
|
||||||
|
<li className={menu === "notify" ? "active":""}>
|
||||||
|
<Link to={`/users/${username}/notice`} onClick={changeNum}>
|
||||||
|
<span>通知</span>
|
||||||
|
{messagesCount ? <span className="unNum">{messagesCount}</span>:""}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li className={menu === "undo" ? "active":""}>
|
||||||
|
<Link to={`/users/${username}/notice/undo`}>
|
||||||
|
<span>接收仓库</span>
|
||||||
|
{transferCount ? <span className="unNum">{transferCount}</span>:""}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li className={menu === "apply" ? "active":""}>
|
||||||
|
<Link to={`/users/${username}/notice/apply`}>
|
||||||
|
<span>成员申请</span>
|
||||||
|
{applyCount ? <span className="unNum">{applyCount}</span>:""}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<Switch>
|
||||||
|
<Route
|
||||||
|
path="/users/:username/notice/apply"
|
||||||
|
render={(p) => {
|
||||||
|
return <Apply {...props} {...p} deleteEvent={deleteEvent}/>;
|
||||||
|
}}
|
||||||
|
></Route>
|
||||||
|
<Route
|
||||||
|
path="/users/:username/notice/undo"
|
||||||
|
render={(p) => {
|
||||||
|
return <UndoEvent {...props} {...p} deleteEvent={deleteEvent}/>;
|
||||||
|
}}
|
||||||
|
></Route>
|
||||||
|
<Route
|
||||||
|
path="/users/:username/notice"
|
||||||
|
render={(p) => {
|
||||||
|
return <Notify {...props} {...p} deleteEvent={deleteEvent}/>;
|
||||||
|
}}
|
||||||
|
></Route>
|
||||||
|
</Switch>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export default Index;
|
|
@ -0,0 +1,60 @@
|
||||||
|
.noticeMenu{
|
||||||
|
padding:0px 30px;
|
||||||
|
display: flex;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
li{
|
||||||
|
font-size: 16px;
|
||||||
|
padding:0px;
|
||||||
|
margin-right:30px;
|
||||||
|
height: 70px;
|
||||||
|
line-height: 70px;
|
||||||
|
position: relative;
|
||||||
|
transform: none;
|
||||||
|
a{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
&.active a span{
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
.unNum{
|
||||||
|
color: #d38900;
|
||||||
|
font-size: 12px;
|
||||||
|
border-radius: 13px;
|
||||||
|
height: 16px;
|
||||||
|
line-height: 16px;
|
||||||
|
padding:0px 4px;
|
||||||
|
min-width: 23px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #ffe4b3;
|
||||||
|
margin-top: 27px;
|
||||||
|
margin-left: 10px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.notifyList{
|
||||||
|
padding:0px 30px;
|
||||||
|
li{
|
||||||
|
display: flex;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
padding:20px 0px;
|
||||||
|
.notifyImg{
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
.notifyFlex{
|
||||||
|
flex:1;
|
||||||
|
p{
|
||||||
|
margin:0px;
|
||||||
|
}
|
||||||
|
.notifyInfos{
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:last-child{
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import Nodata from '../Nodata';
|
||||||
|
import { Pagination , Spin } from 'antd';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { getImageUrl } from 'educoder';
|
||||||
|
import Axios from "axios";
|
||||||
|
|
||||||
|
const limit = 15;
|
||||||
|
function Notify(props){
|
||||||
|
const username = props.match.params.username;
|
||||||
|
const [ list , setList ] = useState(undefined);
|
||||||
|
const [ page , setPage ] = useState(1);
|
||||||
|
const [ total , setTotal ] = useState(0);
|
||||||
|
const [ isSpin , setIsSpin ] = useState(true);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
props && props.deleteEvent("notify",0);
|
||||||
|
},[])
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(username){
|
||||||
|
setIsSpin(true);
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
},[username,page])
|
||||||
|
|
||||||
|
function getList(){
|
||||||
|
const url = `/users/${username}/applied_messages.json`;
|
||||||
|
Axios.get(url,{
|
||||||
|
params:{
|
||||||
|
page,per_page:limit
|
||||||
|
}
|
||||||
|
}).then(result=>{
|
||||||
|
if(result){
|
||||||
|
setList(result.data.applied_messages);
|
||||||
|
setTotal(result.data.total_count);
|
||||||
|
setIsSpin(false);
|
||||||
|
}
|
||||||
|
}).catch(error=>{})
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderStatus(status,applied){
|
||||||
|
let { project , owner} = applied
|
||||||
|
if(status){
|
||||||
|
switch(status){
|
||||||
|
case 'canceled':
|
||||||
|
return <p>取消转移【<Link to={`/projects/${project && project.owner && project.owner.login}/${project && project.identifier}`}>{project && project.name}</Link>】仓库</p>
|
||||||
|
case 'common':
|
||||||
|
return <p>正在将【<Link to={`/projects/${project && project.owner && project.owner.login}/${project && project.identifier}`}>{project && project.name}</Link>】仓库转移给【<Link to={`/users/${owner && owner.login}`}>{owner && owner.name}</Link>】</p>
|
||||||
|
case 'successed':
|
||||||
|
return <p>【<Link to={`/projects/${project && project.owner && project.owner.login}/${project && project.identifier}`}>{project && project.name}</Link>】仓库成功转移给【<Link to={`/users/${owner && owner.login}`}>{owner && owner.name}</Link>】</p>
|
||||||
|
default:
|
||||||
|
return <p>拒绝转移【<Link to={`/projects/${project && project.owner && project.owner.login}/${project && project.identifier}`}>{project && project.name}</Link>】仓库</p>
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderApplyStatus(status,applied) {
|
||||||
|
let { project } = applied;
|
||||||
|
if(status){
|
||||||
|
switch(status){
|
||||||
|
case 'successed':
|
||||||
|
return <p>已通过你加入【<Link to={`/projects/${project && project.owner && project.owner.login}/${project && project.identifier}`}>{project && project.name}</Link>】项目的申请</p>
|
||||||
|
default:
|
||||||
|
return <p>已拒绝你加入【<Link to={`/projects/${project && project.owner && project.owner.login}/${project && project.identifier}`}>{project && project.name}</Link>】项目的申请</p>
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div>
|
||||||
|
<Spin spinning={isSpin}>
|
||||||
|
<div style={{minHeight:"400px"}}>
|
||||||
|
{
|
||||||
|
list && list.length > 0 ?
|
||||||
|
<ul className="notifyList">
|
||||||
|
{
|
||||||
|
list.map((i,k)=>{
|
||||||
|
return(
|
||||||
|
<li>
|
||||||
|
<Link to={`/users/${i.login}`}><img src={getImageUrl(`/${i.applied_user && i.applied_user.image_url}`)} alt="" className="notifyImg"/></Link>
|
||||||
|
<div className="notifyFlex">
|
||||||
|
<p className="notifyInfos">
|
||||||
|
<Link to={`/users/${i.applied_user && i.applied_user.login}`} className="font-15 mr20">{i.applied_user && i.applied_user.name}</Link>
|
||||||
|
<span className="color-grey-9">{i.time_ago}</span>
|
||||||
|
</p>
|
||||||
|
{ i.applied_type === "AppliedProject" ? renderApplyStatus(i.status,i.applied):renderStatus(i.status,i.applied)}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
:
|
||||||
|
""
|
||||||
|
}
|
||||||
|
{list && list.length === 0 && <Nodata _html="暂无通知" />}
|
||||||
|
{
|
||||||
|
total > limit &&
|
||||||
|
<div className="edu-txt-center pt20 pb20">
|
||||||
|
<Pagination simple pageSize={limit} total={total} current={page} onChange={(p)=>{setPage(p)}}/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Notify;
|
|
@ -0,0 +1,123 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import Nodata from '../Nodata';
|
||||||
|
import { FlexAJ } from '../Component/layout';
|
||||||
|
import { Pagination , Popconfirm , Spin } from 'antd';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { getImageUrl } from 'educoder';
|
||||||
|
import Axios from 'axios';
|
||||||
|
|
||||||
|
const limit = 15;
|
||||||
|
function UndoEvent(props){
|
||||||
|
const username = props.match.params.username;
|
||||||
|
const [ list , setList ] = useState(undefined);
|
||||||
|
const [ page , setPage ] = useState(1);
|
||||||
|
const [ total , setTotal ] = useState(0);
|
||||||
|
const [ isSpin , setIsSpin ] = useState(true);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(username){
|
||||||
|
setIsSpin(true);
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
},[username,page])
|
||||||
|
|
||||||
|
function getList(){
|
||||||
|
const url = `/users/${username}/applied_transfer_projects.json`;
|
||||||
|
Axios.get(url,{
|
||||||
|
params:{
|
||||||
|
page,per_page:limit
|
||||||
|
}
|
||||||
|
}).then(result=>{
|
||||||
|
if(result){
|
||||||
|
setList(result.data.applied_transfer_projects);
|
||||||
|
setTotal(result.data.total_count);
|
||||||
|
setIsSpin(false);
|
||||||
|
}
|
||||||
|
}).catch(error=>{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接受
|
||||||
|
function acceptDivert(id){
|
||||||
|
const url = `/users/${username}/applied_transfer_projects/${id}/accept.json`;
|
||||||
|
Axios.post(url).then(result=>{
|
||||||
|
if(result && result.data){
|
||||||
|
getList();
|
||||||
|
props && props.deleteEvent("undo",1);
|
||||||
|
}
|
||||||
|
}).catch(error=>{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拒绝
|
||||||
|
function revertDivert(id){
|
||||||
|
const url = `/users/${username}/applied_transfer_projects/${id}/refuse.json`;
|
||||||
|
Axios.post(url).then(result=>{
|
||||||
|
if(result && result.data){
|
||||||
|
getList();
|
||||||
|
props && props.deleteEvent("undo",1);
|
||||||
|
}
|
||||||
|
}).catch(error=>{})
|
||||||
|
}
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div>
|
||||||
|
<Spin spinning={isSpin}>
|
||||||
|
<div style={{minHeight:"400px"}}>
|
||||||
|
{
|
||||||
|
list && list.length > 0 ?
|
||||||
|
<ul className="notifyList">
|
||||||
|
{
|
||||||
|
list.map((i,k)=>{
|
||||||
|
return(
|
||||||
|
<li>
|
||||||
|
<Link to={`/users/${i.user && i.user.login}`}><img src={getImageUrl(`/${i.user && i.user.image_url}`)} alt="" className="notifyImg"/></Link>
|
||||||
|
<div className="notifyFlex">
|
||||||
|
<p className="notifyInfos">
|
||||||
|
<Link to={`/users/${i.login}`} className="font-15 mr20">{i.user && i.user.name}</Link>
|
||||||
|
<span className="color-grey-9">{i.time_ago}</span>
|
||||||
|
</p>
|
||||||
|
<FlexAJ>
|
||||||
|
<p className="color-grey-6">请求将仓库【<Link to={`/projects/${i.project && i.project.owner && i.project.owner.login}/${i.project && i.project.identifier}`}>{i.project && i.project.name}</Link>】
|
||||||
|
转移给【<Link to={`/users/${i.owner && i.owner.login}`}>{i.owner && i.owner.name}</Link>】,是否接受?</p>
|
||||||
|
{
|
||||||
|
i.status === "common" &&
|
||||||
|
<span>
|
||||||
|
<Popconfirm title={`确定接受仓库${i.project && i.project.name}?`} okText="确定" cancelText="取消" onConfirm={()=>acceptDivert(i.id)}>
|
||||||
|
<a className="color-blue">接受</a>
|
||||||
|
</Popconfirm>
|
||||||
|
<Popconfirm title={`确定拒绝接受仓库${i.project && i.project.name}?`} okText="确定" cancelText="取消" onConfirm={()=>revertDivert(i.id)}>
|
||||||
|
<a className="color-red ml20">拒绝</a>
|
||||||
|
</Popconfirm>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
i.status === "canceled" && <span className="color-grey-9">对方已取消转移</span>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
i.status === "accepted" && <span className="color-grey-9">已接受</span>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
i.status === "refused" && <span className="color-grey-9">已拒绝</span>
|
||||||
|
}
|
||||||
|
</FlexAJ>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
:
|
||||||
|
""
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
{list && list.length === 0 && <Nodata _html="暂无接收信息" />}
|
||||||
|
{
|
||||||
|
total > limit &&
|
||||||
|
<div className="edu-txt-center pt20 pb20">
|
||||||
|
<Pagination simple pageSize={limit} total={total} current={page} onChange={(p)=>{setPage(p)}}/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default UndoEvent;
|
|
@ -212,7 +212,7 @@ class Detail extends Component {
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
className="user_img"
|
className="user_img"
|
||||||
src={getImageUrl(`images/${data && data.author_picture}`)}
|
src={getImageUrl(`/${data && data.author_picture}`)}
|
||||||
alt=""
|
alt=""
|
||||||
width="50"
|
width="50"
|
||||||
height="50"
|
height="50"
|
||||||
|
@ -249,7 +249,7 @@ class Detail extends Component {
|
||||||
添加于 {data && data.created_at}
|
添加于 {data && data.created_at}
|
||||||
</span>
|
</span>
|
||||||
{data && data.user_permission ? (
|
{data && data.user_permission ? (
|
||||||
<span className="pull-right">
|
<span className="pull-right 123123">
|
||||||
<a className="color-blue fr" onClick={this.copydetail}>
|
<a className="color-blue fr" onClick={this.copydetail}>
|
||||||
复制
|
复制
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -89,8 +89,9 @@ class Milepost extends Component {
|
||||||
closeselect: status === "closed" ? current_user.user_id : undefined,
|
closeselect: status === "closed" ? current_user.user_id : undefined,
|
||||||
openselect: status === "closed" ? undefined : current_user.user_id
|
openselect: status === "closed" ? undefined : current_user.user_id
|
||||||
})
|
})
|
||||||
|
this.getList(1, status, 'desc');
|
||||||
this.getList(1, status, 'desc')
|
const { getDetail } = this.props;
|
||||||
|
getDetail && getDetail();
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -107,7 +108,9 @@ class Milepost extends Component {
|
||||||
}
|
}
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result) {
|
if (result) {
|
||||||
this.getList(1, this.state.status, 'desc')
|
this.getList(1, this.state.status, 'desc');
|
||||||
|
const { getDetail } = this.props;
|
||||||
|
getDetail && getDetail();
|
||||||
}
|
}
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -150,7 +153,7 @@ class Milepost extends Component {
|
||||||
const { data, limit, page, openselect, closeselect, spinings } = this.state;
|
const { data, limit, page, openselect, closeselect, spinings } = this.state;
|
||||||
const { projectsId , owner } = this.props.match.params;
|
const { projectsId , owner } = this.props.match.params;
|
||||||
const menu = (
|
const menu = (
|
||||||
<Menu onClick={this.arrayList}>
|
<Menu className="orderCondition" onClick={this.arrayList}>
|
||||||
<Menu.Item key={'created_on'} value="desc">到期日从近到远</Menu.Item>
|
<Menu.Item key={'created_on'} value="desc">到期日从近到远</Menu.Item>
|
||||||
<Menu.Item key={'created_on'} value="asc">到期日从远到近</Menu.Item>
|
<Menu.Item key={'created_on'} value="asc">到期日从远到近</Menu.Item>
|
||||||
<Menu.Item key={'percent'} value="desc">完成度从低到高</Menu.Item>
|
<Menu.Item key={'percent'} value="desc">完成度从低到高</Menu.Item>
|
||||||
|
@ -228,8 +231,8 @@ class Milepost extends Component {
|
||||||
<Link to={`/projects/${owner}/${projectsId}/milestones/${item.id}/edit`} className="color-grey-9">编辑</Link>
|
<Link to={`/projects/${owner}/${projectsId}/milestones/${item.id}/edit`} className="color-grey-9">编辑</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid-item ml15 color-grey-9">
|
<div className="grid-item ml15 color-grey-9">
|
||||||
<i className="iconfont icon-yiguanbi1 font-14 mr5"></i>
|
<i className={item.status === "closed" ? "iconfont icon-gouxuan font-14 mr5":"iconfont icon-yiguanbi1 font-14 mr5"}></i>
|
||||||
<a onClick={() => this.updatestatusemile(this.state.status === "closed" ? "open" : "closed", item)} className="color-grey-9">{this.state.status === "closed" ? "开启" : "关闭"}</a>
|
<a onClick={() => this.updatestatusemile(item.status === "closed" ? "open" : "closed", item)} className="color-grey-9">{this.state.status === "closed" ? "开启" : "关闭"}</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid-item ml15 color-grey-9">
|
<div className="grid-item ml15 color-grey-9">
|
||||||
<i className="iconfont icon-lajitong font-14 mr5" ></i>
|
<i className="iconfont icon-lajitong font-14 mr5" ></i>
|
||||||
|
|
|
@ -69,6 +69,27 @@ class MilepostDetail extends Component {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deletedetail = (id) => {
|
||||||
|
const { projectsId , owner } = this.props.match.params;
|
||||||
|
const url = `/${owner}/${projectsId}/issues/${id}.json`;
|
||||||
|
axios.delete(url, {
|
||||||
|
data: {
|
||||||
|
project_id: projectsId,
|
||||||
|
id: id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
if (result) {
|
||||||
|
const { page } = this.state;
|
||||||
|
this.getIssueList(page);
|
||||||
|
const { getDetail } = this.props;
|
||||||
|
getDetail && getDetail();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
// 获取列表数据
|
// 获取列表数据
|
||||||
getIssueList = ( page , item , value , update , updateValue , type ) => {
|
getIssueList = ( page , item , value , update , updateValue , type ) => {
|
||||||
const { projectsId, meilid , owner } = this.props.match.params;
|
const { projectsId, meilid , owner } = this.props.match.params;
|
||||||
|
@ -141,7 +162,7 @@ class MilepostDetail extends Component {
|
||||||
|
|
||||||
renderMenu = (array, name, id) => {
|
renderMenu = (array, name, id) => {
|
||||||
return (
|
return (
|
||||||
<Menu>
|
<Menu className="orderCondition">
|
||||||
<Menu.Item key={"all"} onClick={(e) => this.getOption(e, id, name)}>{name}</Menu.Item>
|
<Menu.Item key={"all"} onClick={(e) => this.getOption(e, id, name)}>{name}</Menu.Item>
|
||||||
{
|
{
|
||||||
array && array.length > 0 && array.map((item, key) => {
|
array && array.length > 0 && array.map((item, key) => {
|
||||||
|
@ -218,7 +239,7 @@ class MilepostDetail extends Component {
|
||||||
</span>
|
</span>
|
||||||
<div className="milepostdiv">
|
<div className="milepostdiv">
|
||||||
<Link to={`/projects/${owner}/${projectsId}/milestones/${meilid}/edit`} className="topWrapper_btn" style={{ marginRight: 15 }} >编辑里程碑</Link>
|
<Link to={`/projects/${owner}/${projectsId}/milestones/${meilid}/edit`} className="topWrapper_btn" style={{ marginRight: 15 }} >编辑里程碑</Link>
|
||||||
<Link to={`/projects/${owner}/${projectsId}/issues/${meilid}/new`} className="topWrapper_btn">创建任务</Link>
|
<Link to={`/projects/${owner}/${projectsId}/issues/${meilid}/new`} className="topWrapper_btn">创建易修</Link>
|
||||||
</div>
|
</div>
|
||||||
</FlexAJ>
|
</FlexAJ>
|
||||||
</div>
|
</div>
|
||||||
|
@ -275,7 +296,15 @@ class MilepostDetail extends Component {
|
||||||
:
|
:
|
||||||
issues && issues.length>0 && issues.map((item,key)=>{
|
issues && issues.length>0 && issues.map((item,key)=>{
|
||||||
return(
|
return(
|
||||||
<OrderItem key={key} mile item={item} search_count={search_count} page={page} limit={limit} {...this.props} {...this.state}></OrderItem>
|
<OrderItem
|
||||||
|
key={key} mile
|
||||||
|
item={item}
|
||||||
|
search_count={search_count}
|
||||||
|
page={page}
|
||||||
|
limit={limit}
|
||||||
|
{...this.props} {...this.state}
|
||||||
|
deletedetail={this.deletedetail}
|
||||||
|
></OrderItem>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,10 +42,9 @@ class OrderItem extends Component {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
const { item , checkbox , mile } = this.props;
|
const { item , checkbox , mile , user_admin_or_member } = this.props;
|
||||||
const { projectsId , owner } = this.props.match.params;
|
const { projectsId , owner } = this.props.match.params;
|
||||||
const { current_user } = this.props
|
const { current_user } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
item &&
|
item &&
|
||||||
<div className="issueItem">
|
<div className="issueItem">
|
||||||
|
@ -91,13 +90,13 @@ class OrderItem extends Component {
|
||||||
<div className="milepostleft">
|
<div className="milepostleft">
|
||||||
<Link to={`/projects/${owner}/${projectsId}/issues/${item.id}/detail`}><i className="iconfont icon-pinglun1 mr3 font-16"></i>{item.journals_count}</Link>
|
<Link to={`/projects/${owner}/${projectsId}/issues/${item.id}/detail`}><i className="iconfont icon-pinglun1 mr3 font-16"></i>{item.journals_count}</Link>
|
||||||
{
|
{
|
||||||
current_user && current_user.login ?
|
user_admin_or_member ?
|
||||||
<div style={{ display: this.state.orderid === item.id && this.state.isdisplay ? 'flex' : 'none' }}>
|
<div id="hoverBox" style={{ display: this.state.orderid === item.id && this.state.isdisplay ? 'flex' : 'none' }}>
|
||||||
<div className="mr8 ml8 color-grey-9">
|
<div className="mr8 ml8 color-grey-9">
|
||||||
<Link to={`/projects/${owner}/${projectsId}/issues/${item.id}/updatedetail`} className="color-grey-9"><i className="iconfont icon-bianji3 font-14 mr5"></i></Link>
|
<Link to={`/projects/${owner}/${projectsId}/issues/${item.id}/updatedetail`} className="color-grey-9"><i className="iconfont icon-bianji3 font-14 mr5"></i></Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="color-grey-9">
|
<div className="color-grey-9">
|
||||||
<Popconfirm placement="bottom" title={'您确定要删除吗'} okText="是" cancelText="否" onConfirm={() => this.deletedetail(item.id)}>
|
<Popconfirm placement="bottom" overlayClassName="overlayBox" getPopupContainer={()=>document.getElementById("hoverBox")} title={'您确定要删除当前易修吗?'} okText="是" cancelText="否" onConfirm={() => this.deletedetail(item.id)}>
|
||||||
<i className="iconfont icon-yiguanbi1 font-14"></i>
|
<i className="iconfont icon-yiguanbi1 font-14"></i>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -64,6 +64,8 @@ class NewMilepost extends Component {
|
||||||
if (result) {
|
if (result) {
|
||||||
this.setState({ isSpin: false })
|
this.setState({ isSpin: false })
|
||||||
this.props.history.push(`/projects/${owner}/${projectsId}/milestones`);
|
this.props.history.push(`/projects/${owner}/${projectsId}/milestones`);
|
||||||
|
const { getDetail } = this.props;
|
||||||
|
getDetail && getDetail();
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
this.setState({ isSpin: false })
|
this.setState({ isSpin: false })
|
||||||
|
|
|
@ -17,7 +17,9 @@
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
.overlayBox{
|
||||||
|
width: 230px;
|
||||||
|
}
|
||||||
.topmilepost {
|
.topmilepost {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -590,7 +592,7 @@ a.issue-type-button.active:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 发布人、指派人数量过多时要出现滚动条 */
|
/* 发布人、指派人数量过多时要出现滚动条 */
|
||||||
.ant-dropdown-menu {
|
.ant-dropdown-menu.orderCondition {
|
||||||
max-height: 350px;
|
max-height: 350px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,7 +201,7 @@ class order extends Component {
|
||||||
|
|
||||||
renderMenu = (array, name, id, toGet) => {
|
renderMenu = (array, name, id, toGet) => {
|
||||||
return (
|
return (
|
||||||
<Menu>
|
<Menu className="orderCondition">
|
||||||
<Menu.Item key={"all"} onClick={(e) => this.getOption(e, id, name, toGet)}>
|
<Menu.Item key={"all"} onClick={(e) => this.getOption(e, id, name, toGet)}>
|
||||||
{name}
|
{name}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
@ -268,11 +268,8 @@ class order extends Component {
|
||||||
checkedValue:[],
|
checkedValue:[],
|
||||||
all:undefined
|
all:undefined
|
||||||
});
|
});
|
||||||
this.state.select_params = {
|
this.state.select_params.page = 1;
|
||||||
search: undefined,
|
this.state.select_params.limit = 15;
|
||||||
page: 1,
|
|
||||||
limit: 15,
|
|
||||||
};
|
|
||||||
this.getIssueList(type);
|
this.getIssueList(type);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -337,6 +334,8 @@ class order extends Component {
|
||||||
const { status_type } = this.state;
|
const { status_type } = this.state;
|
||||||
|
|
||||||
this.getIssueList(status_type);
|
this.getIssueList(status_type);
|
||||||
|
const { getDetail } = this.props;
|
||||||
|
getDetail && getDetail();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
@ -348,17 +347,14 @@ class order extends Component {
|
||||||
this.props.showLoginDialog();
|
this.props.showLoginDialog();
|
||||||
}
|
}
|
||||||
renderNew =()=>{
|
renderNew =()=>{
|
||||||
const { projectsId , owner } = this.props.match.params;
|
const { data } = this.state;
|
||||||
if (this.props.checkIfLogin()) {
|
if(data && data.user_admin_or_member){
|
||||||
|
const { projectsId , owner } = this.props.match.params;
|
||||||
return(
|
return(
|
||||||
<Link className="topWrapper_btn ml10" target="_blank" to={`/projects/${owner}/${projectsId}/issues/new`}>
|
<Link className="topWrapper_btn ml10" target="_blank" to={`/projects/${owner}/${projectsId}/issues/new`}>
|
||||||
+ 创建任务
|
+ 创建易修
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
}else{
|
|
||||||
return(
|
|
||||||
<a className="topWrapper_btn ml10" onClick={this.islogin}>+ 创建任务</a>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,6 +434,8 @@ class order extends Component {
|
||||||
status_id: select_params.update_status_id
|
status_id: select_params.update_status_id
|
||||||
}).then(result => {
|
}).then(result => {
|
||||||
if (result) {
|
if (result) {
|
||||||
|
const { getDetail } = this.props;
|
||||||
|
(select_params && select_params.update_status_id) && getDetail && getDetail();
|
||||||
this.props.showNotification("修改成功!");
|
this.props.showNotification("修改成功!");
|
||||||
this.successFunc();
|
this.successFunc();
|
||||||
}
|
}
|
||||||
|
@ -451,7 +449,6 @@ class order extends Component {
|
||||||
const { status_type } = this.state;
|
const { status_type } = this.state;
|
||||||
this.getIssueList(status_type);
|
this.getIssueList(status_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
resetSelectParams = () => {
|
resetSelectParams = () => {
|
||||||
let select_params = this.state.select_params;
|
let select_params = this.state.select_params;
|
||||||
select_params.update_author_id = undefined;
|
select_params.update_author_id = undefined;
|
||||||
|
@ -482,6 +479,8 @@ class order extends Component {
|
||||||
ids: checkedValue
|
ids: checkedValue
|
||||||
}).then(result => {
|
}).then(result => {
|
||||||
if (result) {
|
if (result) {
|
||||||
|
const { getDetail } = this.props;
|
||||||
|
getDetail && getDetail();
|
||||||
this.props.showNotification("删除成功!");
|
this.props.showNotification("删除成功!");
|
||||||
this.successFunc();
|
this.successFunc();
|
||||||
}
|
}
|
||||||
|
@ -553,7 +552,7 @@ class order extends Component {
|
||||||
<div className="topWrapper" style={{borderBottom:"none"}}>
|
<div className="topWrapper" style={{borderBottom:"none"}}>
|
||||||
<div className="target-detail-search">
|
<div className="target-detail-search">
|
||||||
<Search
|
<Search
|
||||||
placeholder="输入issue名称进行搜索"
|
placeholder="输入关键字搜索易修"
|
||||||
enterButton
|
enterButton
|
||||||
onSearch={this.searchFunc}
|
onSearch={this.searchFunc}
|
||||||
style={{ width: 300 }}
|
style={{ width: 300 }}
|
||||||
|
@ -574,7 +573,7 @@ class order extends Component {
|
||||||
<div className="f-wrap-between screenWrap">
|
<div className="f-wrap-between screenWrap">
|
||||||
<div className="df">
|
<div className="df">
|
||||||
{
|
{
|
||||||
current_user && current_user.login ?
|
((current_user && current_user.login) && (data && data.user_admin_or_member)) ?
|
||||||
<Checkbox value="0" style={{ lineHeight: "50px", marginRight: "15px" }} checked={all} onChange={this.changeAll}></Checkbox>
|
<Checkbox value="0" style={{ lineHeight: "50px", marginRight: "15px" }} checked={all} onChange={this.changeAll}></Checkbox>
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
|
@ -819,13 +818,14 @@ class order extends Component {
|
||||||
<OrderItem
|
<OrderItem
|
||||||
key={key}
|
key={key}
|
||||||
item={item}
|
item={item}
|
||||||
checkbox={current_user ? <Checkbox value={item.id} key={item.id} style={{ margin: '4px 15px 0px 0px' }}></Checkbox> : ""}
|
checkbox={current_user &&(data && data.user_admin_or_member) ? <Checkbox value={item.id} key={item.id} style={{ margin: '4px 15px 0px 0px' }}></Checkbox> : ""}
|
||||||
search_count={search_count}
|
search_count={search_count}
|
||||||
page={select_params.page}
|
page={select_params.page}
|
||||||
limit={select_params.limit}
|
limit={select_params.limit}
|
||||||
{...this.props}
|
{...this.props}
|
||||||
{...this.state}
|
{...this.state}
|
||||||
deletedetail={this.deletedetail}
|
deletedetail={this.deletedetail}
|
||||||
|
user_admin_or_member={data && data.user_admin_or_member}
|
||||||
></OrderItem>
|
></OrderItem>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
@ -834,7 +834,7 @@ class order extends Component {
|
||||||
)}
|
)}
|
||||||
{
|
{
|
||||||
search_count > select_params.limit ?
|
search_count > select_params.limit ?
|
||||||
<div className="mt30 mb10 edu-txt-center">
|
<div className="mt30 mb30 edu-txt-center">
|
||||||
<Pagination
|
<Pagination
|
||||||
simple
|
simple
|
||||||
defaultCurrent={select_params.page}
|
defaultCurrent={select_params.page}
|
||||||
|
|
|
@ -193,13 +193,14 @@ class order_form extends Component {
|
||||||
if (result) {
|
if (result) {
|
||||||
this.props.history.push(`/projects/${owner}/${projectsId}/issues/${orderId}/detail`);
|
this.props.history.push(`/projects/${owner}/${projectsId}/issues/${orderId}/detail`);
|
||||||
this.props.showNotification("任务更新成功!");
|
this.props.showNotification("任务更新成功!");
|
||||||
|
const { getDetail } = this.props;
|
||||||
|
getDetail && getDetail();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
isSpin: false,
|
isSpin: false,
|
||||||
});
|
});
|
||||||
console.log(error);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,17 +311,17 @@ class order_form extends Component {
|
||||||
<div className="list-right">
|
<div className="list-right">
|
||||||
<div className="pd20">
|
<div className="pd20">
|
||||||
<h3 className="mb15">
|
<h3 className="mb15">
|
||||||
{form_type === "new" ? "新建" :( form_type === "copy" ? "复制" : "编辑")}任务
|
{form_type === "new" ? "新建" :( form_type === "copy" ? "复制" : "编辑")}易修
|
||||||
</h3>
|
</h3>
|
||||||
<Form.Item>
|
<Form.Item>
|
||||||
{getFieldDecorator("subject", {
|
{getFieldDecorator("subject", {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: "请填写任务标题",
|
message: "请填写易修标题",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
})(<Input placeholder="标题" size="large" />)}
|
})(<Input placeholder="标题" size="large" maxLength={80}/>)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<div className="quillContent">
|
<div className="quillContent">
|
||||||
<MDEditor
|
<MDEditor
|
||||||
|
|
|
@ -26,15 +26,15 @@ function Collaborator(props){
|
||||||
{
|
{
|
||||||
author && author.type === "Organization" ?
|
author && author.type === "Organization" ?
|
||||||
<span>
|
<span>
|
||||||
<span style={{cursor:"pointer"}} className={nav === "1" ? "font-18 text-black color-blue":"font-18 text-black"} onClick={()=>setNav("1")}>协作者管理</span>
|
<span style={{cursor:"pointer"}} className={nav === "1" ? "font-18 text-black color-blue":"font-18 text-black"} onClick={()=>{setNav("1");setNewId(undefined)}}>协作者管理</span>
|
||||||
<span style={{cursor:"pointer"}} className={nav === "2" ? "font-18 text-black ml30 color-blue":"font-18 text-black ml30"} onClick={()=>setNav("2")}>团队管理</span>
|
<span style={{cursor:"pointer"}} className={nav === "2" ? "font-18 text-black ml30 color-blue":"font-18 text-black ml30"} onClick={()=>{setNav("2");setNewId(undefined)}}>团队管理</span>
|
||||||
</span>
|
</span>
|
||||||
:
|
:
|
||||||
<span className="font-18 text-black">协作者管理</span>
|
<span className="font-18 text-black">协作者管理</span>
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
nav === "1" ?
|
nav === "1" ?
|
||||||
<AddMember getID={getID} login/>
|
<AddMember getID={getID} login showNotification={props.showNotification}/>
|
||||||
:
|
:
|
||||||
<AddGroup getGroupID={getGroupID} organizeId={owner}/>
|
<AddGroup getGroupID={getGroupID} organizeId={owner}/>
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ function Collaborator(props){
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
nav === "1" ?
|
nav === "1" ?
|
||||||
<Member newId={newId} projectsId={projectsId} owner={owner} project_id={props.project_id} author={props.author} showNotification={props.showNotification}/>
|
<Member newId={newId} projectsId={projectsId} owner={owner} project_id={props.project_id} author={props.projectDetail && props.projectDetail.author} showNotification={props.showNotification}/>
|
||||||
:
|
:
|
||||||
<Group owner={owner} projectsId={projectsId} newGroupId={newGroupId}/>
|
<Group owner={owner} projectsId={projectsId} newGroupId={newGroupId}/>
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,6 @@ function CollaboratorMember({projectsId,owner,project_id,author,showNotification
|
||||||
const [ role , setRole ] = useState(undefined);
|
const [ role , setRole ] = useState(undefined);
|
||||||
const [ listData , setListData ] = useState(undefined);
|
const [ listData , setListData ] = useState(undefined);
|
||||||
const [ total , setTotal ] = useState(0);
|
const [ total , setTotal ] = useState(0);
|
||||||
|
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if(newId){
|
if(newId){
|
||||||
addCollaborator(newId);
|
addCollaborator(newId);
|
||||||
|
@ -188,7 +186,7 @@ function CollaboratorMember({projectsId,owner,project_id,author,showNotification
|
||||||
className="show-user-link"
|
className="show-user-link"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={getImageUrl(`images/${text}`)}
|
src={getImageUrl(`/${text}`)}
|
||||||
alt=""
|
alt=""
|
||||||
width="32px"
|
width="32px"
|
||||||
height="32px"
|
height="32px"
|
||||||
|
|
|
@ -13,6 +13,7 @@ const menu = [
|
||||||
{name:"易修 (Issue)",index:"issues"},
|
{name:"易修 (Issue)",index:"issues"},
|
||||||
{name:"合并请求",index:"pulls"},
|
{name:"合并请求",index:"pulls"},
|
||||||
{name:"工作流(beta版)",index:"devops"},
|
{name:"工作流(beta版)",index:"devops"},
|
||||||
|
// {name:"资源库",index:"resources"},
|
||||||
{name:"里程碑",index:"versions"},
|
{name:"里程碑",index:"versions"},
|
||||||
{name:"动态",index:"activity"},
|
{name:"动态",index:"activity"},
|
||||||
]
|
]
|
||||||
|
@ -24,14 +25,18 @@ class Setting extends Component {
|
||||||
LanguageList: undefined,
|
LanguageList: undefined,
|
||||||
private_check: undefined,
|
private_check: undefined,
|
||||||
loading:true,
|
loading:true,
|
||||||
project_units:['home',"activity","code"]
|
project_units:['home',"activity","code"],
|
||||||
|
divertVisible:false,
|
||||||
|
is_transfering:undefined,
|
||||||
|
projectName:undefined
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate=(prevPros)=>{
|
componentDidUpdate=(prevPros)=>{
|
||||||
|
|
||||||
if(prevPros && this.props && !this.props.checkIfLogin()){
|
if(prevPros && this.props && !this.props.checkIfLogin()){
|
||||||
this.props.history.push("/403")
|
this.props.history.push("/403")
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
componentDidMount = () => {
|
componentDidMount = () => {
|
||||||
|
@ -70,6 +75,7 @@ class Setting extends Component {
|
||||||
project_units:units
|
project_units:units
|
||||||
});
|
});
|
||||||
this.setState({
|
this.setState({
|
||||||
|
projectName:result.data.project_name,
|
||||||
private_check: result.data.private,
|
private_check: result.data.private,
|
||||||
loading:false,
|
loading:false,
|
||||||
project_units:units
|
project_units:units
|
||||||
|
@ -162,10 +168,11 @@ class Setting extends Component {
|
||||||
|
|
||||||
// 删除本仓库
|
// 删除本仓库
|
||||||
deleteProject = () => {
|
deleteProject = () => {
|
||||||
|
const { projectsId , owner } = this.props.match.params;
|
||||||
|
const { projectName } = this.state;
|
||||||
this.props.confirm({
|
this.props.confirm({
|
||||||
content: "删除后无法恢复,是否确认删除本仓库?",
|
content: <span style={{display:"block",textAlign:"left"}}>该操作无法撤销!且将会一并删除相关的易修、合并请求、工作流、里程碑、动态等数据。<br/>是否确认删除 <span style={{fontWeight:"bold"}}>{owner}/{projectName}({projectsId})</span>?</span>,
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
const { projectsId , owner } = this.props.match.params;
|
|
||||||
const url = `/${owner}/${projectsId}.json`;
|
const url = `/${owner}/${projectsId}.json`;
|
||||||
axios
|
axios
|
||||||
.delete(url)
|
.delete(url)
|
||||||
|
@ -187,8 +194,12 @@ class Setting extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { getFieldDecorator } = this.props.form;
|
const { getFieldDecorator } = this.props.form;
|
||||||
|
const { projectDetail } = this.props;
|
||||||
|
|
||||||
const { CategoryList, LanguageList, private_check ,loading } = this.state;
|
const { CategoryList, LanguageList, private_check ,loading } = this.state;
|
||||||
|
let mirror = projectDetail && projectDetail.mirror;
|
||||||
|
let type = projectDetail && projectDetail.type;
|
||||||
|
const forked_from_project_id = this.props && this.props.projectDetail && this.props.projectDetail.forked_from_project_id;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
|
@ -214,18 +225,22 @@ class Setting extends Component {
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={private_check}
|
checked={private_check}
|
||||||
onChange={this.changePrivate}
|
onChange={this.changePrivate}
|
||||||
|
disabled={forked_from_project_id}
|
||||||
>
|
>
|
||||||
将仓库设为私有
|
<span className="color-grey-9">将仓库设为私有</span>
|
||||||
|
<span className="color-grey-6">
|
||||||
|
{ forked_from_project_id ?`(Fork仓库的可见性实时同步自源仓库,不支持直接修改)`:`(修改仓库的可见性,将会影响到该仓库下所有Fork仓库的可见性)`}
|
||||||
|
</span>
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
<Form.Item label="仓库描述">
|
<Form.Item label="项目简介">
|
||||||
{getFieldDecorator("project_description", {
|
{getFieldDecorator("project_description", {
|
||||||
rules: [],
|
rules: [],
|
||||||
})(
|
})(
|
||||||
<TextArea
|
<TextArea
|
||||||
placeholder="请输入仓库描述"
|
placeholder="请输入项目简介"
|
||||||
style={{ height: "80px" }} maxLength={200}
|
style={{ height: "80px" }} maxLength={200}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -261,7 +276,7 @@ class Setting extends Component {
|
||||||
<Checkbox
|
<Checkbox
|
||||||
key={key}
|
key={key}
|
||||||
value={item.index}
|
value={item.index}
|
||||||
disabled={item.index === "home" || item.index === "activity" || item.index === "code"}
|
disabled={item.index === "home" || item.index === "activity" || item.index === "code" || (mirror && (type && type===2) && item.index === "pulls")}
|
||||||
>{item.name}</Checkbox>
|
>{item.name}</Checkbox>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import sonar from '../Images/sonar.png';
|
||||||
|
import { FlexAJ } from '../Component/layout';
|
||||||
|
import { Button } from 'antd';
|
||||||
|
import './index.scss';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
function Index(props) {
|
||||||
|
const [ spining , setSpining ] = useState(false);
|
||||||
|
const [ data , setData ] = useState(null);
|
||||||
|
|
||||||
|
const permission = props.projectDetail && props.projectDetail.permission;
|
||||||
|
const { owner , projectsId } = props.match.params;
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(permission && permission!=="Reporter"){
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
},[permission])
|
||||||
|
|
||||||
|
function startCheck() {
|
||||||
|
setSpining(true);
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
|
||||||
|
function run() {
|
||||||
|
const url = `/${owner}/${projectsId}/sonarqube.json`;
|
||||||
|
axios.get(url).then(result=>{
|
||||||
|
if(result){
|
||||||
|
setSpining(false);
|
||||||
|
setData(result.data);
|
||||||
|
}
|
||||||
|
}).catch(error=>{setSpining(false);})
|
||||||
|
}
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className="sonarBox">
|
||||||
|
<FlexAJ>
|
||||||
|
<img src={sonar} alt=""/>
|
||||||
|
<Button type={"primary"} loading={spining} onClick={startCheck} disabled={permission !== "Admin" && permission !== "Owner" && permission !== "Manager"}>{spining ? "分析中":"质量分析"}</Button>
|
||||||
|
</FlexAJ>
|
||||||
|
<div className="sonarDesc">
|
||||||
|
<p>1. 基于 Sonar 的代码质量分析,支持对项目进行文件数、重复率统计、代码逻辑缺陷扫描等功能,并给出对应解决报告;</p>
|
||||||
|
<p>2. 目前支持 Java、JavaScript、C++、Go、Python、PHP、Ruby、Groovy、Lua、TypeScript、Web、XML;</p>
|
||||||
|
<p>3. 默认支持代码文本格式全为 UTF-8,其他编码可能会产生乱码;</p>
|
||||||
|
<p>4. 仅保存最近一次分析结果;</p>
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
data && data.length>0 && data.map((i,k)=>{
|
||||||
|
return(
|
||||||
|
<div className="sonarData">
|
||||||
|
<p className="color-grey-9 font-16">分支:<span className="color-grey-6">{i.branch_name}</span></p>
|
||||||
|
<div>
|
||||||
|
<span className="color-grey-9 mr30">开始时间:<span className="color-grey-6">{i.created_at}</span></span>
|
||||||
|
<span className="color-grey-9">结束时间:<span className="color-grey-6">{i.updated_at}</span></span>
|
||||||
|
</div>
|
||||||
|
<ul className="sonarList">
|
||||||
|
<li>
|
||||||
|
<span>{i.bug_num || "0"}</span>
|
||||||
|
<span>bugs</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span>{i.loopholes || "0"}</span>
|
||||||
|
<span>漏洞</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span>{i.repetition_rate || "--"}</span>
|
||||||
|
<span>重复</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span>{i.file_num || "0"}</span>
|
||||||
|
<span>文件数</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Index;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue