diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index f221492f..00000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,1190 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1584692398144 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..7a73a41b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js index a7b2c9f4..4a9d9465 100644 --- a/config/webpack.config.prod.js +++ b/config/webpack.config.prod.js @@ -19,7 +19,8 @@ const getClientEnvironment = require("./env"); let publicPath = "/react/build/"; const publicUrl = publicPath.slice(0, -1); -const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false"; +// const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false"; +const shouldUseSourceMap = process.env.NODE_ENV !== "production"; const env = getClientEnvironment(publicPath); // This is the production configuration. @@ -54,7 +55,8 @@ module.exports = { }, bail: true, mode: "production", - devtool: false, //测试版 + // devtool: false, //测试版 + devtool: shouldUseSourceMap?'source-map':false, entry: [require.resolve("./polyfills"), paths.appIndexJs], output: { path: paths.appBuild, diff --git a/package-lock.json b/package-lock.json index 69d6155f..9ea84263 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3425,9 +3425,9 @@ "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" }, "clipboard": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz", - "integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz", + "integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==", "requires": { "good-listener": "^1.2.2", "select": "^1.1.2", @@ -3875,6 +3875,52 @@ "warning": "^4.0.3" } }, + "cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "requires": { + "cross-spawn": "^7.0.1" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "cross-fetch": { "version": "3.1.4", "resolved": "https://registry.nlark.com/cross-fetch/download/cross-fetch-3.1.4.tgz", @@ -4885,7 +4931,7 @@ }, "dom-closest": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-closest/-/dom-closest-0.2.0.tgz", + "resolved": "https://registry.npm.taobao.org/dom-closest/download/dom-closest-0.2.0.tgz", "integrity": "sha1-69n5HRvyLo1vR3h2u80+yQIWwM8=", "requires": { "dom-matches": ">=1.0.1" @@ -4929,7 +4975,7 @@ }, "dom-matches": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-matches/-/dom-matches-2.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/dom-matches/download/dom-matches-2.0.0.tgz", "integrity": "sha1-0nKLQWqHUzmA6wibhI0lPPI6dYw=" }, "dom-scroll-into-view": { @@ -5187,7 +5233,7 @@ }, "enquire.js": { "version": "2.1.6", - "resolved": "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz", + "resolved": "https://registry.npm.taobao.org/enquire.js/download/enquire.js-2.1.6.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fenquire.js%2Fdownload%2Fenquire.js-2.1.6.tgz", "integrity": "sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ=" }, "entities": { @@ -5706,7 +5752,7 @@ }, "eventlistener": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/eventlistener/-/eventlistener-0.0.1.tgz", + "resolved": "https://registry.npm.taobao.org/eventlistener/download/eventlistener-0.0.1.tgz", "integrity": "sha1-7Suqu4UiJ68rz4iRUscsY8pTLrg=" }, "events": { @@ -8040,7 +8086,7 @@ }, "hammerjs": { "version": "2.0.8", - "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", + "resolved": "https://registry.npm.taobao.org/hammerjs/download/hammerjs-2.0.8.tgz", "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=" }, "handle-thing": { @@ -8881,7 +8927,7 @@ }, "immutable": { "version": "3.7.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", + "resolved": "https://registry.npm.taobao.org/immutable/download/immutable-3.7.6.tgz", "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" }, "import-fresh": { @@ -10486,7 +10532,7 @@ }, "lodash.throttle": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "resolved": "https://registry.npm.taobao.org/lodash.throttle/download/lodash.throttle-4.1.1.tgz", "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" }, "lodash.uniq": { @@ -16586,6 +16632,11 @@ } } }, + "save-dev": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/save-dev/-/save-dev-0.0.1-security.tgz", + "integrity": "sha512-k6knZTDNK8PKKbIqnvxiOveJinuw2LcQjqDoaorZWP9M5AR2EPsnpDeSbeoZZ0pHr5ze1uoaKdK8NBGQrJ34Uw==" + }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", diff --git a/package.json b/package.json index b58b501d..04142cb4 100644 --- a/package.json +++ b/package.json @@ -22,10 +22,11 @@ "case-sensitive-paths-webpack-plugin": "2.1.1", "chalk": "1.1.3", "classnames": "^2.2.5", - "clipboard": "^2.0.6", + "clipboard": "^2.0.8", "code-prettify": "^0.1.0", "codemirror": "^5.53.0", "connected-react-router": "4.4.1", + "cross-env": "^7.0.3", "css-loader": "^3.5.2", "dompurify": "^2.0.15", "dotenv": "4.0.0", @@ -103,6 +104,7 @@ "redux-thunk": "2.3.0", "rsuite": "^4.3.4", "sass-loader": "7.3.1", + "save-dev": "0.0.1-security", "scroll-into-view": "^1.14.2", "showdown": "^1.9.1", "showdown-katex": "^0.8.0", @@ -122,8 +124,8 @@ }, "scripts": { "start": "node --max_old_space_size=15360 scripts/start.js", - "build": "NODE_ENV=production node --max_old_space_size=15360 scripts/build.js", - "test-build": "NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js", + "build": "cross-env NODE_ENV=production node --max_old_space_size=15360 scripts/build.js", + "test-build": "cross-env NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js", "pre-build": "NODE_ENV=preBuild node --max_old_space_size=15360 scripts/build.js", "gen_stats": "NODE_ENV=production webpack --profile --config=./config/webpack.config.prod.js --json > stats.json", "ana": "webpack-bundle-analyzer ./stats.json", @@ -193,6 +195,7 @@ "babel-core": "^6.26.0", "babel-plugin-import": "^1.13.0", "babel-plugin-transform-runtime": "^6.23.0", + "babel-polyfill": "^6.26.0", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", "babel-preset-stage-2": "^6.24.1", diff --git a/public/css/edu-purge.css b/public/css/edu-purge.css index 5011767d..0d146204 100644 --- a/public/css/edu-purge.css +++ b/public/css/edu-purge.css @@ -1,3 +1,4 @@ +@charset "utf-8"; /* 头部 */ .header { width: 100%; @@ -1271,7 +1272,7 @@ html body { font-size: 14px; line-height: 2.0; background: #fafafa; - font-family: "微软雅黑", "宋体"; + font-family: "Microsoft YaHei", "SimSun"; color: #05101a; height: 100%; position: relative; @@ -1307,6 +1308,7 @@ td, span { margin: 0; padding: 0; + margin-bottom: 0px!important; } table, @@ -1363,10 +1365,6 @@ a:visited { color: #05101a; } -a:hover { - color: #2A61FF!important; -} - ol, ul, li { @@ -1522,7 +1520,15 @@ a.edu-txt-w80, .font-16 { font-size: 16px !important; } - +.weight400{ + font-weight: 400; +} +.weight500{ + font-weight: 500; +} +.weight{ + font-weight: bold; +} .font-17 { font-size: 17px !important; } @@ -1542,6 +1548,9 @@ a.edu-txt-w80, .font-25 { font-size: 25px !important; } +.font-26 { + font-size: 26px !important; +} .font-24 { font-size: 24px !important; @@ -1563,6 +1572,9 @@ a.edu-txt-w80, font-size: 36px !important; } +.font-40 { + font-size: 40px !important; +} .font-50 { font-size: 50px !important; } @@ -1748,6 +1760,14 @@ a.decoration { margin-bottom: 10px; } +.mb12 { + margin-bottom: 12px; +} + +.mb13 { + margin-bottom: 13px; +} + .mb14 { margin-bottom: 14px; } @@ -2436,7 +2456,11 @@ a.hoverLine:hover{ .color-grey-9 { - color: #999999 !important; + color: #999 !important; +} + +a:hover{ + color: #466AFF !important; } .color-grey-98 { @@ -2480,12 +2504,9 @@ a.color-grey-3:hover,a.color-ooo:hover { color: #2A61FF !important; } .color-blue-file { - color: #0054CC!important; + color: #4598FA!important; } /* 绿色 */ -.color-green-file{ - color: #28BD6C; -} /*主*/ .color-blue_4C { color: #4CACFF !important; diff --git a/public/css/iconfont.css b/public/css/iconfont.css index a15df586..3866189c 100644 --- a/public/css/iconfont.css +++ b/public/css/iconfont.css @@ -1,8 +1,8 @@ @font-face { font-family: "iconfont"; /* Project id 2340181 */ - src: url('iconfont.woff2?t=1628841816999') format('woff2'), - url('iconfont.woff?t=1628841816999') format('woff'), - url('iconfont.ttf?t=1628841816999') format('truetype'); + src: url('iconfont.woff2?t=1632964996877') format('woff2'), + url('iconfont.woff?t=1632964996877') format('woff'), + url('iconfont.ttf?t=1632964996877') format('truetype'); } .iconfont { @@ -13,6 +13,222 @@ -moz-osx-font-smoothing: grayscale; } +.icon-wenjian7:before { + content: "\e8e0"; +} + +.icon-xiangyoujiantou:before { + content: "\e8de"; +} + +.icon-xiangzuojiantou:before { + content: "\e8df"; +} + +.icon-a-liulanicon2x:before { + content: "\e8dd"; +} + +.icon-wenjianicon:before { + content: "\e8dc"; +} + +.icon-a-yuanquan2x:before { + content: "\e8db"; +} + +.icon-xiangmubiaoqian:before { + content: "\e8da"; +} + +.icon-icon:before { + content: "\e8ce"; +} + +.icon-tar:before { + content: "\e8cf"; +} + +.icon-a-fuzhi2:before { + content: "\e8d0"; +} + +.icon-fujian1:before { + content: "\e8d1"; +} + +.icon-a-bianji1:before { + content: "\e8d2"; +} + +.icon-banbenicon:before { + content: "\e8d3"; +} + +.icon-shanchuicon2:before { + content: "\e8d4"; +} + +.icon-a-lajitong_icon3x:before { + content: "\e8d5"; +} + +.icon-xialaanniu2:before { + content: "\e8d6"; +} + +.icon-xiazai-icon:before { + content: "\e8d7"; +} + +.icon-master_icon1:before { + content: "\e8d8"; +} + +.icon-shangchuanicon:before { + content: "\e8d9"; +} + +.icon-gerenziliao1:before { + content: "\e8c7"; +} + +.icon-lichengbeiicon:before { + content: "\e885"; +} + +.icon-cangkushezhiicon:before { + content: "\e889"; +} + +.icon-dongtaiicon:before { + content: "\e88a"; +} + +.icon-gongzuoliuicon:before { + content: "\e88b"; +} + +.icon-yixiuicon1:before { + content: "\e89b"; +} + +.icon-a-wikiicon1:before { + content: "\e8c6"; +} + +.icon-daimakuicon1:before { + content: "\e8c5"; +} + +.icon-wodetongzhi:before { + content: "\e8c8"; +} + +.icon-tongzhiguanli:before { + content: "\e8c9"; +} + +.icon-xuanzhong3:before { + content: "\e8ca"; +} + +.icon-xitongtongzhiicon:before { + content: "\e8cb"; +} + +.icon-xiaoxi2:before { + content: "\e8cc"; +} + +.icon-sshmiyue:before { + content: "\e8cd"; +} + +.icon-gerenziliao:before { + content: "\e8c4"; +} + +.icon-xinshouzhiyin:before { + content: "\e8e4"; +} + +.icon-xinjianxiangmu:before { + content: "\e8e6"; +} + +.icon-jiaruketang1:before { + content: "\e8e9"; +} + +.icon-xiangmugonggao:before { + content: "\e8c2"; +} + +.icon-chengguo:before { + content: "\e8c3"; +} + +.icon-chengjiaogonggao:before { + content: "\e8c0"; +} + +.icon-jishuzichan:before { + content: "\e8c1"; +} + +.icon-feibiaogonggao:before { + content: "\e8bc"; +} + +.icon-zhongbiaogonggao:before { + content: "\e8bd"; +} + +.icon-gengzhenggonggao:before { + content: "\e8be"; +} + +.icon-zhaobiaogonggao:before { + content: "\e8bf"; +} + +.icon-wenjian6:before { + content: "\e8ba"; +} + +.icon-wenjianjia4:before { + content: "\e8bb"; +} + +.icon-quxiaoguanzhu:before { + content: "\e89a"; +} + +.icon-dianzan_icon:before { + content: "\e8a2"; +} + +.icon-wenjian5:before { + content: "\e896"; +} + +.icon-wenjianjia3:before { + content: "\e8a9"; +} + +.icon-fuzhiicon:before { + content: "\e886"; +} + +.icon-zhuye-fill:before { + content: "\e876"; +} + +.icon-daimakuicon:before { + content: "\e884"; +} + .icon-xinjian2:before { content: "\e8b0"; } @@ -29,22 +245,6 @@ content: "\e8a6"; } -.icon-dianzan_icon:before { - content: "\e8ba"; -} - -.icon-quxiaoguanzhu:before { - content: "\e8bb"; -} - -.icon-daimakuicon:before { - content: "\e8a9"; -} - -.icon-zhuyeicon:before { - content: "\e884"; -} - .icon-biaoqianicon:before { content: "\e882"; } @@ -53,14 +253,6 @@ content: "\e883"; } -.icon-cangkushezhiicon:before { - content: "\e885"; -} - -.icon-fuzhiicon:before { - content: "\e886"; -} - .icon-lianjieicon:before { content: "\e887"; } @@ -69,18 +261,6 @@ content: "\e888"; } -.icon-lichengbeiicon:before { - content: "\e889"; -} - -.icon-gongzuoliuicon:before { - content: "\e88a"; -} - -.icon-dongtaiicon:before { - content: "\e88b"; -} - .icon-morendianzan_icon:before { content: "\e88e"; } @@ -93,10 +273,6 @@ content: "\e899"; } -.icon-wenjian5:before { - content: "\e89a"; -} - .icon-tijiaoicon:before { content: "\e89e"; } @@ -105,10 +281,6 @@ content: "\e89f"; } -.icon-wenjianjia3:before { - content: "\e8a2"; -} - .icon-xialaanniu1:before { content: "\e8a4"; } @@ -193,10 +365,6 @@ content: "\e898"; } -.icon-weixuanzhongqingqiuicon:before { - content: "\e89b"; -} - .icon-xiezuozheguanliicon:before { content: "\e8a1"; } @@ -241,10 +409,6 @@ content: "\e875"; } -.icon-fuzhi_icon:before { - content: "\e876"; -} - .icon-shanchuicon:before { content: "\e877"; } diff --git a/public/css/iconfont.js b/public/css/iconfont.js index 94af421b..0e23ffb8 100644 --- a/public/css/iconfont.js +++ b/public/css/iconfont.js @@ -1 +1 @@ -!function(c){var l,a,h,i,o,z='',t=(t=document.getElementsByTagName("script"))[t.length-1].getAttribute("data-injectcss"),p=function(c,l){l.parentNode.insertBefore(c,l)};if(t&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}function v(){o||(o=!0,h())}function m(){try{i.documentElement.doScroll("left")}catch(c){return void setTimeout(m,50)}v()}l=function(){var c,l;(l=document.createElement("div")).innerHTML=z,z=null,(c=l.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",l=c,(c=document.body).firstChild?p(l,c.firstChild):c.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(l,0):(a=function(){document.removeEventListener("DOMContentLoaded",a,!1),l()},document.addEventListener("DOMContentLoaded",a,!1)):document.attachEvent&&(h=l,i=c.document,o=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,v())})}(window); +!function(c){var a,l,h,i,o,z='',t=(t=document.getElementsByTagName("script"))[t.length-1].getAttribute("data-injectcss"),p=function(c,a){a.parentNode.insertBefore(c,a)};if(t&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}function v(){o||(o=!0,h())}function m(){try{i.documentElement.doScroll("left")}catch(c){return void setTimeout(m,50)}v()}a=function(){var c,a;(a=document.createElement("div")).innerHTML=z,z=null,(c=a.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",a=c,(c=document.body).firstChild?p(a,c.firstChild):c.appendChild(a))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(a,0):(l=function(){document.removeEventListener("DOMContentLoaded",l,!1),a()},document.addEventListener("DOMContentLoaded",l,!1)):document.attachEvent&&(h=a,i=c.document,o=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,v())})}(window); \ No newline at end of file diff --git a/public/css/iconfont.json b/public/css/iconfont.json index 7f25b322..5acfb6e9 100644 --- a/public/css/iconfont.json +++ b/public/css/iconfont.json @@ -5,6 +5,384 @@ "css_prefix_text": "icon-", "description": "", "glyphs": [ + { + "icon_id": "24656750", + "name": "文件", + "font_class": "wenjian7", + "unicode": "e8e0", + "unicode_decimal": 59616 + }, + { + "icon_id": "630094", + "name": "向右箭头", + "font_class": "xiangyoujiantou", + "unicode": "e8de", + "unicode_decimal": 59614 + }, + { + "icon_id": "630095", + "name": "向左箭头", + "font_class": "xiangzuojiantou", + "unicode": "e8df", + "unicode_decimal": 59615 + }, + { + "icon_id": "24600282", + "name": "浏览icon@2x", + "font_class": "a-liulanicon2x", + "unicode": "e8dd", + "unicode_decimal": 59613 + }, + { + "icon_id": "24567893", + "name": "文件icon", + "font_class": "wenjianicon", + "unicode": "e8dc", + "unicode_decimal": 59612 + }, + { + "icon_id": "24527422", + "name": "圆圈@2x", + "font_class": "a-yuanquan2x", + "unicode": "e8db", + "unicode_decimal": 59611 + }, + { + "icon_id": "24378423", + "name": "项目标签", + "font_class": "xiangmubiaoqian", + "unicode": "e8da", + "unicode_decimal": 59610 + }, + { + "icon_id": "24368060", + "name": "icon", + "font_class": "icon", + "unicode": "e8ce", + "unicode_decimal": 59598 + }, + { + "icon_id": "24368061", + "name": "tar", + "font_class": "tar", + "unicode": "e8cf", + "unicode_decimal": 59599 + }, + { + "icon_id": "24289113", + "name": "复制 (2)", + "font_class": "a-fuzhi2", + "unicode": "e8d0", + "unicode_decimal": 59600 + }, + { + "icon_id": "24289114", + "name": "附件", + "font_class": "fujian1", + "unicode": "e8d1", + "unicode_decimal": 59601 + }, + { + "icon_id": "24289115", + "name": "编 辑", + "font_class": "a-bianji1", + "unicode": "e8d2", + "unicode_decimal": 59602 + }, + { + "icon_id": "24289116", + "name": "版本icon", + "font_class": "banbenicon", + "unicode": "e8d3", + "unicode_decimal": 59603 + }, + { + "icon_id": "24289117", + "name": "删除icon", + "font_class": "shanchuicon2", + "unicode": "e8d4", + "unicode_decimal": 59604 + }, + { + "icon_id": "24289118", + "name": "垃圾桶_icon@3x", + "font_class": "a-lajitong_icon3x", + "unicode": "e8d5", + "unicode_decimal": 59605 + }, + { + "icon_id": "24289119", + "name": "下拉按钮", + "font_class": "xialaanniu2", + "unicode": "e8d6", + "unicode_decimal": 59606 + }, + { + "icon_id": "24289120", + "name": "下载-icon", + "font_class": "xiazai-icon", + "unicode": "e8d7", + "unicode_decimal": 59607 + }, + { + "icon_id": "24289121", + "name": "master_icon", + "font_class": "master_icon1", + "unicode": "e8d8", + "unicode_decimal": 59608 + }, + { + "icon_id": "24289122", + "name": "上传icon", + "font_class": "shangchuanicon", + "unicode": "e8d9", + "unicode_decimal": 59609 + }, + { + "icon_id": "24059956", + "name": "个人资料", + "font_class": "gerenziliao1", + "unicode": "e8c7", + "unicode_decimal": 59591 + }, + { + "icon_id": "24059409", + "name": "里程碑icon", + "font_class": "lichengbeiicon", + "unicode": "e885", + "unicode_decimal": 59525 + }, + { + "icon_id": "24059410", + "name": "仓库设置icon", + "font_class": "cangkushezhiicon", + "unicode": "e889", + "unicode_decimal": 59529 + }, + { + "icon_id": "24059411", + "name": "动态icon", + "font_class": "dongtaiicon", + "unicode": "e88a", + "unicode_decimal": 59530 + }, + { + "icon_id": "24059412", + "name": "工作流icon", + "font_class": "gongzuoliuicon", + "unicode": "e88b", + "unicode_decimal": 59531 + }, + { + "icon_id": "24059413", + "name": "易修icon", + "font_class": "yixiuicon1", + "unicode": "e89b", + "unicode_decimal": 59547 + }, + { + "icon_id": "24059414", + "name": "wiki icon", + "font_class": "a-wikiicon1", + "unicode": "e8c6", + "unicode_decimal": 59590 + }, + { + "icon_id": "24047186", + "name": "代码库icon", + "font_class": "daimakuicon1", + "unicode": "e8c5", + "unicode_decimal": 59589 + }, + { + "icon_id": "24047189", + "name": "我的通知", + "font_class": "wodetongzhi", + "unicode": "e8c8", + "unicode_decimal": 59592 + }, + { + "icon_id": "24047190", + "name": "通知管理", + "font_class": "tongzhiguanli", + "unicode": "e8c9", + "unicode_decimal": 59593 + }, + { + "icon_id": "24047191", + "name": "选中", + "font_class": "xuanzhong3", + "unicode": "e8ca", + "unicode_decimal": 59594 + }, + { + "icon_id": "24047192", + "name": "系统通知icon", + "font_class": "xitongtongzhiicon", + "unicode": "e8cb", + "unicode_decimal": 59595 + }, + { + "icon_id": "24047193", + "name": "消息", + "font_class": "xiaoxi2", + "unicode": "e8cc", + "unicode_decimal": 59596 + }, + { + "icon_id": "24047194", + "name": "ssh密钥", + "font_class": "sshmiyue", + "unicode": "e8cd", + "unicode_decimal": 59597 + }, + { + "icon_id": "24014152", + "name": "个人资料", + "font_class": "gerenziliao", + "unicode": "e8c4", + "unicode_decimal": 59588 + }, + { + "icon_id": "23655968", + "name": "新手指引", + "font_class": "xinshouzhiyin", + "unicode": "e8e4", + "unicode_decimal": 59620 + }, + { + "icon_id": "23655969", + "name": "新建项目", + "font_class": "xinjianxiangmu", + "unicode": "e8e6", + "unicode_decimal": 59622 + }, + { + "icon_id": "23658111", + "name": "加入课堂", + "font_class": "jiaruketang1", + "unicode": "e8e9", + "unicode_decimal": 59625 + }, + { + "icon_id": "23791639", + "name": "项目公告", + "font_class": "xiangmugonggao", + "unicode": "e8c2", + "unicode_decimal": 59586 + }, + { + "icon_id": "23791640", + "name": "成果", + "font_class": "chengguo", + "unicode": "e8c3", + "unicode_decimal": 59587 + }, + { + "icon_id": "23791410", + "name": "成交公告", + "font_class": "chengjiaogonggao", + "unicode": "e8c0", + "unicode_decimal": 59584 + }, + { + "icon_id": "23791411", + "name": "技术资产", + "font_class": "jishuzichan", + "unicode": "e8c1", + "unicode_decimal": 59585 + }, + { + "icon_id": "23790928", + "name": "废标公告", + "font_class": "feibiaogonggao", + "unicode": "e8bc", + "unicode_decimal": 59580 + }, + { + "icon_id": "23790929", + "name": "中标公告", + "font_class": "zhongbiaogonggao", + "unicode": "e8bd", + "unicode_decimal": 59581 + }, + { + "icon_id": "23790930", + "name": "更正公告", + "font_class": "gengzhenggonggao", + "unicode": "e8be", + "unicode_decimal": 59582 + }, + { + "icon_id": "23790931", + "name": "招标公告", + "font_class": "zhaobiaogonggao", + "unicode": "e8bf", + "unicode_decimal": 59583 + }, + { + "icon_id": "23732532", + "name": "文件", + "font_class": "wenjian6", + "unicode": "e8ba", + "unicode_decimal": 59578 + }, + { + "icon_id": "23732533", + "name": "文件夹", + "font_class": "wenjianjia4", + "unicode": "e8bb", + "unicode_decimal": 59579 + }, + { + "icon_id": "23642443", + "name": "取消关注", + "font_class": "quxiaoguanzhu", + "unicode": "e89a", + "unicode_decimal": 59546 + }, + { + "icon_id": "23642444", + "name": "点赞_icon", + "font_class": "dianzan_icon", + "unicode": "e8a2", + "unicode_decimal": 59554 + }, + { + "icon_id": "23639530", + "name": "文件", + "font_class": "wenjian5", + "unicode": "e896", + "unicode_decimal": 59542 + }, + { + "icon_id": "23639533", + "name": "文件夹", + "font_class": "wenjianjia3", + "unicode": "e8a9", + "unicode_decimal": 59561 + }, + { + "icon_id": "23639440", + "name": "复制icon", + "font_class": "fuzhiicon", + "unicode": "e886", + "unicode_decimal": 59526 + }, + { + "icon_id": "23639422", + "name": "主页-fill", + "font_class": "zhuye-fill", + "unicode": "e876", + "unicode_decimal": 59510 + }, + { + "icon_id": "23639423", + "name": "代码库icon", + "font_class": "daimakuicon", + "unicode": "e884", + "unicode_decimal": 59524 + }, { "icon_id": "23572260", "name": "新建", @@ -33,34 +411,6 @@ "unicode": "e8a6", "unicode_decimal": 59558 }, - { - "icon_id": "23492900", - "name": "点赞_icon", - "font_class": "dianzan_icon", - "unicode": "e8ba", - "unicode_decimal": 59578 - }, - { - "icon_id": "23492901", - "name": "取消关注", - "font_class": "quxiaoguanzhu", - "unicode": "e8bb", - "unicode_decimal": 59579 - }, - { - "icon_id": "23473151", - "name": "代码库icon", - "font_class": "daimakuicon", - "unicode": "e8a9", - "unicode_decimal": 59561 - }, - { - "icon_id": "23473104", - "name": "主页icon", - "font_class": "zhuyeicon", - "unicode": "e884", - "unicode_decimal": 59524 - }, { "icon_id": "23472253", "name": "标签icon", @@ -75,20 +425,6 @@ "unicode": "e883", "unicode_decimal": 59523 }, - { - "icon_id": "23472256", - "name": "仓库设置icon", - "font_class": "cangkushezhiicon", - "unicode": "e885", - "unicode_decimal": 59525 - }, - { - "icon_id": "23472257", - "name": "复制icon", - "font_class": "fuzhiicon", - "unicode": "e886", - "unicode_decimal": 59526 - }, { "icon_id": "23472258", "name": "链接icon", @@ -103,27 +439,6 @@ "unicode": "e888", "unicode_decimal": 59528 }, - { - "icon_id": "23472260", - "name": "里程碑icon", - "font_class": "lichengbeiicon", - "unicode": "e889", - "unicode_decimal": 59529 - }, - { - "icon_id": "23472261", - "name": "工作流icon", - "font_class": "gongzuoliuicon", - "unicode": "e88a", - "unicode_decimal": 59530 - }, - { - "icon_id": "23472262", - "name": "动态icon", - "font_class": "dongtaiicon", - "unicode": "e88b", - "unicode_decimal": 59531 - }, { "icon_id": "23472263", "name": "默认点赞_icon", @@ -145,13 +460,6 @@ "unicode": "e899", "unicode_decimal": 59545 }, - { - "icon_id": "23472268", - "name": "文件", - "font_class": "wenjian5", - "unicode": "e89a", - "unicode_decimal": 59546 - }, { "icon_id": "23472269", "name": "提交icon", @@ -166,13 +474,6 @@ "unicode": "e89f", "unicode_decimal": 59551 }, - { - "icon_id": "23472271", - "name": "文件夹", - "font_class": "wenjianjia3", - "unicode": "e8a2", - "unicode_decimal": 59554 - }, { "icon_id": "23472272", "name": "下拉按钮", @@ -320,13 +621,6 @@ "unicode": "e898", "unicode_decimal": 59544 }, - { - "icon_id": "23144155", - "name": "未选中请求icon", - "font_class": "weixuanzhongqingqiuicon", - "unicode": "e89b", - "unicode_decimal": 59547 - }, { "icon_id": "23144158", "name": "协作者管理icon", @@ -404,13 +698,6 @@ "unicode": "e875", "unicode_decimal": 59509 }, - { - "icon_id": "23046262", - "name": "复制_icon", - "font_class": "fuzhi_icon", - "unicode": "e876", - "unicode_decimal": 59510 - }, { "icon_id": "23046268", "name": "删除icon", diff --git a/public/css/iconfont.ttf b/public/css/iconfont.ttf index 484348ba..cffaad68 100644 Binary files a/public/css/iconfont.ttf and b/public/css/iconfont.ttf differ diff --git a/public/css/iconfont.woff b/public/css/iconfont.woff index bfdd0b9c..af2a764e 100644 Binary files a/public/css/iconfont.woff and b/public/css/iconfont.woff differ diff --git a/public/css/iconfont.woff2 b/public/css/iconfont.woff2 index 386dde00..7d4cb19b 100644 Binary files a/public/css/iconfont.woff2 and b/public/css/iconfont.woff2 differ diff --git a/public/js/editormd/editormd.min.js b/public/js/editormd/editormd.min.js index 0add3b37..860a4de0 100755 --- a/public/js/editormd/editormd.min.js +++ b/public/js/editormd/editormd.min.js @@ -3319,9 +3319,9 @@ text = text.replace(emailReg, function ($1, $2, $3, $4) { return $1.replace(/@/g, "_#_@_#_"); }); - + // " + editormd.urls.atLinkBase + "" + $2 + " text = text.replace(atLinkReg, function ($1, $2) { - return "" + $1 + ""; + return " " + $1 + " "; }).replace(/_#_@_#_/g, "@"); } diff --git a/src/App.js b/src/App.js index e6f1fc3e..3072aca5 100644 --- a/src/App.js +++ b/src/App.js @@ -3,7 +3,7 @@ import './App.css'; import { ConfigProvider } from 'antd' import zhCN from 'antd/lib/locale-provider/zh_CN'; import { - BrowserRouter as Router, + // BrowserRouter as Router, Route, Switch } from 'react-router-dom'; @@ -19,7 +19,7 @@ import moment from 'moment' import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles'; import SiderBar from './forge/Component/SiderBar' -import { SnackbarHOC } from 'educoder' +import { SnackbarHOC } from 'educoder'; import { initAxiosInterceptors } from './AppConfig' import { Provider } from 'react-redux'; import configureStore from './redux/stores/configureStore'; @@ -39,6 +39,11 @@ const Projects = Loadable({ loader: () => import('./forge/Index'), loading: Loading, }) +// forge项目详情 +const ProjectDetail = Loadable({ + loader: () => import("./forge/Main/DetailAdaptor"), + loading: Loading, +}); //forge安全设置 const Security = Loadable({ loader: () => import('./forge/SecuritySetting/Index'), @@ -91,6 +96,15 @@ const ProjectIndex = Loadable({ loader: () => import("./forge/Index"), loading: Loading, }); + +// const CreateMerge = Loadable({ +// loader: () => import('./forge/Merge/NewMerge'), +// loading: Loading, +// }) + +// 此处仅维护前端可能的一级路由,不用进行项目或者组织判断的字段。 +const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize"]; + class App extends Component { constructor(props) { super(props); @@ -100,6 +114,51 @@ class App extends Component { mydisplay: false, occupation: 0, mygetHelmetapi: null, + pathType: null, + pathName: null, + } + } + + UNSAFE_componentWillMount() { + initAxiosInterceptors(this.props); + let pathname = window.location.pathname ? window.location.pathname.split('/')[1] : ''; + pathname && this.getPathnameType(pathname); + + // 添加路由监听,决定组织还是个人 + this.unlisten = this.props.history.listen((location) => { + let newPathname = location.pathname.split('/')[1]; + if (this.state.pathName !== newPathname) { + // this.setState({ pathType: '' }); + newPathname && this.getPathnameType(newPathname); + } + }); + } + + shouldComponentUpdate(nextProps, nextState) { + // (!keyWord.includes(this.props.location.pathname.split('/')[1])) && + if (nextProps.location.pathname.split('/')[1] !== this.props.location.pathname.split('/')[1] && nextState.pathType === this.state.pathType) { + return false; + } else { + return true; + } + } + + getPathnameType = (pathname) => { + if (!keyWord.includes(pathname)) { + let url = `/owners/${pathname}.json`; + axios.get(url).then((response) => { + if (response && response.status === 200) { + this.setState({ + pathType: response.data.type || '404', + pathName: pathname, + }) + } + }); + }else{ + this.setState({ + pathType: pathname, + pathName: pathname, + }); } } @@ -119,13 +178,19 @@ class App extends Component { componentDidMount() { document.title = "loading..."; - initAxiosInterceptors(this.props); + this.getAppdata(); window.addEventListener('error', (event) => { const msg = `${event.type}: ${event.message}`; }); + } + + componentWillUnmount() { + this.unlisten && this.unlisten(); // 执行解绑 + } + //修改登录方法 Modifyloginvalue = () => { this.setState({ @@ -196,7 +261,7 @@ class App extends Component { }; render() { - const { mygetHelmetapi } = this.state; + const { mygetHelmetapi, pathType} = this.state; let personal = mygetHelmetapi && mygetHelmetapi.personal; return ( @@ -204,87 +269,131 @@ class App extends Component { this.Modifyloginvalue()}> - - - {/* wiki预览 */} - */} + + {/* wiki预览 */} + { + return () + } + } /> + + {/* 项目PR */} + () + } + > + + {/*项目*/} + { - return () + return () } - } /> - - {/*项目*/} - { - return () - } - }> - - { - return () - } - }> - - {/*项目*/} - { - return () - } - }> - - { - return () - } + }> + + { + return () } - /> - {/*403*/} - + }> + - - { - return () - } - }> - - {/*404*/} - - - {/* 查询 */} - - - - {/* 个人主页 */} - { - return () - } - }> - ( - personal && personal.length > 0 ? - - : - - ) + { + return () } - /> - - - + } + /> + {/*403*/} + + + + + {/*404*/} + + + {/* 查询 */} + + + ( + + ) + } + /> + + + {/* 组织 */} + { + return () + } + }> + + + {/*新建项目等*/} + { + return () + } + }> + + + {/* 判断为用户/组织,并进入对应页面 */} + { + pathType === 'User' ? + { + return () + } + } + /> : pathType === 'Organization' ? { + return () + } + }> + : pathType === '404' ? : + ( + personal && personal.length > 0 ? + + : + + ) + } + /> + // + // + } + + + + {/* 个人主页 */} + { + return () + } + }> + + + + + {/* */} diff --git a/src/AppConfig.js b/src/AppConfig.js index 034612ec..ea85a4e5 100644 --- a/src/AppConfig.js +++ b/src/AppConfig.js @@ -85,7 +85,10 @@ export function initAxiosInterceptors(props) { } if (response.data.status === 404) { - locationurl('/nopage'); + let responseURL = response.request ? response.request.responseURL:''; + if (responseURL.indexOf('/api/users/') === -1 && responseURL.indexOf('/api/organizations/') === -1 ) { + locationurl('/nopage'); + } } if (response.data.status === 500) { diff --git a/src/college/College.js b/src/college/College.js index 85d43fb7..f7a3ab6c 100644 --- a/src/college/College.js +++ b/src/college/College.js @@ -195,7 +195,7 @@ class College extends Component { align: 'center', className: "edu-txt-center font-14 maxnamewidth105", render: (text, record) => ( - { diff --git a/src/common/DateUtil.js b/src/common/DateUtil.js index 630b2d7d..8846d274 100644 --- a/src/common/DateUtil.js +++ b/src/common/DateUtil.js @@ -107,7 +107,7 @@ export function timeAgo(backDate) { try { moment(backDate); } catch (e) { - return; + return '刚刚'; } if(typeof backDate ==='number'){ backDate=backDate*1000 @@ -134,4 +134,5 @@ export function timeAgo(backDate) { if (seconds) { return seconds + "秒前"; } + return "刚刚"; } \ No newline at end of file diff --git a/src/common/TextUtil.js b/src/common/TextUtil.js index 94e73631..d1aa0e9c 100644 --- a/src/common/TextUtil.js +++ b/src/common/TextUtil.js @@ -69,7 +69,7 @@ export function appendFileSizeToUploadFile(item) { } export function appendFileSizeToUploadFileAll(fileList) { return fileList.map(item => { - if (item.name.indexOf(uploadNameSizeSeperator) == -1) { + if (item.name.indexOf(uploadNameSizeSeperator) === -1) { return Object.assign({}, item, { name: `${item.name}${uploadNameSizeSeperator}${bytesToSize(item.size)}` }) } return item diff --git a/src/context/TPIContextProvider.js b/src/context/TPIContextProvider.js index 22b24727..f3ea3e0f 100644 --- a/src/context/TPIContextProvider.js +++ b/src/context/TPIContextProvider.js @@ -435,11 +435,11 @@ class TPIContextProvider extends Component { image_url: "avatars/User/1" login: "innov" name: "Coder" - user_url: "/users/innov" + user_url: "/innov" */ let user = resData.user; user.username = resData.user.name; - user.user_url = `/users/${resData.user.login}`; + user.user_url = `/${resData.user.login}`; // user.image_url = resData.image_url; user.is_teacher = resData.is_teacher; resData.user = user; diff --git a/src/forge/Activity/Activity.js b/src/forge/Activity/Activity.js index 0272f065..4a7a1d34 100644 --- a/src/forge/Activity/Activity.js +++ b/src/forge/Activity/Activity.js @@ -10,6 +10,10 @@ import ActivityItem from './ActivityItem'; import axios from 'axios'; const LIMIT = 15; const ARRAY = [ + { + id:"", + name:'全部' + }, { id:1, name:'1天' @@ -32,10 +36,15 @@ class Activity extends Component{ constructor(props){ super(props); this.state={ - time:'30', + time:undefined, type:undefined, state:undefined, page:1, + pr_count:undefined, + new_pr_count:undefined, + close_issues_count:undefined, + open_issues_count:undefined, + pr_all_count:undefined,issues_count:undefined, data:undefined, project_trends:undefined, @@ -63,8 +72,15 @@ class Activity extends Component{ this.setState({ data:result.data, project_trends:result.data.project_trends, - isSpin:false + isSpin:false, + pr_count:result.data.pr_count, + new_pr_count:result.data.new_pr_count, + close_issues_count:result.data.close_issues_count, + open_issues_count:result.data.open_issues_count, + pr_all_count:result.data.pr_all_count, + issues_count:result.data.issues_count, }) + window.scrollTo(0,0); } }).catch(error=>{ console.log(error); @@ -74,19 +90,19 @@ class Activity extends Component{ // 切换周期 changeTime=(e)=>{ this.setState({ - time:e.key, + time:e.key ==="item_0"?undefined:e.key, isSpin:true }) const { type,status,page } = this.state; - this.getInfo(e.key,type,status,page); + this.getInfo(e.key ==="item_0"?undefined:e.key,type,status,page); } //筛选 changeTrends=(type,status)=>{ this.setState({ - type,status + type,status,page:1 }) - const {time,page}=this.state; - this.getInfo(time,type,status,page); + const {time}=this.state; + this.getInfo(time,type,status,1); } // 分页 ChangePage=(page)=>{ @@ -108,12 +124,14 @@ class Activity extends Component{ ) render(){ - const { time , data , page , project_trends , isSpin } = this.state; + const { time , data , page , project_trends , isSpin , pr_count , new_pr_count , close_issues_count , open_issues_count , pr_all_count ,issues_count } = this.state; + let name = time ? ARRAY.filter(item=>item.id === parseInt(time)) :[{name:"全部"}]; - let name = time && ARRAY.filter(item=>item.id === parseInt(time)) ; - const second_per = (parseInt(data && data.close_issues_count)/parseInt(data && data.issues_count)*100)+'%'; - const third_per = (parseInt(data && data.close_issues_count)/parseInt(data && data.issues_count)*100)+'%'; - const fourth_per = (parseInt(data && data.open_issues_count)/parseInt(data && data.issues_count)*100)+'%'; + const first_per = pr_all_count > 0 ? `${parseFloat(pr_count/pr_all_count).toFixed(2)*100}%` :"50%"; + const second_per =pr_all_count > 0 ? `${parseFloat(new_pr_count/pr_all_count).toFixed(2)*100}%` :"50%"; + const third_per =issues_count > 0 ?`${parseFloat(close_issues_count/issues_count).toFixed(2)*100}%` :"50%"; + const fourth_per =issues_count > 0 ?`${parseFloat(open_issues_count/issues_count).toFixed(2)*100}%` :"50%"; + return(
@@ -122,7 +140,7 @@ class Activity extends Component{
-

+

{data && data.pr_all_count}合并请求 @@ -132,25 +150,25 @@ class Activity extends Component{

- {data && data.issues_count}任务 + {data && data.issues_count}易修
diff --git a/src/forge/Activity/ActivityItem.js b/src/forge/Activity/ActivityItem.js index b726a4af..48a72e79 100644 --- a/src/forge/Activity/ActivityItem.js +++ b/src/forge/Activity/ActivityItem.js @@ -14,25 +14,25 @@ class ActivityItem extends Component { {/* 如果是版本发布 */} {item.trend_type === "VersionRelease" ?

- {item.name} + {item.name} {item.trend_type}

: // 如果是任务 item.trend_type === "Issue" ?

- {item.name} + {item.name} {item.trend_type}

: // 如果是合并请求

- {item.name} + {item.name} {item.trend_type}

}

- + {item.user_name} diff --git a/src/forge/Branch/CloneAddress.js b/src/forge/Branch/CloneAddress.js index 618b5663..c2e6dd74 100644 --- a/src/forge/Branch/CloneAddress.js +++ b/src/forge/Branch/CloneAddress.js @@ -1,16 +1,10 @@ import React, { useState } from 'react'; -import { Dropdown, Menu, Tooltip } from 'antd'; +import { Menu } from 'antd'; import "./branch.scss"; +import CopyTool from '../Component/CopyTool'; function CloneAddress({http_url , ssh_url , zip_url , tar_url}) { const [ key , setKey ] = useState("HTTP"); - // 点击按钮复制功能 - function jsCopy(){ - var e = document.getElementById("copy_rep_content"); - e.select(); - document.execCommand("Copy"); - } - return (

@@ -20,9 +14,7 @@ function CloneAddress({http_url , ssh_url , zip_url , tar_url}) {
- - - +
diff --git a/src/forge/Branch/Select.jsx b/src/forge/Branch/Select.jsx index a44584c4..ff3dd829 100644 --- a/src/forge/Branch/Select.jsx +++ b/src/forge/Branch/Select.jsx @@ -1,34 +1,63 @@ -import React , { useState , useEffect } from 'react'; -import { Popover , Dropdown , Input , Spin } from 'antd'; +import React , { useState , useEffect , useRef } from 'react'; +import { Dropdown} from 'antd'; import './branch.scss'; -import { getBranch , getTag } from '../GetData/getData'; import SelectOverlay from './SelectOverlay'; - +import { findDOMNode } from 'react-dom'; export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true })=>{ const [ showValue , setShowValue ] = useState(branch); + const [ visible , setVisible ] = useState(false); + + const refFa = useRef(null); + const refBox = useRef(null); + + useEffect(() => { + document.addEventListener('click', clickMe , false); + }, []) + + const clickMe = ({ target }) => { + // 查找父组件 + const faComponent = findDOMNode(refFa.current); + const boxComponent = findDOMNode(refBox.current); + + if (faComponent && boxComponent) { + const isChild = faComponent.contains(target); + const isBox = boxComponent.contains(target); + if(!isChild && !isBox){ + setVisible(false); + } + } + } useEffect(()=>{ setShowValue(branch); },[branch]) + function ChangeB(params) { + setVisible(false); + changeBranch(params); + } + const menu = ( - + +
); return( - -
+ +
setVisible(visible ? false : true)}> {/* {nav === 0 ?"分支":"标签"} */} - + {showValue} - +
diff --git a/src/forge/Branch/SelectOverlay.jsx b/src/forge/Branch/SelectOverlay.jsx index d536d1c9..0be56732 100644 --- a/src/forge/Branch/SelectOverlay.jsx +++ b/src/forge/Branch/SelectOverlay.jsx @@ -2,7 +2,7 @@ import React , { useState , useEffect } from 'react'; import { Input , Spin , Menu } from 'antd'; import { getBranch , getTag } from '../GetData/getData'; -function SelectOverlay({ changeBranch , tagflag , branchList , projectsId , owner }) { +function SelectOverlay({ changeBranch , tagflag , projectsId , owner , visible }) { const [ inputValue , setInputValue] = useState(undefined); const [ nav , setNav ] = useState(0); const [ isSpin , setIsSpin ] = useState(true); @@ -12,12 +12,12 @@ function SelectOverlay({ changeBranch , tagflag , branchList , projectsId , owne const [ keys ,setKeys] = useState("branch"); useEffect(()=>{ - if(branchList){ - setData(branchList); - setDatas(branchList); - setIsSpin(false); + if(visible){ + setKeys("branch"); + getBranchs(projectsId,owner); + setIsSpin(true); } - },[branchList]) + },[visible]) async function getBranchs(id,owner){ let result = await getBranch(id,owner); @@ -45,8 +45,10 @@ function SelectOverlay({ changeBranch , tagflag , branchList , projectsId , owne setIsSpin(true); if(e.key === "branch"){ getBranchs(projectsId,owner); + setNav(0); }else{ getTags(projectsId,owner); + setNav(1); } } @@ -55,7 +57,7 @@ function SelectOverlay({ changeBranch , tagflag , branchList , projectsId , owne
} - placeholder="请输入分支或标签名称搜索" + placeholder={`请输入分支${tagflag ? "或标签" :""}名称搜索`} autocomplete="off" className="OptionsInput" value={inputValue} onChange={changeInputValue} @@ -68,12 +70,16 @@ function SelectOverlay({ changeBranch , tagflag , branchList , projectsId , owne
    { - datas && datas.length>0 ? + datas && datas.length>0 && datas.map((item,key)=>{ return(
  • chooseitem(item.name)}>{item.name}
  • ) - }): + }) + + } + { + datas && datas.length === 0 &&

    暂无{inputValue}{nav === 0 ?"分支":"标签"}~

    }
diff --git a/src/forge/Branch/branch.scss b/src/forge/Branch/branch.scss index 447b2cee..030b05cd 100644 --- a/src/forge/Branch/branch.scss +++ b/src/forge/Branch/branch.scss @@ -23,6 +23,7 @@ max-height: 300px; } .OptionsUl{ + min-height: 50px; max-height: 220px; overflow-y: auto; } @@ -48,7 +49,7 @@ .branch-tagBox{ border:1px solid #D0D0D0; border-radius: 3px; - height: 36px; + height: 32px; display: flex; align-items: center; cursor: pointer; @@ -87,6 +88,13 @@ line-height: 30px; padding:0px 5px; margin-left: 20px!important; + &.ant-menu-item-selected{ + border-color:#466aff!important; + color:#466aff!important; + } + &.ant-menu-item-active{ + border-color:transparent ; + } } } } @@ -109,10 +117,13 @@ color: #333; } &.ant-menu-item-selected{ - border-color:#1890ff!important; + border-color:#466aff!important; } &.ant-menu-item-active{ border-color:transparent ; } } +} +.copytool{ + margin:0px 10px; } \ No newline at end of file diff --git a/src/forge/Component/AddGroup.jsx b/src/forge/Component/AddGroup.jsx index 656175d5..feff6f37 100644 --- a/src/forge/Component/AddGroup.jsx +++ b/src/forge/Component/AddGroup.jsx @@ -55,6 +55,7 @@ function AddGroup({organizeId,getGroupID}){ function addCollaborator(){ getGroupID && getGroupID(id); + setID(undefined); } return( diff --git a/src/forge/Component/Component.scss b/src/forge/Component/Component.scss index 627304e1..30a62005 100644 --- a/src/forge/Component/Component.scss +++ b/src/forge/Component/Component.scss @@ -162,20 +162,29 @@ li.ant-menu-item{ margin:0px 20px!important; } } - +.hoverA{ + display:flex; + align-items: center; + max-width: 78px; + &:hover a{ + color:#2A61FF !important ; + } +} .menuPanels{ width: 295px; .leftline{ position: relative; color: #666; height: 16px; + margin-left: 14px; + font-size: 12px; &::before{ position: absolute; - left: -10px; + left: -7px; top:3px; height: 12px; width: 1px; - background-color: #666666; + background-color: #999; content: ""; } } @@ -203,9 +212,18 @@ li.ant-menu-item{ background: #F3F4F6; } } + .ant-btn{ + width: 102px; + height: 32px; + line-height: 30px; + } .ant-btn-primary{ color: #fff; - background-color: #2A61FF; + background-color: #466AFF; + border:none; + &:hover{ + background-color: rgba(70,106,255,0.85); + } } .focusPanelHeadInfo{ padding:14px 16px; @@ -228,8 +246,12 @@ li.ant-menu-item{ display: flex; align-items: center; } +.menuMaininfos{ + padding:10px 16px 14px; + border-bottom: 1px solid #eee; +} .menuinfos{ - padding:10px 20px; + padding:10px 20px 16px; &>a{ display: flex; flex-direction: column; diff --git a/src/forge/Component/Contributors.jsx b/src/forge/Component/Contributors.jsx index 9890ea76..e88acc05 100644 --- a/src/forge/Component/Contributors.jsx +++ b/src/forge/Component/Contributors.jsx @@ -46,45 +46,47 @@ function Contributors({contributors,owner,projectsId,currentLogin}){ } } + function renderOrganize(list) { + let str = ""; + list.map(i=>{ + str = str+i.name + "、"; + }) + return str && str.substr(0,str.length - 1); + } + function setMenusFunc(data){ if(data){ let ele = ( - - -
- - {data.name} + + + + +
+ {data.name} + { data.location && {data.location} } { - data.location && - {data.location} + data.organizations && data.organizations.length>0&& +

+ 所属组织:{renderOrganize(data.organizations)} +

} - - { - data.organizations && data.organizations.length > 0 ? - - 所属组织: -
- {renderArray(data.organizations)} -
-
- :"" - } -
-
+
+
+ - + {data.projects_count} 项目数 - - + + {data.followers_count} 粉丝数 - - + + {data.following_count} 关注数 - +
{ @@ -147,7 +149,7 @@ function Contributors({contributors,owner,projectsId,currentLogin}){ return(
- + 贡献者 { contributors && contributors.total_count > 0 && {contributors.total_count}} @@ -157,7 +159,7 @@ function Contributors({contributors,owner,projectsId,currentLogin}){ list.map((item,key)=>{ return( - + setVisibleFunc(true,item.login,key)}/> diff --git a/src/forge/Component/CopyTool.jsx b/src/forge/Component/CopyTool.jsx new file mode 100644 index 00000000..36ed1d8c --- /dev/null +++ b/src/forge/Component/CopyTool.jsx @@ -0,0 +1,51 @@ +import React, { useState, useCallback, memo } from 'react'; +import { Tooltip } from 'antd'; + +CopyTool.defaultProps = { + beforeText: '复制链接', //浮动过去显示的文字 + afterText: '复制成功', //点击后显示的文字 + className: '', //传给svg的class + inputId: 'copyText', //要复制的文本的ID + timeOut:true, //复制后将浮动的文字改为beforeText +}; + + +function CopyTool({ beforeText, afterText, className , inputId , timeOut }) { + const [title, setTitle] = useState(() => { + return beforeText; + }); + + // 复制链接 + const copyUrl = useCallback(() => { + const copyEle = document.querySelector(`#${inputId}`); // 获取要复制的节点 + if (!copyEle) { + console.error("您的CopyTool未设置正确的inputId"); + return; + } + copyEle.select(); // 执行选中元素 + if (document.execCommand('copy')) { + document.execCommand('copy'); + } + document.getSelection().removeAllRanges(); + + setTitle(afterText); + if(timeOut){ + setTimeout(function(){ + setTitle(beforeText); + },1500) + } + }, []); + + return ( + { setTitle(beforeText) }} + > + + + ); +} + + +export default memo(CopyTool); \ No newline at end of file diff --git a/src/forge/Component/DeleteModal/Index.jsx b/src/forge/Component/DeleteModal/Index.jsx index 7e631dac..c3c13689 100644 --- a/src/forge/Component/DeleteModal/Index.jsx +++ b/src/forge/Component/DeleteModal/Index.jsx @@ -1,7 +1,7 @@ import React from 'react'; import { AlignCenter } from '../layout'; -import { Modal , Button } from 'antd'; -import './Index.scss'; +import { Button } from 'antd'; +import Modals from '../PublicModal/Index'; function DeleteBox({ visible , @@ -12,24 +12,22 @@ function DeleteBox({ content }) { return( -
- } + } + onCancel={onCancel} + visible={visible} >
{content} -

{subTitle}

+

{subTitle}

- + ) } export default DeleteBox; \ No newline at end of file diff --git a/src/forge/Component/DeleteModal/Index.scss b/src/forge/Component/DeleteModal/Index.scss deleted file mode 100644 index 7df79ebf..00000000 --- a/src/forge/Component/DeleteModal/Index.scss +++ /dev/null @@ -1,45 +0,0 @@ -.deleteBox{ - .ant-modal-header{ - background-color: #f8f8f8; - border-bottom: none; - .ant-modal-title{ - text-align: left; - font-size: 20px; - } - } - .ant-modal-body{ - padding:30px 50px; - p{ - font-size: 16px; - line-height: 26px; - color:#666; - word-break: break-all; - } - .desc{ - .descMain{ - align-items: center; - justify-content: center; - font-size: 20px; - margin-bottom: 10px; - i{ - font-size: 38px!important; - color:#DF0002 - } - } - } - } - .ant-modal-footer{ - border-top: none; - text-align: center; - padding-bottom: 40px; - button{ - width: 120px; - margin:0px 20px; - &.ant-btn-danger{ - background-color: #fff; - color: #DF0002; - border-color: #D0D0D0; - } - } - } -} \ No newline at end of file diff --git a/src/forge/Component/DrawerPanel.jsx b/src/forge/Component/DrawerPanel.jsx index 0e604d59..fa99e6c6 100644 --- a/src/forge/Component/DrawerPanel.jsx +++ b/src/forge/Component/DrawerPanel.jsx @@ -78,7 +78,7 @@ function DrawerPanel({visible,onClose,branch,owner,projectsId,history, name , li if(dataref.type==="file"){ onClose(); let value = turnbar(branch); - history.push(`/projects/${owner}/${projectsId}/tree/${value}/${dataref.path}`); + history.push(`/${owner}/${projectsId}/tree/${value}/${dataref.path}`); } } diff --git a/src/forge/Component/EAccount.scss b/src/forge/Component/EAccount.scss index d0fd2ef2..6fe44ab3 100644 --- a/src/forge/Component/EAccount.scss +++ b/src/forge/Component/EAccount.scss @@ -1,6 +1,6 @@ .ant-modal-mask{ - z-index: 1001; + z-index: 1031; } .ant-modal-wrap{ - z-index: 1002; + z-index: 1032; } \ No newline at end of file diff --git a/src/forge/Component/MemberCards.jsx b/src/forge/Component/MemberCards.jsx index 393ddbb1..48d90e13 100644 --- a/src/forge/Component/MemberCards.jsx +++ b/src/forge/Component/MemberCards.jsx @@ -45,15 +45,15 @@ const Div = styled.div`{ export default (({ user , img, name, time, focusStatus, is_current_user, login , successFunc }) => { return (
- +
- {name} + {name} { is_current_user ? : - + }
diff --git a/src/forge/Component/ModalFun/index.jsx b/src/forge/Component/ModalFun/index.jsx new file mode 100644 index 00000000..8fee2c73 --- /dev/null +++ b/src/forge/Component/ModalFun/index.jsx @@ -0,0 +1,125 @@ +/* eslint-disable react/jsx-no-duplicate-props */ +import React, { useState } from 'react'; +import * as ReactDOM from 'react-dom'; +import { Modal, Button } from 'antd'; +import './index.scss'; + +// 函数式调用删除、通知等模态框 + +InitModal.defaultProps = { + okText: '确认', //确定按钮的文字 + cancelText: '取消', //取消按钮的文字 + className: '', //传入的模态框类名 + inputId: 'copyText', //要复制的文本的ID + onCancel:()=>{}, //取消的回调 + onOk:()=>{}, //确认的回调 + title:'提示', //模态框名字 + contentTitle:'', //内容标题 + content:'', //详细内容 + afterClose:()=>{}, //关闭模态框以后的回调 +}; + +// 使用函数调用删除组件 +export default function DelModal(props) { + renderModal({ ...props, type: 'delete' }) +} + +// 使用函数调用选择模态框组件 +export function Confirm(props) { + renderModal({ ...props, type: 'confirm' }) +} + +function renderModal(props) { + const { type, afterClose } = props; + const div = document.createElement('div'); + document.body.appendChild(div); + + function destroy() { + afterClose && afterClose(); + const unmountResult = ReactDOM.unmountComponentAtNode(div); + if (unmountResult && div.parentNode) { + div.parentNode.removeChild(div); + } + } + + function modalType(type) { + if (type === 'delete') { + return + + {props.contentTitle} + } + /> + } else if (type === 'confirm') { + return + } else { + return + } + } + + function render() { + setTimeout(() => { + ReactDOM.render( + modalType(type), + div, + ); + }); + } + render(); +} + +// 选择模态框组件 +function InitModal({ + onCancel, + onOk, + title, + contentTitle, + content, + okText, + cancelText, + afterClose, + className, +}) { + + const [visible, setVisible] = useState(true); + + function onCancelModal() { + setVisible(false); + onCancel && onCancel() + } + + function onSuccess() { + setVisible(false); + onOk && onOk(); + } + + return ( + + {cancelText} + , + , + ]} + > +
+ {contentTitle &&

{contentTitle}

} +

{content}

+
+
+ ) +} diff --git a/src/forge/Wiki/components/Login/index.scss b/src/forge/Component/ModalFun/index.scss similarity index 81% rename from src/forge/Wiki/components/Login/index.scss rename to src/forge/Component/ModalFun/index.scss index 13d16066..24f7b021 100644 --- a/src/forge/Wiki/components/Login/index.scss +++ b/src/forge/Component/ModalFun/index.scss @@ -1,4 +1,4 @@ -.delete-modal { +.myself-modal { .ant-modal-header { padding: 9px 24px; background: #f8f8f8; @@ -16,7 +16,7 @@ .ant-modal-body { text-align: center; } - .delete-title { + .content-title { display: flex; justify-content: center; align-items: center; @@ -32,7 +32,7 @@ color: #ca0002; font-size: 1.5rem !important; } - .delete-descibe { + .content-descibe { font-size: 14px; color: #666; line-height: 33px; @@ -53,4 +53,11 @@ border-color: #df0002; } } + .ant-btn-default:hover, + .ant-btn-default:active, + .ant-btn-default:focus { + background: #f3f4f6; + color: #333; + border-color: #d0d0d0; + } } \ No newline at end of file diff --git a/src/forge/Component/NoticeModal/Index.scss b/src/forge/Component/NoticeModal/Index.scss new file mode 100644 index 00000000..18e4dcda --- /dev/null +++ b/src/forge/Component/NoticeModal/Index.scss @@ -0,0 +1,90 @@ +.systemBox{ + .ant-modal-body{ + padding:1px 0px 0px 0px; + .sysBox{ + background-image: url('./bg.png'); + background-repeat: no-repeat; + background-size: 100% 334px; + margin-top: -55px; + } + .sysnoticeBox{ + width: 100%; + padding:80px 0px 34px; + display: flex; + flex-direction: column; + width: 780px; + margin: 0px auto; + p.ntitle{ + height: 33px; + font-size: 24px; + font-weight: 500; + color: #31FFF7; + line-height: 33px; + text-align: center; + } + p.nSubtitle{ + height: 25px; + line-height: 25px; + font-size: 18px; + font-weight: 500; + color: #FFFFFF; + margin-top: 60px; + padding-left: 20px; + } + .markdown-body{ + box-shadow: 0px 0px 17px rgba(0,0,0,0.2); + border-radius: 4px; + margin-top: 17px!important; + } + .nContent{ + padding:20px 34px; + background-color: #fff; + line-height: 30px; + font-size: 15px; + font-weight: 400; + color: #333; + .realmName{ + margin-top: 20px; + display: flex; + ul{ + width: 50%; + padding-left: 0px!important; + li{ + font-size: 15px; + font-weight: 500; + line-height: 32px; + text-align: left; + color: #000; + list-style-type: none!important; + &:first-child{ + color: #E65714; + } + } + } + } + .nSubdesc{ + font-size: 15px; + font-weight: 400; + color: #000000; + line-height: 31px; + margin-top: 20px; + } + .nInfo{ + font-size: 14px; + font-weight: 400; + color: #333333; + text-align: right; + margin-top: 25px; + p{ + height: 20px; + line-height: 20px; + } + } + } + .nBtn{ + text-align: center; + margin-top: 33px; + } + } + } +} \ No newline at end of file diff --git a/src/forge/Component/NoticeModal/SystemNotice.jsx b/src/forge/Component/NoticeModal/SystemNotice.jsx new file mode 100644 index 00000000..1560c1ff --- /dev/null +++ b/src/forge/Component/NoticeModal/SystemNotice.jsx @@ -0,0 +1,76 @@ +import React , { useEffect , useState } from 'react'; +import { Modal , Button } from 'antd'; +import './Index.scss'; +import '../../css/index.scss'; +import RenderHtml from '../../../components/render-html'; +import cookie from 'react-cookies'; + +function SystemNotice({system_notification,history}){ + const [ visible , setVisible ] = useState(false); + + useEffect(()=>{ + if(system_notification && !cookie.load('notice_stage')){ + setVisible(true); + } + },[system_notification,history.location]) + + function sureContinue() { + cookie.remove('notice_stage'); + + let inFifteenMinutes = new Date(new Date().getTime() + 24 * 3600 * 1000);//一天 + // let inFifteenMinutes = new Date(new Date().getTime() + 60 * 1000);//一分钟 + cookie.save('notice_stage', true,{ expires: inFifteenMinutes,path:"/" }); + + setVisible(false); + } + + return ( + +
+
+

{system_notification && system_notification.subject}

+

{system_notification && system_notification.sub_subject}

+ {/*
+
+ 为了给用户提供更加稳定、优质的服务,我们即将对平台门户首页、平台名称、平台域名进行一次全面升级与变更。原平台名称:Trustie(中文名:确实)将于2021年10月xx日统一更改为Gitlink(中文名:确实开源)。届时平台域名将统一进行更换,更换规则如下 +
+
+
    +
  • 原域名:
  • +
  • 官网顶级域名https://www.trustie.net
  • +
  • 版本库子域名https://forgeplus.trustie.net
  • +
  • 论坛子域名https://forum.trustie.net/forums
  • +
+
    +
  • 更换后域名:
  • +
  • 官网顶级域名https://www.gitlink.org.cn
  • +
  • 版本库子域名https://www.git.gitlink.org.cn
  • +
  • 论坛子域名https://forum.gitlink.org.cn
  • +
+
+
+ 自2021年10月xx日起,旧域名将停止访问。因平台名称与域名变更给您带来的不便,我们深表歉意!非常感谢您一直以来对本平台的信任与支持,我们将一如既往地为您提供优质的服务。 特此通知! +
+
+

Gitlink运营团队

+

2021年10月xx日

+
+
*/} + +
+ +
+
+
+
+ ) +} +export default SystemNotice; \ No newline at end of file diff --git a/src/forge/Component/NoticeModal/bg.png b/src/forge/Component/NoticeModal/bg.png new file mode 100644 index 00000000..625b3c31 Binary files /dev/null and b/src/forge/Component/NoticeModal/bg.png differ diff --git a/src/forge/Component/ProfileModal/Index.jsx b/src/forge/Component/ProfileModal/Index.jsx new file mode 100644 index 00000000..7cead761 --- /dev/null +++ b/src/forge/Component/ProfileModal/Index.jsx @@ -0,0 +1,72 @@ +import React , { useEffect , useState } from 'react'; +import Modals from '../PublicModal/Index'; +import { Button } from 'antd'; +import axios from 'axios'; + +import ProfileImg from './images/profile.png'; +import './Index.scss'; + +function ProfileModal({visible,onCancel,history}) { + const [ modalVis , setModalVis ] = useState(visible); + const [ addMemberCheck , setAddMemberCheck ] = useState(false); + + useEffect(()=>{ + axios.interceptors.response.use((response) => { + if (response && (response.data.status === 411 || response.data.status === 412)) { + setModalVis(true); + if(response.data.status === 412){ + setAddMemberCheck(true); + } + } + return response; + }, (error) => { + }); + },[]) + + useEffect(()=>{ + setModalVis(visible); + },[visible]) + + function onOk(){ + onCancel(); + setModalVis(false); + setTimeout(function(){ + window.open(`/settings/profile`,"_blank"); + },200) + } + + function onNo() { + onCancel(); + setModalVis(false); + } + + return( + + +
+ : +
+ + +
+ } + > +
+ + { + addMemberCheck ? +

目标用户个人资料不完整,需提醒目标用户补充资料后以进行后续操作

+ : +

您目前的个人资料不完整,需要补充资料以进行后续操作。是否前往补充个人信息?

+ } +
+ + ) +} +export default ProfileModal; \ No newline at end of file diff --git a/src/forge/Component/ProfileModal/Index.scss b/src/forge/Component/ProfileModal/Index.scss new file mode 100644 index 00000000..cf13121e --- /dev/null +++ b/src/forge/Component/ProfileModal/Index.scss @@ -0,0 +1,18 @@ +.contents{ + display: flex; + align-items: center; + justify-content: center; + margin:10px auto 0px; + img{ + margin-right: 13px; + width: 44px; + } + p{ + line-height: 29px; + max-width: 327px; + font-size: 16px!important; + } +} +.font-44{ + font-size: 44px!important; +} \ No newline at end of file diff --git a/src/forge/Component/ProfileModal/Profile.jsx b/src/forge/Component/ProfileModal/Profile.jsx new file mode 100644 index 00000000..e63c1286 --- /dev/null +++ b/src/forge/Component/ProfileModal/Profile.jsx @@ -0,0 +1,17 @@ +import React from 'react'; + +function Profile({children,sureFunc,showCompeleteDialog , completeProfile, className}) { + + function checkProfile() { + if(!completeProfile){ + showCompeleteDialog && showCompeleteDialog(); + }else{ + sureFunc(); + } + } + + return( + {children} + ) +} +export default Profile; \ No newline at end of file diff --git a/src/forge/Component/ProfileModal/images/profile.png b/src/forge/Component/ProfileModal/images/profile.png new file mode 100644 index 00000000..6dbed21f Binary files /dev/null and b/src/forge/Component/ProfileModal/images/profile.png differ diff --git a/src/forge/Component/PublicModal/Index.jsx b/src/forge/Component/PublicModal/Index.jsx new file mode 100644 index 00000000..c12e12b1 --- /dev/null +++ b/src/forge/Component/PublicModal/Index.jsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { Modal } from 'antd'; +import './Index.scss'; + +function Modals({title,children,btn,onCancel,visible}) { + return( + + {children} + + ) +} +export default Modals; \ No newline at end of file diff --git a/src/forge/Component/PublicModal/Index.scss b/src/forge/Component/PublicModal/Index.scss new file mode 100644 index 00000000..1a0fbf31 --- /dev/null +++ b/src/forge/Component/PublicModal/Index.scss @@ -0,0 +1,75 @@ +.deleteBox{ + z-index: 1033; + .ant-modal-close-x{ + font-size: 17px!important; + } + .ant-modal-header{ + background-color: #f8f8f8; + padding:10px 30px; + .ant-modal-title{ + text-align: left; + font-size: 16px; + font-weight: bold; + } + } + .ant-modal-close{ + top:0px !important; + font-size: 24px !important; + } + .ant-modal-body{ + padding:30px 50px; + p{ + font-size: 14px; + line-height: 26px; + color:#666; + word-break: break-all; + } + .desc{ + .descMain{ + align-items: center; + justify-content: center; + font-size: 20px; + margin-bottom: 10px; + i.red{ + color:#DF0002; + } + } + } + } + .ant-modal-footer{ + border-top: none; + text-align: center; + padding-bottom: 40px; + button,a{ + width: 96px; + height: 32px; + margin:0px 20px; + font-weight: 400; + font-size: 14px; + &.ant-btn{ + border-color: #D0D0D0; + color: #666; + &:hover,&:active,&:focus{ + background: #f3f4f6; + } + } + &.ant-btn-danger{ + background-color: #fff; + color: #DF0002; + border-color: #D0D0D0; + &:hover,&:active,&:focus{ + border-color: #DF0002; + background-color: #fff; + } + } + &.ant-btn.ant-btn-primary{ + background-color: #466AFF; + color: #fff; + border-color: #466AFF; + &:hover,&:focus,&:active{ + background-color: rgba(70,106,255,0.85); + } + } + } + } +} \ No newline at end of file diff --git a/src/forge/Component/Releases.jsx b/src/forge/Component/Releases.jsx index d8c5e86f..260e6bd2 100644 --- a/src/forge/Component/Releases.jsx +++ b/src/forge/Component/Releases.jsx @@ -1,14 +1,13 @@ import React from 'react'; -import { AlignCenter , AlignTop , FlexAJ } from '../Component/layout'; +import { AlignTop } from '../Component/layout'; import { Link } from 'react-router-dom'; -function Releases({owner,projectsId,releaseVersions , baseOperate , projectType}){ - +function Releases({ owner, projectsId, releaseVersions, distribution }) { return(
- + 发行版 - { releaseVersions && releaseVersions.total_count > 0 && {releaseVersions.total_count}} + { releaseVersions && releaseVersions.total_count > 0 && {releaseVersions.total_count}} { releaseVersions && releaseVersions.total_count>0 ? @@ -16,9 +15,10 @@ function Releases({owner,projectsId,releaseVersions , baseOperate , projectType} return( key === 0 &&
-

- 发布{item.name}版本 - 最新 +

+ {/* 如果是点击最新则发行版列表页只展示最新的一个 */} + {item.name} + 最新

{item.created_at}

@@ -27,7 +27,8 @@ function Releases({owner,projectsId,releaseVersions , baseOperate , projectType} }) :
- 您暂未发布任何版本{baseOperate && projectType !==2 && 创建新版本} + 您暂未发布任何版本 + {distribution && 创建新版本}
} diff --git a/src/forge/Component/Sort.jsx b/src/forge/Component/Sort.jsx index 58f8a5d2..a15f04da 100644 --- a/src/forge/Component/Sort.jsx +++ b/src/forge/Component/Sort.jsx @@ -2,9 +2,9 @@ import React from 'react'; import {Popover} from 'antd'; import './Component.scss'; -export default (({menu , children})=>{ +export default (({menu , children, overlayClassName})=>{ return( - + {children} ) diff --git a/src/forge/Component/User.jsx b/src/forge/Component/User.jsx index 4d22c77b..0d970173 100644 --- a/src/forge/Component/User.jsx +++ b/src/forge/Component/User.jsx @@ -5,6 +5,7 @@ import { Link } from 'react-router-dom'; export default ({ url , name , column , id , login })=>{ const Img = styled.span` display:flex; + font-weight: bold; ${column && "flex-direction: column;text-align:center;"} align-items: center; & img{ @@ -20,7 +21,7 @@ export default ({ url , name , column , id , login })=>{ `; return( id? - + { url && } {name} diff --git a/src/forge/DevOps/About.jsx b/src/forge/DevOps/About.jsx index b9524d54..31ced220 100644 --- a/src/forge/DevOps/About.jsx +++ b/src/forge/DevOps/About.jsx @@ -149,7 +149,7 @@ function About(props, ref) { axios.post(url).then(result=>{ setIsSpining(false); if(result && result.data.status === 0){ - props.history.push(`/projects/${owner}/${projectsId}/devops/dispose`); + props.history.push(`/${owner}/${projectsId}/devops`); // 需要将顶部的open_devops修改 let { changeOpenDevops } = props; changeOpenDevops && changeOpenDevops(true); diff --git a/src/forge/DevOps/Dispose.jsx b/src/forge/DevOps/Dispose.jsx index 2211dbb5..1e08cdab 100644 --- a/src/forge/DevOps/Dispose.jsx +++ b/src/forge/DevOps/Dispose.jsx @@ -96,7 +96,7 @@ function Dispose(props){ setVisible(false); if(result && result.data){ props.showNotification("流水线新增成功,请进行工作流配置!"); - props.history.push(`/projects/${owner}/${projectsId}/devops/dispose/${result.data.id}`); + props.history.push(`/${owner}/${projectsId}/devops/${result.data.id}`); }else{ props.showNotification("流水线新增失败,请稍后再试!"); } @@ -134,12 +134,12 @@ function Dispose(props){ // 模板管理 function toModalManage(){ - props.history.push(`/projects/${owner}/${projectsId}/devops/mould`); + props.history.push(`/${owner}/${projectsId}/devops/mould`); } // 参数管理 function toparameter(){ - props.history.push(`/projects/${owner}/${projectsId}/devops/params`); + props.history.push(`/${owner}/${projectsId}/devops/params`); } const operate = current_user && (permission && permission !== "Reporter"); diff --git a/src/forge/DevOps/Dispose/List.jsx b/src/forge/DevOps/Dispose/List.jsx index 4c077452..297c5556 100644 --- a/src/forge/DevOps/Dispose/List.jsx +++ b/src/forge/DevOps/Dispose/List.jsx @@ -73,7 +73,7 @@ function List({ list, operate , projectsId , owner , showModal , deleteFunc }){ render:(value,item)=>{ let v = turnbar(item.branch); return( - {value} + {value} ) } }, @@ -117,7 +117,7 @@ function List({ list, operate , projectsId , owner , showModal , deleteFunc }){ return( { operate ? - + 编辑 :"" } { operate ? @@ -125,7 +125,7 @@ function List({ list, operate , projectsId , owner , showModal , deleteFunc }){ 删除 :"" } - 查看运行记录 + 查看运行记录 ) } diff --git a/src/forge/DevOps/Dispose/PipelineName.jsx b/src/forge/DevOps/Dispose/PipelineName.jsx index 4acaa206..63ee5437 100644 --- a/src/forge/DevOps/Dispose/PipelineName.jsx +++ b/src/forge/DevOps/Dispose/PipelineName.jsx @@ -51,7 +51,7 @@ function PipelineName({visible,onCancel,onOk,value ,branchList}){ }) } - {setEventValue(e)}}> { EVENT.map((item,key)=>{ return( diff --git a/src/forge/DevOps/Index.jsx b/src/forge/DevOps/Index.jsx index c3a29a3e..3302f603 100644 --- a/src/forge/DevOps/Index.jsx +++ b/src/forge/DevOps/Index.jsx @@ -36,39 +36,37 @@ export default ((props)=>{ return( - () - } - > - () } > - () } > - () } > - () - } - > - () } > - () + (p) => () + } + > + {/* 原本的两种合为一个 */} + {return( p.location.state.open_devops?:)} } > diff --git a/src/forge/DevOps/Infos.jsx b/src/forge/DevOps/Infos.jsx index b5220138..99029cde 100644 --- a/src/forge/DevOps/Infos.jsx +++ b/src/forge/DevOps/Infos.jsx @@ -26,7 +26,7 @@ export default ((props)=>{ return(
- { permission !=="Reporter" && 工作流配置} + { permission !=="Reporter" && 工作流配置}
diff --git a/src/forge/DevOps/Manage/Params.jsx b/src/forge/DevOps/Manage/Params.jsx index 7cb55276..6df62dd4 100644 --- a/src/forge/DevOps/Manage/Params.jsx +++ b/src/forge/DevOps/Manage/Params.jsx @@ -104,7 +104,7 @@ function Params(props){ 工作流 - 参数管理 - 返回 + 返回
diff --git a/src/forge/DevOps/Mould.jsx b/src/forge/DevOps/Mould.jsx index 933299d6..204fd161 100644 --- a/src/forge/DevOps/Mould.jsx +++ b/src/forge/DevOps/Mould.jsx @@ -126,7 +126,7 @@ function Mould(props){
childRef.current = f} ref={childRef} visible={visible} onCancel={()=>setVisible(false)} onOk={onOk}> - 工作流 - 模板管理返回 + 工作流 - 模板管理返回
diff --git a/src/forge/DevOps/Structure.jsx b/src/forge/DevOps/Structure.jsx index 52ac1682..99040d38 100644 --- a/src/forge/DevOps/Structure.jsx +++ b/src/forge/DevOps/Structure.jsx @@ -198,7 +198,7 @@ function Structure(props,ref){ } function clickRows(event,e){ - props.history.push(`/projects/${owner}/${projectsId}/devops/${e.number}/detail`); + props.history.push(`/${owner}/${projectsId}/devops/${e.number}/detail`); } const column = [ { @@ -290,7 +290,7 @@ function Structure(props,ref){ 构建列表 - 返回 + 返回
diff --git a/src/forge/DevOps/disposePipeline.jsx b/src/forge/DevOps/disposePipeline.jsx index 1da142f6..deabc149 100644 --- a/src/forge/DevOps/disposePipeline.jsx +++ b/src/forge/DevOps/disposePipeline.jsx @@ -275,7 +275,7 @@ function disposePipeline(props){ ...params }).then(result=>{ if(result){ - props.history.push(`/projects/${owner}/${projectsId}/devops/dispose`); + props.history.push(`/${owner}/${projectsId}/devops`); } setLoading(false); }).catch(error=>{ diff --git a/src/forge/DevOps/opsDetail.jsx b/src/forge/DevOps/opsDetail.jsx index 6ac3dc44..1944dfe6 100644 --- a/src/forge/DevOps/opsDetail.jsx +++ b/src/forge/DevOps/opsDetail.jsx @@ -48,7 +48,7 @@ export default (props) => { axios.post(url).then((result) => { if (result && result.data) { props.showNotification("工作流正在重新构建!"); - props.history.push(`/projects/${owner}/${projectId}/devops/${result.data.number}/detail`); + props.history.push(`/${owner}/${projectId}/devops/${result.data.number}/detail`); } }) .catch((error) => { @@ -87,7 +87,7 @@ export default (props) => { 退出 diff --git a/src/forge/DevOps/ssh/XmlPanel.jsx b/src/forge/DevOps/ssh/XmlPanel.jsx index ae642caa..295d96ce 100644 --- a/src/forge/DevOps/ssh/XmlPanel.jsx +++ b/src/forge/DevOps/ssh/XmlPanel.jsx @@ -24,7 +24,6 @@ function onLayout(term, el) { entry.target.offsetHeight, term, ); - console.log('cols, rows', cols, rows); term.resize(cols, rows); mediator.publish('ssh-xterm-resize', { columns: cols, @@ -139,12 +138,10 @@ export default ({ sshConfigData, sid }) => { }, 1000); } isFirstConnected.current = true; - console.log('event:', event); const data = Base64.decode(event.data.toString()); let w = term._core._renderService.dimensions.actualCellWidth || 9.5; - console.log('data:', data, w, term); term.write(data); }; diff --git a/src/forge/Divert/DivertModal.jsx b/src/forge/Divert/DivertModal.jsx index a6ecdc05..d4c1f201 100644 --- a/src/forge/Divert/DivertModal.jsx +++ b/src/forge/Divert/DivertModal.jsx @@ -41,14 +41,15 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){ // 确认转移 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){ + if(result && result.data.id){ onSuccess(result.data && result.data.owner); + }else{ + onSuccess(); } }).catch(error=>{}) } @@ -104,7 +105,7 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){ :
    -
  • 仓库仅可以转移到您已经加入的组织中,不可以转移到未加入的组织中
  • +
  • 仓库仅可以转移到您具有管理权限的组织中
  • 涉及到仓库改名操作,请提前做好仓库备份并且在转移后对本地仓库的remote进行修改
  • 转移仓库到组织后,你和组织创建者/管理员同时拥有对该仓库的管理操作
diff --git a/src/forge/Head/AddProjectModal.jsx b/src/forge/Head/AddProjectModal.jsx index 8e3073e3..81f1d27c 100644 --- a/src/forge/Head/AddProjectModal.jsx +++ b/src/forge/Head/AddProjectModal.jsx @@ -1,6 +1,7 @@ import React, { useState , forwardRef, useEffect } from 'react'; import { Form , Modal , Input , Radio } from 'antd'; import Axios from 'axios'; +import CheckProfile from '../Component/ProfileModal/Profile'; export default Form.create()( forwardRef((props)=>{ @@ -77,7 +78,7 @@ export default Form.create()( - setVisible(true)}>加入项目 + setVisible(true)}>加入项目 ) }) diff --git a/src/forge/Head/AppPullRefresh.jsx b/src/forge/Head/AppPullRefresh.jsx new file mode 100644 index 00000000..2b9c7660 --- /dev/null +++ b/src/forge/Head/AppPullRefresh.jsx @@ -0,0 +1,108 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { Icon } from 'antd'; +import _ from 'lodash'; +import Nodata from '../Nodata'; + + +class PullRefresh extends Component { + constructor(props) { + super(props); + this.state = { + } + this.pullRef = {}; + // 节流 + this.onScrollList = _.throttle(this.handleScroll, 200, { + leading: false, + trailing: true, + }); + } + + componentDidMount() { + let dom = document.querySelector('.pull-refresh-wrap'); + dom && dom.addEventListener('scroll', this.onScrollList); + } + + componentWillUnmount() { + let dom = document.querySelector('.pull-refresh-wrap'); + dom && dom.removeEventListener('scroll', this.onScrollList) + } + + + handleScroll = () => { + if (this.props.count < this.props.pageSize) return; + if (this.props.type === 1 || this.props.type === 2) return; + const wrap = this.pullRef; + const currentScroll = wrap.scrollTop + wrap.clientHeight + + // 触底 + if (currentScroll >= (wrap.scrollHeight - 200)) { + this.loadData() + } + } + + + handleLoadClick = () => { + this.loadData(); + } + + loadData = () => { + this.props.onPullRefresh() + } + + + renderLoading() { + switch (this.props.type) { + case 0: // 加载更多 + return
显示更多
+ case 1: // 加载中 + return ( +
+ + 加载中... +
+ ) + case 2: // 无样式 + return
没有更多了
+ default: + return
没有更多了
+ } + } + + + render() { + const { className, count, children } = this.props; + return ( +
{ this.pullRef = dom }} + > + + {children} + + { + count < 1 && + } + + {/* 大于分页数据才显示loading */} + {/* {this.props.count >= this.props.pageSize ? this.renderLoading() : null} */} + +
+ + ) + } + +} + + +PullRefresh.propTypes = { + className: PropTypes.string, + children: PropTypes.any, + onPullRefresh: PropTypes.func.isRequired, + type: PropTypes.oneOf([0, 1, 2]), + count: PropTypes.number.isRequired, + pageSize: PropTypes.number.isRequired, +} + + +export default PullRefresh diff --git a/src/forge/Head/Footer.jsx b/src/forge/Head/Footer.jsx index 568583ea..52c06858 100644 --- a/src/forge/Head/Footer.jsx +++ b/src/forge/Head/Footer.jsx @@ -19,7 +19,7 @@ function Footer(){ return(
-
+
{value && showhtml(value)} {/*
diff --git a/src/forge/Head/Header.js b/src/forge/Head/Header.js index 7364ebd3..ac139351 100644 --- a/src/forge/Head/Header.js +++ b/src/forge/Head/Header.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import AccountProfile from "../../modules/user/AccountProfile"; import { getImageUrl } from 'educoder' import axios from 'axios'; -import { Input , notification , Dropdown , Menu } from 'antd'; +import { Input , notification , Dropdown ,Popover, Menu,Badge, Button } from 'antd'; import { Link } from 'react-router-dom'; import LoginDialog from '../../modules/login/LoginDialog'; @@ -10,8 +10,10 @@ import HeadSearch from '../Component/HeadSearch'; import AddProjectModal from './AddProjectModal'; import '../../modules/tpm/TPMIndex.css'; +import CheckProfile from '../Component/ProfileModal/Profile'; import './header.scss'; +import NoticeContent from './NoticeContent'; const $ = window.$ // TODO 这部分脚本从公共脚本中直接调用 const { Search } = Input; @@ -46,6 +48,7 @@ class NewHeader extends Component { settings: null, visiblemyss: false, openSearch:false, + visible:false, //浮动消息框展示控制 } } componentDidMount() { @@ -91,9 +94,6 @@ class NewHeader extends Component { this.setState({ user: newProps.user }) - if (newProps.Headertop !== undefined) { - old_url = newProps.Headertop.old_url - } } educoderlogin = () => { @@ -120,7 +120,6 @@ class NewHeader extends Component { }) }; HideAddcoursestypess = (i) => { - console.log("调用了"); this.setState({ Addcoursestypes: false, mydisplay: true, @@ -222,6 +221,15 @@ class NewHeader extends Component { } } } + + checkProfile=(url)=>{ + const { showCompeleteDialog , completeProfile } = this.props; + if(!completeProfile){ + showCompeleteDialog && showCompeleteDialog(); + }else{ + window.location.href(url); + } + } addMenu=(list)=>{ return( @@ -231,21 +239,27 @@ class NewHeader extends Component { { list.map((item,key)=>{ return( - (item.name !=="加入课堂" && item.name !=="加入开发项目") && {item.name} + (item.name !=="加入课堂" && item.name !=="加入开发项目") && + + {window.location.href=item.url}}>{item.name} + ) }) } - + + +
) } + renderMenu=(personal)=>{ const { current_user } = this.props; return( - {current_user && current_user.username} + {current_user && current_user.username} { personal && personal.length > 0 && personal.map((item,key)=>{ @@ -254,14 +268,18 @@ class NewHeader extends Component { ) }) } -
  • 设置
  • + {/*
  • 设置
  • */} this.educoderloginysl()}>退出
    ) } + handleVisibleChange = visible => { + this.setState({ visible }); + }; + render() { - const { match} = this.props; + const { match ,resetUserInfo ,showNotification} = this.props; let current_user = this.props.user; let { AccountProfiletype, @@ -270,6 +288,7 @@ class NewHeader extends Component { headtypesonClickbool, headtypess, settings, + visible, } = this.state; /*用户名称 用户头像url*/ let activeIndex = false; @@ -347,8 +366,7 @@ class NewHeader extends Component { }) } - // let search_url = settings && settings.common && settings.common.search; - let notice_url = settings && settings.common && settings.common.notice; + let search_url = settings && settings.common && settings.common.search; return (
    @@ -380,21 +398,21 @@ class NewHeader extends Component { { settings.navbar && settings.navbar.map((item, key) => { var new_link = item.link; - var user_login = this.props.user && this.props.user.login; + var user_login = current_user && current_user.login; var is_hidden = item.hidden if (new_link && (new_link.indexOf("courses") > -1 || new_link.indexOf("contests") > -1)) { if (user_login) { if (new_link.indexOf("courses") > -1) { - new_link = new_link.replace(/courses/g, "users/" + user_login + "/courses") + new_link = new_link.replace(/courses/g, user_login + "/courses") } else if (new_link.indexOf("contests") > -1) { - new_link = new_link.replace(/contests/g, "users/" + user_login + "/contests") + new_link = new_link.replace(/contests/g, user_login + "/contests") } } else { is_hidden = true } } if (user_login && (new_link && new_link.indexOf("homes") > -1)) { - new_link = new_link.replace(/homes/g, "users/" + user_login + "/user_activities") + new_link = new_link.replace(/homes/g, user_login + "/user_activities") } var waiLian = (new_link && str.filter(item=>new_link.indexOf(item)>-1) ); @@ -411,25 +429,30 @@ class NewHeader extends Component { }
    - {/* {search_url ? this.SearchInput(openSearch,search_url):""} */} - + { search_url && } { current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)? - + :"" } - {this.props.user && this.props.user.login && notice_url ? -
    - {user && user.login && - - - - - - } -
    :"" + { (settings && settings.common && settings.common.notice) && (current_user && current_user.login)? + } + visible={visible} + onVisibleChange={this.handleVisibleChange} + destroyTooltipOnHide + > + + {current_user && + + } + + + : "" }
    {!user || (user && !user.login) ? @@ -442,7 +465,7 @@ class NewHeader extends Component { : - + 头像 diff --git a/src/forge/Head/NoticeContent.jsx b/src/forge/Head/NoticeContent.jsx new file mode 100644 index 00000000..634a7adc --- /dev/null +++ b/src/forge/Head/NoticeContent.jsx @@ -0,0 +1,262 @@ +import React, { useEffect, useState } from 'react'; +import { Badge, Menu } from 'antd'; +import { Link } from 'react-router-dom'; +import axios from 'axios'; +import AppPullRefresh from './AppPullRefresh'; +import { noticeSourceType } from '../common/static'; +import './header.scss'; +import '../SecuritySetting/notice/manager/Index.scss'; +import '../SecuritySetting/Index.scss'; +import '../SecuritySetting/notice/myNotice/Index.scss'; + + +function NoticeContent({ visible, showNotification, resetUserInfo, current_user: { login } }) { + const [initialize, setInitialize] = useState(true); + const [noticeType, setNoticeType] = useState("notification"); + const [letterUnreadCount, setLetterUnreadCount] = useState(0);//未读私信数量 + + const [noticeUnreadCount, setNoticeUnreadCount] = useState(0);//未读系统通知数量 + const [noticePage, setNoticePage] = useState(0); + const [noticeUnreadList, setNoticeUnreadList] = useState([]);//未读系统通知列表 + + const [atUnreadCount, setAtUnreadCount] = useState();//未读@我数量 + const [atPage, setAtPage] = useState(0); + const [atUnreadList, setAtUnreadList] = useState([]);//未读@我列表 + + useEffect(() => { + resetUserInfo(); + }, [noticeUnreadCount,atUnreadCount]); + + useEffect(()=>{ + setNoticePage(0); + setAtPage(0); + },[visible]) + + useEffect(() => { + const params = { + type: noticeType, + limit: 10, + page: noticeType === "notification" ? noticePage : noticeType === "atme" ? atPage : "", + status: 1, + } + getMessageList(params); + }, [noticePage, atPage]); + + useEffect(() => { + const params = { + type: noticeType, + limit: 10, + page: 0, + status: 1, + }; + if (initialize) { + params.type = "atme" + } + visible && getMessageList(params); + }, [visible]); + + + function getMessageList(params) { + axios.get(`/users/${login}/messages.json`, { + params: params, + }).then((response) => { + if (response && response.data) { + setNoticeUnreadCount(response.data.unread_notification); + setAtUnreadCount(response.data.unread_atme); + if (params.type === "notification") { + let list = response.data.messages; + if (params.page !== 0) { + list = [...noticeUnreadList, ...list]; + } + setNoticeUnreadList(list); + if (initialize) { + // 如果是第一次加载,根据数据量判断是否切换tab栏 + setInitialize(false); + if (response.data.unread_notification === 0 && response.data.unread_atme !== 0) { + setNoticeType("atme"); + } + } + } else if (params.type === "atme") { + let list = response.data.messages; + if (params.page !== 0) { + list = [...atUnreadList, ...list]; + } + setAtUnreadList(list); + } + } + }) + } + + function readAll() { + axios.post(`/users/${login}/messages/read.json`, { + type: noticeType, + ids: [-1] + }).then((response) => { + let data = response.data; + if (!data) return; + if (data.status === 0) { + changeReadMarkAll(noticeType); + } else { + showNotification(data.message); + } + }); + } + + + function changeReadMarkAll(noticeType) { + if (noticeType === "notification") { + let list = noticeUnreadList.slice(); + list.forEach(item => { + item.status = 2; + }) + setNoticeUnreadList(list); + setNoticeUnreadCount(0); + } else if (noticeType === "atme") { + let list = atUnreadList.slice(); + list.forEach(item => { + item.status = 2; + }) + setAtUnreadList(list); + setAtUnreadCount(0); + } + } + + // const [letter_unread_list, setLetter_unread_list] = useState([ + // { + // id: 122, + // read: 0, //是否已读,0未读,1已读 + // send_name: "蒋宇航", //消息发送人 + // send_login: "jiangYuHang", //消息发送人的login,前端根据这个跳转到消息内页 + // content: "私信内容", //最近一条未读消息的内容 + // create_time: "2019-03-04 18:08", //发送时间 + // }, + // ]); + + function readItem(item) { + axios.post(`/users/${login}/messages/read.json`, { + type: noticeType, + ids: [item.id] + }).then((response) => { + let data = response.data; + if (!data) return; + if (data.status === 0) { + changeReadMark(item); + item.notification_url && window.open(item.notification_url); + } else { + showNotification(data.message); + } + }); + } + + + function changeReadMark(item) { + if (item.type === "notification") { + let list = noticeUnreadList.slice(); + let index = noticeUnreadList.indexOf(item); + list[index].status = 2; + setNoticeUnreadList(list); + if (noticeUnreadCount > 0) { + setNoticeUnreadCount(noticeUnreadCount - 1); + } + } else if (item.type === "atme") { + let list = atUnreadList.slice(); + let index = atUnreadList.indexOf(item); + list[index].status = 2; + setAtUnreadList(list); + if (atUnreadCount > 0) { + setAtUnreadCount(atUnreadCount - 1); + } + } + } + + return ( +
    +
    + setNoticeType(e.key)}> + 系统通知 + {/* 私信 */} + @我 + +
    + + {/* 系统通知 */} + {noticeType === "notification" && { setNoticePage(noticePage + 1); }} //触发加载ajax的function + // type={2} // 传送加载组件的状态 + count={noticeUnreadList.length} // 数据当前的总数量 + pageSize={10} // + > + { + noticeUnreadList.map(item => { + return ( +
    { readItem(item) }}> +
    + + + + +
    + + {item.time_ago} +
    +
    +
    + ) + }) + } +
    + } + + {/* @我 */} + {noticeType === "atme" && { setAtPage(atPage + 1); }} //触发加载ajax的function + // type={1} // 传送加载组件的状态 + count={atUnreadList.length} // 数据当前的总数量 + pageSize={10} // + > + {atUnreadList.map(item => { + return ( +
    { readItem(item) }}> +
    + + + +
    + " + (item.sender ? item.sender.name : '') + "   " + item.content + " 中@我" }}> + {item.time_ago} +
    +
    +
    + ) + }) + } +
    + } + + {/* 私信 */} + {/* {noticeType === "1" ? letter_unread_list.length > 0 ? letter_unread_list.map(item => { + return ( +
    +
    = 30 && item.content.length <= 34 ? '65px' : "" }}> + +
    + {item.send_name}: + = 50 ? item.content.substr(0, 50) + "..." : item.content }}> + {item.create_time ? timeAgo(item.create_time) : "刚刚"} +
    +
    +
    + ) + }) : "暂无数据" : ""} */} +
    + 全部消息 + {noticeUnreadCount > 0 && noticeType === "notification" && 所有系统消息一键已读} + {atUnreadCount > 0 && noticeType === "atme" && 所有@我一键已读} +
    +
    + + ) +} +export default NoticeContent; diff --git a/src/forge/Head/header.scss b/src/forge/Head/header.scss index 0246658a..263cd1ee 100644 --- a/src/forge/Head/header.scss +++ b/src/forge/Head/header.scss @@ -24,12 +24,20 @@ width: 34px; height: 34px; border-radius: 50%; - margin-left: 30px; + margin-left: 15px; } + .currentMenu{ width: 120px; text-align: center; padding:0px; + .currentName{ + padding:0px 8px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + display: block; + } li{ height: 40px; line-height: 40px; @@ -119,4 +127,139 @@ width: 110px; text-align: right; } +} + +// 右上角小铃铛单独样式 +.notice-popover{ + //popover小尖尖 + .ant-popover-arrow{ + display: none; + } + + //popover框 + .ant-popover-inner-content { + width: 386px; + height: 446px; + box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5); + border-radius: 4px; + margin-top: -10px; + padding: 12px 1px 12px 0; + } +} + +.messageHoverDiv .ant-menu-item{ + margin-right: 24px !important; +} + +.hoverNotice-head{ + margin-left: 18px; + + & .ant-badge{ + font-size: 14px !important; + } + + &>.ant-menu-horizontal { + border-bottom: 1px solid #e8e8e8 !important; + } +} + +.hoverNotice-body{ + height: 342px; + overflow-y: scroll; + + & b{ + font-weight: 400; + text-shadow: 0.5px 0 0 #333; + } + + .none_panels{ + height: 100%; + } +} + +.message-icon{ + position: relative; + .ant-scroll-number{ + right:12px; + padding: 0 0px; + } +} + + + +.hoverNotice-buttom{ + display: flex; + justify-content: space-between; + padding: 12px 18px; + a{ + color: #466AFF; + &:hover{ + opacity:0.85; + } + } +} + +.noticeCont-back{ + .pointer{ + cursor: pointer; + } + &:hover{ + background: #F3F4F6; + } +} + +.noticeCont{ + display: flex; + margin: 0 16px 0 18px; + padding: 12px 0 10px 0; + line-height: 24px; + border-bottom: 1px solid #EEEEEE; + cursor: default; + i{ + font-size: 14px !important; + margin-right: 6px; + color: #333333; + } + + .boldSpan{ + font-weight: 400; + text-shadow: 0.5px 0 0 #333; + } + + .noticeCont-text{ + display: flex; + color:#333333; + flex:auto; + justify-content: space-between; + + & .content-span{ + word-break: break-all; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + } + + & .atme-cont-span{ + width: 272px; + } + + & .notice-cont-span{ + width: 255px; + } + + .timeSpan{ + font-size: 12px; + color: #666666; + } + + .at-name{ + margin-right: 12px; + } + } +} + +.text-center{ + text-align: center; } \ No newline at end of file diff --git a/src/forge/Index.js b/src/forge/Index.js index 3870c088..c2e36916 100644 --- a/src/forge/Index.js +++ b/src/forge/Index.js @@ -12,8 +12,9 @@ import Loadable from "react-loadable"; import Loading from "../Loading"; import { ImageLayerOfCommentHOC } from "../modules/page/layers/ImageLayerOfCommentHOC"; + const ProjectNew = Loadable({ - loader: () => import("./New/Index"), + loader: () => import("./New/Index"), loading: Loading, }); const ProjectIndex = Loadable({ @@ -21,21 +22,23 @@ const ProjectIndex = Loadable({ loading: Loading, }); -const ProjectDetail = Loadable({ - loader: () => import("./Main/Detail"), - loading: Loading, -}); +// 项目详情放在用户和组织下作为二级菜单存在 +// const ProjectDetail = Loadable({ +// loader: () => import("./Main/Detail"), +// loading: Loading, +// }); class Index extends Component { - componentDidUpdate=()=>{ - this.props.history.listen(()=>{ + componentDidUpdate = () => { + this.props.history.listen(() => { if (document.body.scrollTop || document.documentElement.scrollTop > 0) { window.scrollTo(0, 0) } }) } render() { + return (
    @@ -52,23 +55,24 @@ class Index extends Component { )} > ( )} > - ( )} - > + > */} ( )} > + ( @@ -86,3 +90,10 @@ export default withRouter( parentSelector: ".newMain", })(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(Index)))) ); + +// export default withRouter( +// ImageLayerOfCommentHOC({ +// imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget", +// parentSelector: ".newMain", +// })(Index) +// ); diff --git a/src/forge/Main/CoderDepot.jsx b/src/forge/Main/CoderDepot.jsx index ee2bc092..f50c134a 100644 --- a/src/forge/Main/CoderDepot.jsx +++ b/src/forge/Main/CoderDepot.jsx @@ -3,6 +3,7 @@ import { WhiteBack , Box , LongWidth , ShortWidth , Gap , AlignCenter , FlexAJ import { Dropdown , Menu , Divider , Spin, Button , Typography } from 'antd'; import { getImageUrl } from "educoder"; import { Link } from 'react-router-dom'; +import { truncateCommitId } from "../common/util"; import CloneAddress from '../Branch/CloneAddress'; import SelectBranch from '../Branch/Select'; @@ -20,6 +21,8 @@ import DrawerPanel from '../Component/DrawerPanel'; import UpdateDescModal from './sub/UpdateDescModal'; import Nodata from '../Nodata'; import Invite from './sub/Invite'; +import CheckProfile from '../Component/ProfileModal/Profile'; +import RenderHtml from '../../components/render-html'; /** * projectDetail.type:0是托管项目,1是镜像项目,2是同步镜像项目(为2时不支持在线创建、在线上传、在线修改、在线删除、创建合并请求等功能) */ @@ -65,6 +68,7 @@ function CoderDepot(props){ const [ editReadme , setEditReadme ] = useState(false); const [ pullsFlag , setPullsFlag ] = useState(true); const [ issuesFlag , setIssuesFlag ] = useState(true); + const [ releaseVersions , setReleaseVersions] = useState(undefined); const owner = props.match.params.owner; const projectsId = props.match.params.projectsId; @@ -72,7 +76,8 @@ function CoderDepot(props){ branchName = returnbar(branchName); const details = props.projectDetail; let pathname = props.history.location.pathname; - + //distribution:判断此用户是否可以创建发行版 + const distribution = details && details.type != 2 && (details.permission === "Admin" || details.permission === "Owner" || details.permission === "Manager"); const { bannerList } = props; useEffect(()=>{ @@ -112,19 +117,52 @@ function CoderDepot(props){ useEffect(()=>{ if (projectsId && owner && defaultBranch){ let b = turnbar(branchName) ; - if(pathname.indexOf(`/projects/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${b}/`) > -1) { + if(pathname.indexOf(`/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${b}/`) > -1) { let url = pathname.split(`/tree/${b}/`)[1]; setTreeValue(url); getFileInfo(url,branchName); setType("file"); + // getReadmeInfo(url,branchName); + // setReadme(undefined); }else{ setTreeValue(undefined); getDirInfo(branchName || defaultBranch); setType("dir"); + // getReadmeInfo('', branchName || defaultBranch); } } },[projectsId,owner,pathname,defaultBranch]) + useEffect(()=>{ + axios.get(`/${owner}/${projectsId}/releases.json`).then((result)=>{ + if(result && result.data){ + const release = { + "list":result.data.releases, + "total_count":result.data.releases.length + } + setReleaseVersions(release); + } + }) + },[]) + + // 获取readme信息 + function getReadmeInfo(path, ref) { + axios.get(`/${owner}/${projectsId}/readme.json`, { + params:{ + owner: owner, + repo: projectsId, + filepath:path, + ref:ref || branchName + } + }).then((result) => { + if (result) { + setReadme(result.data); + } else { + setReadme(undefined); + } + }) + } + // 获取主目录列表 function getDirInfo(branch){ setIsSpin(true); @@ -144,9 +182,10 @@ function CoderDepot(props){ setLastCommitAuthor(c && c.committer); setMainFlag(true); setReadOnly(true); - setReadme(result.data.readme); + // setReadme(result.data.readme); setEditReadme(false); setHide(true); + getReadmeInfo('', branchName || defaultBranch); } setTimeout(function(){setIsSpin(false);},500); }).catch(error=>{setIsSpin(false);}) @@ -158,7 +197,7 @@ function CoderDepot(props){ let ele = document.getElementById("ptxt"); if(ele){ let h = ele.offsetHeight; - if( h > 18 ) setHideBtn(true); + if( h > 35 ) setHideBtn(true); } } },[projectDetail,lastCommit]) @@ -179,15 +218,18 @@ function CoderDepot(props){ setDirInfo(undefined); setFileInfo(en); setType(en.type); + setReadme(undefined); }else{ setFileInfo(undefined); setDirInfo(en); setType("dir"); + getReadmeInfo(path, branchName || defaultBranch); } let c = result.data.last_commit setLastCommit(c && c.commit); setLastCommitAuthor(c && c.committer); setMainFlag(false); + setReadOnly(true); setReadOnly(!editReadme); setHide(true); } @@ -198,7 +240,7 @@ function CoderDepot(props){ // 切换分支或者标签 function changeBranch(value){ let checkvalue = turnbar(value); - let url = `/projects/${owner}/${projectsId}${value && `/tree/${checkvalue}`}${treeValue ? `/${treeValue}`:""}`; + let url = `/${owner}/${projectsId}${value && `/tree/${checkvalue}`}${treeValue ? `/${treeValue}`:""}`; props.history.push(url); } @@ -207,9 +249,13 @@ function CoderDepot(props){ let b = branchName || defaultBranch; let checkvalue = turnbar(b); return ( - - urlLink(`/projects/${owner}/${projectsId}/${checkvalue}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件 - urlLink(`/projects/${owner}/${projectsId}/${checkvalue}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件 + + + urlLink(`/${owner}/${projectsId}/${checkvalue}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件 + + + urlLink(`/${owner}/${projectsId}/${checkvalue}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件 + ) } @@ -228,12 +274,12 @@ function CoderDepot(props){ setTreeValue(undefined); let branch = branchName || defaultBranch; let checkvalue = turnbar(branch); - props.history.push(`/projects/${owner}/${projectsId}/tree/${checkvalue}`); + props.history.push(`/${owner}/${projectsId}/tree/${checkvalue}`); }; // 子目录路径返回链接 function returnUlr(url){ let enBranch = turnbar(branchName); - props.history.push(`/projects/${owner}/${projectsId}/tree${enBranch?`/${enBranch}`:""}/${url}`); + props.history.push(`/${owner}/${projectsId}/tree${enBranch?`/${enBranch}`:""}/${url}`); } // 点击跳转到子目录 function goToSubRoot(path,type,filename){ @@ -241,7 +287,7 @@ function CoderDepot(props){ let enBranch = branchName || defaultBranch; let checkvalue = turnbar(enBranch); setType(type); - props.history.push(`/projects/${owner}/${projectsId}${`/tree/${checkvalue}`}${path?`/${path}`:""}`); + props.history.push(`/${owner}/${projectsId}${`/tree/${checkvalue}`}${path?`/${path}`:""}`); } } @@ -253,7 +299,7 @@ function CoderDepot(props){ //点击直接跳转页面 加载一次路由 let enBranch = branchName || defaultBranch; let checkvalue = turnbar(enBranch); - props.history.push(`/projects/${owner}/${projectsId}/tree/${checkvalue}/${path}`); + props.history.push(`/${owner}/${projectsId}/tree/${checkvalue}/${path}`); setType("file"); setEditReadme(true); }; @@ -295,8 +341,10 @@ function CoderDepot(props){ const mdFlag = n && n.substring(n.length-3,n.length) === ".md"; const { current_user } = props; - const baseOperate = projectDetail && projectDetail.permission && projectDetail.permission !=="Reporter"; + const baseOper = current_user && current_user.login && issuesFlag; + const baseOperate = projectDetail && projectDetail.permission && projectDetail.permission !=="Reporter" && projectDetail.type !== 2 && pullsFlag; const fileOperate = type === "dir" && projectDetail && projectDetail.type !== 2 && ((projectDetail.permission && projectDetail.permission !=="Reporter") || (current_user && current_user.admin)); + return( setOpenModal(false)} onOk={okUpdate}/> @@ -341,36 +389,59 @@ function CoderDepot(props){ branchList={projectDetail && projectDetail.branches && projectDetail.branches.list} > : - 分支:{branchName || defaultBranch} + 分支:{branchName || defaultBranch} }
    - - - - 分支 - {projectDetail && projectDetail.branches && projectDetail.branches.total_count} - - - - - - 标签 - {projectDetail && projectDetail.tags && projectDetail.tags.total_count} - - + { + treeValuePath && treeValuePath.length > 0 ? + + : + + + + + 分支 + {projectDetail && projectDetail.branches_count} + + + + + + 标签 + {projectDetail && projectDetail.tags_count} + + + + } { - baseOperate && projectDetail.type !== 2 && pullsFlag && - - } - { - baseOperate && issuesFlag && - + (baseOperate || baseOper) && +
    + { + baseOperate && + urlLink(`/${owner}/${projectsId}/compare/master...${branchName || defaultBranch}`)} >+ 合并请求 + } + { + baseOper && + urlLink(`/${owner}/${projectsId}/issues/new`)} >+ 易修 + } +
    } { fileOperate && - - + + 文件 } @@ -380,37 +451,27 @@ function CoderDepot(props){
    { - dirInfo || fileInfo ? + (dirInfo && dirInfo.length>0) || fileInfo ?
    { lastCommit &&
    -
    {lastCommit && lastCommit.message}
    +
    { hideBtn && changeHide(hide)}> } - - {lastCommit && lastCommit.time_from_now} + + {lastCommit.time_from_now} { commitCount ? - - {commitCount}次提交 + + {commitCount}次提交 :"" }
    }
      - { - treeValuePath && treeValuePath.length > 0 && - - } { dirInfo && dirInfo.length > 0 && dirInfo.map((item,key)=>{ @@ -441,20 +502,21 @@ function CoderDepot(props){ : "" } { - (dirInfo && dirInfo.length === 0) && (fileInfo && fileInfo.length === 0) ? :"" + (dirInfo && dirInfo.length === 0) && !fileInfo ? :"" } {/* readme文件显示(显示文件详情时不显示readme文件) */} - { dirInfo && (readme && readme.content) ? :"" } + { (readme && readme.content) ? :"" }
    { - !fileInfo && + (!(treeValuePath && treeValuePath.length > 0) && !fileInfo) &&
    - 关于 - {projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner") && - setOpenModal(true)} className="iconfont icon-a-shezhi font-15"> + 关于 + { + projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner" || projectDetail.permission==="Manager") && + setOpenModal(true)} className="iconfont icon-a-shezhi color-grey-9 font-15"> } {desc &&

    {desc}

    } @@ -475,9 +537,9 @@ function CoderDepot(props){
    { projectDetail && projectDetail.license_name && -
    - - {projectDetail.license_name} +
    + + {projectDetail.license_name}
    }
    @@ -498,28 +560,22 @@ function CoderDepot(props){ } {/* 发布 */} { - projectDetail && projectDetail.release_versions && + releaseVersions && } {/* 贡献者 */} { - projectDetail && projectDetail.contributors && - + projectDetail && projectDetail.contributors && projectDetail.contributors.total_count >0 && + } {/* 语言 */} { projectDetail && projectDetail.languages && diff --git a/src/forge/Main/CoderDepotCatalogue.jsx b/src/forge/Main/CoderDepotCatalogue.jsx index 37fd3269..4f5d86c1 100644 --- a/src/forge/Main/CoderDepotCatalogue.jsx +++ b/src/forge/Main/CoderDepotCatalogue.jsx @@ -4,8 +4,8 @@ import { truncateCommitId } from '../common/util'; const typeIco = { "submodule":"icon-file-submodule font-17", - "file":'icon-wenjian5 font-15', - "dir":"icon-wenjianjia3 font-15" + "file":'icon-wenjian6 font-15 color-blue-file', + "dir":"icon-wenjianjia4 font-15 color-blue_4C" } function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){ @@ -13,15 +13,15 @@ function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
  • goToSubRoot(item.path,item.type,item.name)} className={item.type === "submodule" && "submoduleStyle"}> - {item.name} + {item.name} - + {item.commit && item.commit.message} - {item.commit && item.commit.time_from_now} + {item.commit && item.commit.time_from_now}
  • ) } diff --git a/src/forge/Main/CoderDepotPath.jsx b/src/forge/Main/CoderDepotPath.jsx index ad4bb109..89d6a5ca 100644 --- a/src/forge/Main/CoderDepotPath.jsx +++ b/src/forge/Main/CoderDepotPath.jsx @@ -1,3 +1,4 @@ +import { result } from 'lodash'; import React from 'react'; diff --git a/src/forge/Main/CoderDepotReadme.jsx b/src/forge/Main/CoderDepotReadme.jsx index e5f6cbc4..315f7080 100644 --- a/src/forge/Main/CoderDepotReadme.jsx +++ b/src/forge/Main/CoderDepotReadme.jsx @@ -50,7 +50,9 @@ function CoderDepotReadme({ operate , history , readme , ChangeFile }){ 目录 - README.md + + README.md + { operate ? diff --git a/src/forge/Main/CoderRootCommit.js b/src/forge/Main/CoderRootCommit.js index b6ca0be6..b542c390 100644 --- a/src/forge/Main/CoderRootCommit.js +++ b/src/forge/Main/CoderRootCommit.js @@ -1,13 +1,19 @@ import React , { Component } from 'react'; -import { Spin , Pagination } from 'antd'; +import { Spin , Pagination, Timeline } from 'antd'; import { getImageUrl } from 'educoder'; -import { truncateCommitId } from '../common/util'; +import { truncateCommitId ,timeFormat } from '../common/util'; import { AlignTop } from '../Component/layout'; import SelectBranch from '../Branch/Select'; import Nodata from '../Nodata'; +import User from '../Component/User'; +import RenderHtml from '../../components/render-html.jsx'; +import Tree from './img/tree.png'; import axios from 'axios'; import {Link} from "react-router-dom"; +import CopyTool from '../Component/CopyTool'; + +import './tree/Index.scss' function returnbar(str){ if(str && str.length>0 && str.indexOf("%2F")>-1){ @@ -15,14 +21,16 @@ function returnbar(str){ } return str; } + +//代码库--提交页面 class CoderRootCommit extends Component{ constructor(props){ - super(props) + super(props); this.state={ commitDatas:undefined, dataCount:undefined, - limit:20, - page:1, + limit:10, + page: 1, isSpining:false, branchList:undefined } @@ -50,20 +58,34 @@ class CoderRootCommit extends Component{ this.Init(); } } + + UrlParamHash(url){ + const params = {}; + let h; + let hash = url.slice(url.indexOf('?')+1).split('&'); + for(let i = 0; i{ const { branchName } = this.props.match.params; - const { page , limit } = this.state; + const { limit } = this.state; + const {search} = this.props.location; + const realPage = (search && this.UrlParamHash(search).page) ? parseInt(this.UrlParamHash(search).page) : 1; this.setState({ - isSpining:true + isSpining:true, + page:realPage }) - this.getCommitList( branchName , page , limit ); + this.getCommitList( branchName , realPage , limit ); } getCommitList=(branch , page , limit)=>{ this.setState({ isSpining:true }) - console.log(returnbar(branch)); const { projectsId , owner } = this.props.match.params; const url = `/${owner}/${projectsId}/commits.json`; axios.get(url,{ @@ -86,7 +108,8 @@ class CoderRootCommit extends Component{ image_url:item.author && item.author.image_url, sha:item.sha, time_from_now:item.time_from_now, - message:item.message + message:item.message, + timestamp:item.timestamp }) }) this.setState({ @@ -101,14 +124,13 @@ class CoderRootCommit extends Component{ // 切换分支 search:tag为根据标签搜索 changeBranch=(value)=>{ const { projectsId , owner } = this.props.match.params; - this.props.history.push(`/projects/${owner}/${projectsId}/commits/branch/${value}`); + this.props.history.push(`/${owner}/${projectsId}/commits/branch/${value}`); } ChangePage=(page)=>{ - const { branchName } = this.props.match.params; - const { limit } = this.state; - this.getCommitList(branchName , page , limit); + this.props.history.push({pathname: this.props.history.location.pathname,search: `page=${page}`}) } + render(){ const { commitDatas , dataCount , limit , page , isSpining , branchList } = this.state; const { projectDetail, commit_class , defaultBranch } = this.props; @@ -129,46 +151,50 @@ class CoderRootCommit extends Component{ >
    -
    -
    -
    - {dataCount}次提交代码({branch}) -
    -
    -
    - { - commitDatas && commitDatas.length > 0 && commitDatas.map((item,k)=>{ - return( -
    - - {truncateCommitId(`${item.sha}`)} - {item.message} - -

    - { - item.id ? - - {item.image_url?:""} - - : - - {item.image_url?:""} - - - } - -

    + + { + commitDatas && commitDatas.length > 0 && commitDatas.map((item,k)=>{ + return( + 最新:}> +
    +
    + +
    +
    +

    + + {item.timestamp && } +

    +
    +
    +
    +
    + + sha + {truncateCommitId(`${item.sha}`)} + + + +
    + +
    +
    - ) - }) - } - {commitDatas && commitDatas.length === 0 && } -
    -
    + + ) + }) + } + {commitDatas && commitDatas.length === 0 && } + { dataCount > limit ?
    - +
    :"" } diff --git a/src/forge/Main/CoderRootFileDetail.js b/src/forge/Main/CoderRootFileDetail.js index 4adb229d..bdcfc98a 100644 --- a/src/forge/Main/CoderRootFileDetail.js +++ b/src/forge/Main/CoderRootFileDetail.js @@ -1,10 +1,12 @@ import React, { Component } from "react"; -import { Popconfirm , Select } from "antd"; +import { Popconfirm , Select , Dropdown , Spin , Anchor } from "antd"; import "./list.scss"; import axios from "axios"; import Meditor from "../Newfile/m_editor"; import RenderHtml from "../../components/render-html"; +import ReadmeCatelogue from "./sub/ReadmeCatelogue"; +const $ = window.$; function bytesToSize(bytes) { if (bytes === 0) return "0 B"; let k = 1024, @@ -19,11 +21,13 @@ class CoderRootFileDetail extends Component { value: undefined, language: undefined, languages: undefined, - description: props.detail.content + description: props.detail.content, + menuList:undefined }; } componentDidMount = () => { + window.scrollTo(0, 0); const { detail , mdFlag } = this.props; this.setState({ value: detail.content, @@ -149,7 +153,7 @@ class CoderRootFileDetail extends Component { .then((result) => { if (result) { this.props.showNotification("删除成功!"); - this.props.history.push(`/projects/${owner}/${projectsId}`); + this.props.history.push(`/${owner}/${projectsId}`); } }) .catch((error) => { @@ -169,6 +173,31 @@ class CoderRootFileDetail extends Component { }); }; + renderMenulist=()=>{ + const { description } = this.state; + if(description){ + const items = $.map($("#files-md").find("h1,h2,h3,h4,h5,h6"), function (el, _) { + const anchor = el.id; + const level = el.tagName.replace("H", ""); + const href = `#${anchor}`; + return { href:`${href}`,text:el.textContent , level:level } + }); + return items; + } + return []; + } + + menu=()=>{ + const menuList = this.renderMenulist(); + if(menuList && menuList.length > 0){ + return( + + ) + }else{ + return + } + } + render() { const { readOnly, @@ -186,79 +215,88 @@ class CoderRootFileDetail extends Component { const Option = Select.Option; return ( -
    -
    - + +
    + { + md && readOnly && + + + + 目录 + + + } + {bytesToSize(detail && detail.size)}

    - {flag && platform && ( -

    - {readOnly ? ( - - { - !detail.direct_download? - - this.DownLoadFile(detail.download_url)} className="ml20"> - - - { - type !==2 && - this.EditFile(false)} className="ml20"> - + {flag && platform && ( +
    + {readOnly ? ( + + { + !detail.direct_download? + + this.DownLoadFile(detail.download_url)} className="ml20"> + - } - :"" - } - - ) : ( - - - - - )} - { - type !==2 && - - - - - - } - -
    - )} -

    -
    + { + type !==2 && + this.EditFile(false)} className="ml20"> + + + } +
    :"" + } + + ) : ( + + + + + )} + { + type !==2 && + + + + + + } + +
    + )} +

    +
    {detail.image_type ? (
    @@ -272,7 +310,7 @@ class CoderRootFileDetail extends Component {
    ) : ( md && readOnly ? -
    +
    : diff --git a/src/forge/Main/CoderRootIndex.js b/src/forge/Main/CoderRootIndex.js index 84ab94d3..7ff25dae 100644 --- a/src/forge/Main/CoderRootIndex.js +++ b/src/forge/Main/CoderRootIndex.js @@ -1,9 +1,9 @@ import React , { Component } from 'react'; import { Route , Switch } from 'react-router-dom'; -import Top from './DetailTop'; +// import Top from './DetailTop'; import Loadable from 'react-loadable'; import Loading from '../../Loading'; -import axios from 'axios'; +import './Index.scss'; const FileNew = Loadable({ loader: () => import('../Newfile/Index'), @@ -18,25 +18,25 @@ const CoderRootCommit = Loadable({ loading: Loading, }) const CoderRootBranch = Loadable({ - loader: () => import('./CoderRootBranch'), + loader: () => import('./tree/Index'), loading: Loading, }) const CoderRootTag = Loadable({ - loader: () => import('./CoderRootTag'), + loader: () => import('./tag/Index'), loading: Loading, }) const CoderRootVersion = Loadable({ - loader: () => import('../Version/version'), - loading: Loading, -}) -const CoderRootVersionNew = Loadable({ - loader: () => import('../Version/New'), - loading: Loading, -}) -const CoderRootVersionUpdate = Loadable({ - loader: () => import('../Version/New'), + loader: () => import('./version/Index'), loading: Loading, }) +// const CoderRootVersionNew = Loadable({ +// loader: () => import('./version/New'), +// loading: Loading, +// }) +// const CoderRootVersionUpdate = Loadable({ +// loader: () => import('./version/New'), +// loading: Loading, +// }) const Diff = Loadable({ loader: () => import('./Diff'), loading: Loading, @@ -50,94 +50,94 @@ class CoderRootIndex extends Component{ } } - componentDidMount=()=>{ - this.Init(); - } - componentDidUpdate=(prevProps)=>{ - const { location } = this.props; - const prevlocation = prevProps && prevProps.location; - if (location !== prevlocation) { - this.Init(); - } - } + // componentDidMount=()=>{ + // this.Init(); + // } + // componentDidUpdate=(prevProps)=>{ + // const { location } = this.props; + // const prevlocation = prevProps && prevProps.location; + // if (location !== prevlocation) { + // this.Init(); + // } + // } - Init=()=>{ - const { branchName } = this.props.match.params; - const { defaultBranch } = this.props; - this.getTopCount(branchName || defaultBranch); - } + // Init=()=>{ + // const { branchName } = this.props.match.params; + // const { defaultBranch } = this.props; + // this.getTopCount(branchName || defaultBranch); + // } // 获取组件里要显示的数据 - getTopCount=(branch)=>{ - const { projectsId , owner } = this.props.match.params; - const url = `/${owner}/${projectsId}/top_counts.json`; - axios.get(url,{params:{ - ref:branch - }}).then(result=>{ - if(result){ - this.setState({ - coderCount:result.data - }) - } - }).catch(error=>{console.log(error);}) - } + // getTopCount=(branch)=>{ + // const { projectsId , owner } = this.props.match.params; + // const url = `/${owner}/${projectsId}/top_counts.json`; + // axios.get(url,{params:{ + // ref:branch + // }}).then(result=>{ + // if(result){ + // this.setState({ + // coderCount:result.data + // }) + // } + // }).catch(error=>{console.log(error);}) + // } render(){ return( -
    - +
    + {/* */} {/* 新建文件 */} - () } > - () } > - () + (props) => () } > - () + () => () } > - () } > - () + () => () } > - () } > - () } - > - */} + () } > - () } > - () } diff --git a/src/forge/Main/CoderRootTag.js b/src/forge/Main/CoderRootTag.js index a87386d5..48483621 100644 --- a/src/forge/Main/CoderRootTag.js +++ b/src/forge/Main/CoderRootTag.js @@ -34,7 +34,7 @@ export default (( props, { projectDetail }) => {
    • - 标签名 + 标记名 提交信息 下载
    • @@ -49,7 +49,7 @@ export default (( props, { projectDetail }) => { {item.name} - {truncateCommitId(`${item.id}`)} + {truncateCommitId(`${item.id}`)} TAR diff --git a/src/forge/Main/Detail.js b/src/forge/Main/Detail.js index dc6da437..cad0874e 100644 --- a/src/forge/Main/Detail.js +++ b/src/forge/Main/Detail.js @@ -1,12 +1,15 @@ import React, { Component } from 'react'; -import { Spin, Tooltip, Button } from 'antd'; +import { Spin, Tooltip } from 'antd'; import { Link, Route, Switch } from 'react-router-dom'; -import { Content , AlignTop, AlignCenter } from '../Component/layout'; +import { Content, AlignTop } from '../Component/layout'; import DetailBanner from './sub/DetailBanner'; import { numFormat } from 'educoder'; import '../css/index.scss' import './list.scss'; +import { ImageLayerOfCommentHOC } from "../../modules/page/layers/ImageLayerOfCommentHOC"; + + import Loadable from 'react-loadable'; import Loading from '../../Loading'; @@ -68,7 +71,7 @@ const MergeIndexDetail = Loadable({ }) const CreateMerge = Loadable({ - loader: () => import('../Merge/NewMerge'), + loader: () => import('../Merge/CreateMerge'), loading: Loading, }) @@ -104,12 +107,12 @@ const Contribute = Loadable({ }) const CoderRootCommit = Loadable({ - loader: () => import('./CoderRootCommit'), - loading: Loading, + loader: () => import('./CoderRootCommit'), + loading: Loading, }) const CoderDepot = Loadable({ - loader: () => import('./CoderDepot'), - loading: Loading, + loader: () => import('./CoderDepot'), + loading: Loading, }) const TrendsIndex = Loadable({ @@ -140,28 +143,30 @@ const WikiEdit = Loadable({ /** * permission:Manager:管理员,Reporter:报告人员(只有读取权限),Developer:开发人员(除不能设置仓库信息外) */ -function checkPathname(projectsId,owner,pathname){ +function checkPathname(projectsId, owner, pathname) { let name = ""; - if(pathname && pathname !== `/projects/${owner}/${projectsId}`){ - let url = pathname.split(`/projects/${owner}/${projectsId}`)[1]; - if(url.indexOf("/about")>-1){ - name="about" - }else if(url.indexOf("/issues")>-1 ||url.indexOf("Milepost") > 0){ + if (pathname && pathname !== `/${owner}/${projectsId}`) { + let url = pathname.split(`/${owner}/${projectsId}`)[1] || ""; + if (url.indexOf("/about") > -1) { + name = "about" + } else if (url.indexOf("/issues") > -1 || url.indexOf("Milepost") > 0) { name = "issues"; - }else if(url.indexOf("/pulls")>-1){ - name="pulls" - }else if(url.indexOf("/milestones")>-1){ - name="milestones" - }else if(url.indexOf("/activity")>-1){ - name="activity" - }else if(url.indexOf("/setting")>-1){ - name="setting" - }else if(url.indexOf(`/devops`)>-1){ - name="devops" - }else if(url.indexOf(`/source`)>-1){ - name="source" - }else if(url.indexOf(`/wiki`)>-1){ - name="wiki" + } else if (url.indexOf("/pulls") > -1 || url.indexOf("/compare") > -1) { + // /pulls,合并请求除新建合并请求外, + // /compare,新建合并请求 + name = "pulls" + } else if (url.indexOf("/milestones") > -1) { + name = "milestones" + } else if (url.indexOf("/activity") > -1) { + name = "activity" + } else if (url.indexOf("/settings") > -1) { + name = "settings" + } else if (url.indexOf(`/devops`) > -1) { + name = "devops" + } else if (url.indexOf(`/source`) > -1) { + name = "source" + } else if (url.indexOf(`/wiki`) > -1) { + name = "wiki" } } return name; @@ -184,15 +189,15 @@ class Detail extends Component { branchs: undefined, branchList: undefined, project: null, - firstSync:false, - secondSync:false, - open_devops:false, - forkSpin:false, + firstSync: false, + secondSync: false, + open_devops: false, + forkSpin: false, // 默认分支 - defaultBranch:undefined, + defaultBranch: undefined, // 非本平台项目 - platform:false + platform: false } } @@ -209,36 +214,38 @@ class Detail extends Component { } getProject = (num) => { - const { projectsId , owner } = this.props.match.params; + const { projectsId, owner } = this.props.match.params; const url = `/${owner}/${projectsId}/simple.json`; axios.get(url).then((result) => { if (result && result.data) { this.setState({ project: result.data, - open_devops:result.data.open_devops, - platform:result.data.platform && result.data.platform !== 'educoder' + open_devops: result.data.open_devops, + platform: result.data.platform && result.data.platform !== 'educoder' }) if (result.data.type !== 0 && result.data.mirror_status === 1) { console.log("--------start channel --------"); // 是镜像项目,且未完成迁移 this.canvasChannel(); - if(num){ + if (num) { this.setState({ - secondSync:true, - firstSync:false + secondSync: true, + firstSync: false }) - }else{ + } else { this.setState({ - firstSync:true, - secondSync:false + firstSync: true, + secondSync: false }) } - }else{ + } else if (result.data.mirror_status === 2) { + this.deleteProjectBack(); + } else { this.getDetail(); this.setState({ - firstSync:false, - secondSync:false + firstSync: false, + secondSync: false }) } } @@ -246,12 +253,16 @@ class Detail extends Component { } // 工作流激活后修改状态 - changeOpenDevops=(flag)=>{ + changeOpenDevops = (flag) => { this.setState({ - open_devops:flag + open_devops: flag }) } - canvasChannel = () => { + /** + * + * @param {*} deleteFlag :同步镜像需要提示成功,且未成功的情况下不需要删除项目 + */ + canvasChannel = (deleteFlag) => { const name = window.location.hostname === "localhost" ? "testforgeplus.trustie.net" : window.location.hostname; const actioncable = require("actioncable"); var project = this.state.project; @@ -266,11 +277,20 @@ class Detail extends Component { disconnected: () => { }, received: data => { console.log(`###### ---received data--- ######`); + console.log(data); if (data) { - this.getDetail(); + if(deleteFlag){ + this.props.showNotification("镜像同步成功!"); + window.location.reload(); + }else{ + if (data.project && data.project.mirror_status === 2) { + this.deleteProjectBack(); + } + this.getDetail(); + } this.setState({ - firstSync:false, - secondSync:false + firstSync: false, + secondSync: false }); cable.subscriptions.consumer.disconnect(); } @@ -278,12 +298,32 @@ class Detail extends Component { }) } + deleteProjectBack = () => { + const { history } = this.props; + const { projectsId, owner } = this.props.match.params; + axios.delete(`/${owner}/${projectsId}.json`).then(res => { + let hash = '/projects/mirror/new'; + if (res && res.data) { + history.push({ + pathname: hash, + mirror_status: 2 + }); + } + else { + window.location.hash = hash; + } + }); + } + getDetail = () => { - const { projectsId , owner } = this.props.match.params; + const { projectsId, owner } = this.props.match.params; this.getBanner(); const url = `/${owner}/${projectsId}/detail.json`; axios.get(url).then((result) => { if (result && result.data) { + if (result.data.status === 404) { + this.props.history.push('/nopage'); + } this.setState({ projectDetail: result.data, project_id: result.data.project_id, @@ -296,29 +336,29 @@ class Detail extends Component { watchers_count: result.data.watchers_count, praises_count: result.data.praises_count, forked_count: result.data.forked_count, - defaultBranch:result.data.default_branch + defaultBranch: result.data.default_branch }) } }).catch((error) => { }) } // 获取动态导航栏菜单 - getBanner(){ - const { projectsId , owner } = this.props.match.params; + getBanner() { + const { projectsId, owner } = this.props.match.params; const url = `/${owner}/${projectsId}/menu_list.json`; - axios.get(url).then(result=>{ - if(result){ + axios.get(url).then(result => { + if (result) { this.setState({ - bannerList:result.data + bannerList: result.data }) } - }).catch(error=>{}) + }).catch(error => { }) } // 关注和取消关注 focusFunc = (flag) => { const { platform } = this.state; - if(!platform)return; + if (!platform) return; const { project_id } = this.state; axios({ @@ -333,15 +373,15 @@ class Detail extends Component { this.setWatchersCount(result.data.watchers_count, result.data.watched); } }) - .catch(error => { - console.log(error); - }); + .catch(error => { + console.log(error); + }); } // 点赞和取消点赞 pariseFunc = (flag) => { const { platform } = this.state; - if(!platform)return; + if (!platform) return; const { project_id } = this.state; axios({ method: flag ? 'delete' : 'post', @@ -351,9 +391,9 @@ class Detail extends Component { this.setPraisesCount(result.data.praises_count, result.data.praised) } }) - .catch(error => { - console.log(error); - }); + .catch(error => { + console.log(error); + }); } setWatchersCount = (count, is_watched) => { @@ -373,24 +413,24 @@ class Detail extends Component { // fork项目 forkFunc = () => { const { platform } = this.state; - if(!platform)return; + if (!platform) return; this.setState({ - forkSpin:true + forkSpin: true }) 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`; axios.post(url).then(result => { if (result && result.data.status === 0) { - this.props.history.push(`/projects/${current_user && current_user.login}/${result.data.identifier}`); + this.props.history.push(`/${current_user && current_user.login}/${result.data.identifier}`); this.props.showNotification(result.data.message); } this.setState({ - forkSpin:false + forkSpin: false }) }).catch(error => { this.setState({ - forkSpin:false + forkSpin: false }) }) } @@ -398,13 +438,15 @@ class Detail extends Component { // 同步镜像 synchronismMirror = () => { const { platform } = this.state; - if(!platform)return; - const { projectsId , owner } = this.props.match.params; + if (!platform) return; + const { projectsId, owner } = this.props.match.params; const url = `/${owner}/${projectsId}/sync_mirror.json`; axios.post(url).then(result => { if (result && result.data && result.data.status === 0) { - this.props.showNotification("镜像同步成功!"); - this.getProject(2); + this.setState({ + secondSync:true + }) + this.canvasChannel(true); } else { this.props.showNotification("镜像同步失败!"); } @@ -413,113 +455,124 @@ class Detail extends Component { }) } - textFunc = (forked_from_project_id,fork_info)=>{ + textFunc = (forked_from_project_id, fork_info) => { let type = fork_info && fork_info.fork_project_user_type; return forked_from_project_id && fork_info ?
      复刻自 - {fork_info.fork_project_user_name} + {fork_info.fork_project_user_name} / - {fork_info.fork_form_name} + {fork_info.fork_form_name}
      : "" } render() { - const { projectDetail, watchers_count, praises_count, - forked_count, firstSync , secondSync , - isManager, watched, praised, - project , open_devops , platform , defaultBranch , bannerList , forkSpin } = this.state; + const { projectDetail, watchers_count, praises_count, + forked_count, firstSync, secondSync, + isManager, watched, praised, + project, open_devops, platform, defaultBranch, bannerList, forkSpin } = this.state; const url = this.props.history.location.pathname; const urlArr = url.split("/"); 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 common = { getDetail: this.getDetail, - changeOpenDevops:this.changeOpenDevops, + changeOpenDevops: this.changeOpenDevops, defaultBranch } return (
      - - + +
      {project && project.author && - {project.author.name} + {project.author.name} } / - {projectDetail && projectDetail.name} + {projectDetail && projectDetail.name}
      - { projectDetail && projectDetail.private && 私有} + {projectDetail && projectDetail.private && 私有}
      - +
      + { + projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ? + this.textFunc(projectDetail.forked_from_project_id, projectDetail.fork_info) + : "" + } + { + projectDetail && projectDetail.type && projectDetail.type !== 0 ? + 导入于 {projectDetail.mirror_url} + : "" + } +
      +
      { - firstSync ? "": - - { - ((current_user && current_user.admin) || isManager) && (projectDetail && projectDetail.type && projectDetail.type === 2) ? - 同步镜像 : "" - } - - this.focusFunc(watched)}> - - {watched ? '取消关注' : '关注'} - + firstSync ? "" : + { - watchers_count > 0 ? - platform ? - - {numFormat(watchers_count)} - - : - {watchers_count} - :"" + ((current_user && current_user.admin) || isManager) && (projectDetail && projectDetail.type && projectDetail.type === 2) ? + 同步镜像 : "" } - - - this.pariseFunc(praised)}> - - {praised ? '取消点赞' : '点赞'} - - { - praises_count > 0 ? - platform ? - - {numFormat(praises_count)} - : - {praises_count} - :"" - } - - - - - - 复刻 + + this.focusFunc(watched)}> + + {watched ? '取消关注' : '关注'} - - { - forked_count > 0 ? - platform ? - - {numFormat(forked_count)} - - : - {forked_count} - :"" - } + { + watchers_count > 0 ? + platform ? + + {watchers_count} + + : + {watchers_count} + : "" + } + + + this.pariseFunc(praised)}> + + {praised ? '取消点赞' : '点赞'} + + { + praises_count > 0 ? + platform ? + + {praises_count} + : + {praises_count} + : "" + } + + + + + 复刻(Fork) + + + { + forked_count > 0 ? + platform ? + + {forked_count} + + : + {forked_count} + : "" + } + - }
      @@ -537,225 +590,240 @@ class Detail extends Component {
      { firstSync ? "" : - + }
      { firstSync ? - - - - : - - - {/* 资源 */} - () - } - > - {/* 主页 */} - () - } - > - {/* wiki新增文件 */} - () - } - > - {/* wiki编辑文件 */} - () - } - > - {/* wiki */} - () - } - > - {/* 工作流 */} - () - } - > - {/* 标签列表 */} - () - } - > - {/* 仓库设置 */} - () - } - > - {/* 任务详情 */} - () - } - > - {/*修改里程碑*/} - () - } - > - {/* 新建里程碑 */} - () - } - > - {/*里程碑详情*/} - () - } - > - {/* 里程碑 */} - () - } - > - {/* 里程碑页面新建任务 */} - () - } - > - {/* 新建任务 */} - () - } - > - {/* 修改详情 */} - () - } - > - {/* 复制详情 */} - () - } - > - {/* 动态 */} - () - } - > - {/* 代码Index */} - () - } - > - {/* 新建合并请求 */} - () - } - > - () - } - > - () - } - > - () - } - > - () - } - > + + + + : + + + {/* 资源 */} + () + } + > + {/* 主页 */} + () + } + > + {/* wiki新增文件 */} + () + } + > + {/* wiki编辑文件 */} + () + } + > + {/* wiki */} + () + } + > + {/* 工作流 */} + () + } + > + {/* 标签列表 */} + () + } + > + {/* 仓库设置 */} + () + } + > + + {/*修改里程碑*/} + () + } + > + {/* 新建里程碑 */} + () + } + > + {/*里程碑详情*/} + () + } + > + {/* 里程碑 */} + () + } + > + {/* 里程碑页面新建任务 */} + () + } + > + {/* 新建任务 */} + () + } + > + {/* 修改详情 updatedetail*/} + () + } + > + {/* 复制详情 copyetail*/} + () + } + > + + {/* 任务详情 */} + () + } + > + {/* 动态 */} + () + } + > + {/* 代码Index */} + () + } + > + {/* 新建合并请求 */} + {/* () + } + > */} + () + } + > + () + } + > + () + } + > + () + } + > + () + } + > + () + } + > - () - } - > - () - } - > - () - } - > - () - } - > - {/* 贡献者列表 */} - () - } - > + () + } + > + () + } + > + () + } + > + () + } + > + {/* 贡献者列表 */} + () + } + > - {/* 代码库----详情页面 */} - () - } - > - () - } - > - () - } - > - () - } - > - - + {/* 代码库----详情页面 */} + () + } + > + () + } + > + () + } + > + () + } + > + + }
    ) } } -export default Detail; +export default ImageLayerOfCommentHOC({ + imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget", + parentSelector: ".newContainer", +})(Detail); diff --git a/src/forge/Main/DetailAdaptor.js b/src/forge/Main/DetailAdaptor.js new file mode 100644 index 00000000..d65f3bc3 --- /dev/null +++ b/src/forge/Main/DetailAdaptor.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { Route, Switch } from "react-router-dom"; +import { withRouter } from "react-router"; +import Loadable from "react-loadable"; +import Loading from "../../Loading"; +import { SnackbarHOC } from "educoder"; +import { CNotificationHOC } from "../../modules/courses/common/CNotificationHOC"; +import { TPMIndexHOC } from "../../modules/tpm/TPMIndexHOC"; + +// forge项目详情 +const ProjectDetail = Loadable({ + loader: () => import("../Main/Detail"), + loading: Loading, +}); +export default withRouter( + (CNotificationHOC()(SnackbarHOC()(TPMIndexHOC((props) => { + return ( + + ( + + )} + > + + ) + })))) +) \ No newline at end of file diff --git a/src/forge/Main/DetailTop.js b/src/forge/Main/DetailTop.js index 260ff1e6..ecd5ab9f 100644 --- a/src/forge/Main/DetailTop.js +++ b/src/forge/Main/DetailTop.js @@ -12,19 +12,19 @@ class DetailTop extends Component { { platform ? - 0 ? "active" : ""}> + 0 ? "active" : ""}> {(coderCount && coderCount.commits_count) || 0}个提交 - 0 ? "active" : ""}> + 0 ? "active" : ""}> {(coderCount && coderCount.branches_count) || 0}个分支 - 0 ? "active" : ""}> + 0 ? "active" : ""}> {(coderCount && coderCount.tags_count) || 0}个标签 - 0 ? "active" : ""}> + 0 ? "active" : ""}> {(coderCount && coderCount.version_releasesed_count) || 0}个发行版 diff --git a/src/forge/Main/Diff.jsx b/src/forge/Main/Diff.jsx index a6b0b49c..8dad59fb 100644 --- a/src/forge/Main/Diff.jsx +++ b/src/forge/Main/Diff.jsx @@ -1,35 +1,65 @@ import React, { useEffect, useState } from "react"; import styled from "styled-components"; import { Button ,Spin } from "antd"; -import { truncateCommitId } from '../common/util'; +import { timeFormat, truncateCommitId } from '../common/util'; import { getImageUrl } from 'educoder'; import Files from '../Merge/Files'; - +import Tree from "./img/tree.png"; import User from "../Component/User"; -import Keys from "../Component/Keys"; - +import RenderHtml from "../../components/render-html"; import axios from "axios"; +import { Link } from "react-router-dom"; const Infos = styled.div` - border: 1px solid #dddddd; + border: 1px solid #FAFCFF; margin-bottom:15px; & .commitinfos { background-color: #f1f8ff; - border-bottom: 1px solid #ddd; - padding: 20px; + border: 1px solid rgba(42, 97, 255, 0.23); + border-radius: 3px 3px 0px 0px; + padding: 10px 20px 10px 16px; + & .markdown-body table{ + background: #f1f8ff; + } + & .btnblue{ + margin-top: 12px; + } + & .task-hide{ + width: 65rem; + overflow:hidden; + white-space:normal; + word-break:break-all; + font-weight: bold; + color: #333333; + font-size: 16px; + } } & > .f-wrap-between { - padding: 10px 20px; + padding: 14px 20px 14px 16px; + border-radius: 3px 3px 0px 0px; + border: 1px solid #D0D0D0; + .df{ + align-items: center; + & .underline:hover{ + text-decoration: underline; + } + } } `; - -export default ({ match , history }) => { +function turnbar(str){ + if(str && str.length>0 && str.indexOf("/")>-1){ + return str.replaceAll('/','%2F'); + } + return str; +} +//提交详情页 +export default (props) => { + const {match , history } = props; const [data, setData] = useState({undefined}); const [commit, setCommit] = useState(undefined); const [parents, setParents] = useState(undefined); const [committer, setCommitter] = useState(undefined); const [isSpin, setIsSpin] = useState(true); - const { sha , projectsId, owner } = match.params; useEffect(() => { if (projectsId && owner && sha) { @@ -43,6 +73,7 @@ export default ({ match , history }) => { setParents(result.data.parents); setCommitter(result.data.committer || (result.data.commit && result.data.commit.committer)); setIsSpin(false); + } }) .catch(error => { @@ -56,29 +87,42 @@ export default ({ match , history }) => {
    - {commit && commit.message && -
    {commit.message}
    - } - +
    + {commit && commit.message && + + } + {data.branch} +
    +
      - {committer && committer.time_from_now &&
    • {committer.time_from_now}
    • } + {commit && commit.timestamp &&
    • 提交于{timeFormat(commit.timestamp)}
    • }
  • { parents && parents.length > 0 && parents.map((item,key)=>{ return( - +
    + + sha + {truncateCommitId(item.sha)} +
    ) }) } - +
    + + sha + {truncateCommitId(sha)} +
  • @@ -87,6 +131,7 @@ export default ({ match , history }) => { data={data} owner={owner} projectsId={projectsId} + parentsSha={parents && parents.length > 0 && parents[0].sha} />
    diff --git a/src/forge/Main/Index.js b/src/forge/Main/Index.js index 0169d84b..3b1f66db 100644 --- a/src/forge/Main/Index.js +++ b/src/forge/Main/Index.js @@ -1,5 +1,4 @@ import React, { Component } from 'react'; -import { Link } from 'react-router-dom'; import { Menu, Input , Spin, Pagination , Popover , Select } from 'antd'; import Slider from "react-slick"; import { getImageUrl } from 'educoder'; @@ -13,6 +12,8 @@ import axios from 'axios'; import img_new from '../Images/new.png'; import img_array from '../Images/array.png'; import banner from '../Images/banner_list.jpg'; +import CheckProfile from '../Component/ProfileModal/Profile'; + const Search = Input.Search; class Index extends Component { @@ -228,7 +229,7 @@ class Index extends Component { } getoDetail=(login,identifier)=>{ - this.props.history.push(`/projects/${login}/${identifier}`); + this.props.history.push(`/${login}/${identifier}`); } // 选择语言类别 @@ -254,10 +255,14 @@ class Index extends Component { newItem = ()=>{ return( - - 新建镜像项目 - 新建托管项目 - +
      +
    • + {this.props.history.push('/projects/deposit/new')}}>新建项目 +
    • +
    • + {this.props.history.push('/projects/mirror/new')}}>导入项目 +
    • +
    ) } @@ -387,7 +392,13 @@ class Index extends Component {
    { current_user && current_user.login && - + 新建 diff --git a/src/forge/Main/Index.scss b/src/forge/Main/Index.scss index d6331066..5f369292 100644 --- a/src/forge/Main/Index.scss +++ b/src/forge/Main/Index.scss @@ -13,6 +13,21 @@ } } } +.iconBtn{ + i{ + color: #666; + } + span{ + margin-left: 4px; + color: #333!important; + &:last-child{ + font-weight: 500; + } + } + &:hover span,&:hover i{ + color: #466AFF!important; + } +} /* recommandProjects */ .recommandProjects.slick-slider{ width: 1230px; @@ -113,8 +128,8 @@ margin-right: -5px; } .ant-btn{ - height: 36px; - line-height: 34px; + height: 32px; + line-height: 32px; width: 83px; text-align: center; padding:0px ; @@ -130,26 +145,30 @@ } .ant-btn-primary{ color: #fff; - background-color: #2A61FF; + background-color: #466AFF; + border: none; + &:hover{ + background-color: rgba(70,106,255,0.85); + } } } } - .addOptionBtn{ - height: 32px; - line-height: 30px; + .depotBtn,.addOptionBtn{ display: flex; - border:1px solid #d9d9d9; - border-radius: 2px; a{ - padding:0px 13px; - color: rgba(0, 0, 0, 0.65); - cursor: pointer; - } - & > a:first-child{ - border-right: 1px solid #d9d9d9; - } - & > a:last-child{ - border-right: none; + color: #333!important; + font-weight: 500!important; + border-radius: 5px; + width: 83px; + height: 32px; + line-height: 30px; + background: #fff; + border: 1px solid #D0D0D0; + margin-right: 10px; + text-align: center; + &:hover,&:active{ + background: #F3F4F6; + } } } .infoCount{ @@ -170,28 +189,28 @@ flex-wrap: wrap; padding-bottom: 2px; a{ - margin: 0px 17px 0px 0px; + margin: 0px 17px 10px 0px; img{ border-radius: 50%; width: 40px; height: 40px; } - &:nth-child(6){ + &:nth-child(5n){ margin-right: 0px; } } } .progress{ display: flex; - border-radius: 10px; - height: 7px; + border-radius: 2px; + height: 11px; margin-top: 12px; span{ &:first-child{ - border-radius: 10px 0px 0px 10px; + border-radius: 2px 0px 0px 2px; } &:last-child{ - border-radius: 0px 10px 10px 0px; + border-radius: 0px 2px 2px 0px; } } } @@ -205,7 +224,7 @@ height: 8px; width: 8px; left: 0px; - top:10px + top:8px; } &>span{ padding-left: 15px; @@ -228,12 +247,19 @@ justify-content: space-between; align-items: flex-start; border-bottom: 1px solid #d9d9d9; - padding:13px 20px; + padding:12px 20px 11px; border-radius: 4px 4px 0px 0px; border: 1px solid rgba(42, 97, 255, 0.23); background-color: #FAFCFF; .ellipsistxt{ - margin-top: 6px; + &:hover .markdown-body{ + color: #466AFF; + & a{ + color: #466AFF; + } + } + margin-top: 2px; + // cursor: pointer; #ptxt{ margin-bottom: 0px; word-break: break-all; @@ -243,6 +269,27 @@ white-space:-pre-wrap; /* Opera 4-6 */ white-space:-o-pre-wrap; /* Opera 7 */ word-wrap:break-word; + .markdown-body{ + line-height: 10px; + font-size: 14px; + & p { + margin: 1px 0px 0px !important; + font-size: 14px !important; + } + & ol,ul{ + padding-bottom: 3px; + & li{ + min-height: 18px; + } + } + & table{ + line-height: 1; + background: #FAFCFF; + } + &:first-child { + margin-top: -1px !important; + } + } } margin-left: 13px; line-height:18px; @@ -250,7 +297,7 @@ width: 0; color: #666; &.hidetxt{ - height: 18px; + height: 24px; overflow: hidden; position: relative; padding-right:8px; @@ -292,7 +339,7 @@ } } & > li{ - height: 44px; + height: 38px; display: flex; justify-content: space-between; align-items: center; @@ -369,11 +416,29 @@ line-height: 50px; } } +.fileMenu{ + width: 83px; + li{ + padding:6px 0px!important; + text-align: center; + width: 100%; + } +} .catelogue{ cursor: pointer; background: #FAFBFC; 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; + } + } border: 1px solid #D0D0D0; font-size: 15px; font-weight: normal; @@ -403,7 +468,7 @@ .pinfos{ i,a{color: #666;} &:hover i,&:hover a{ - color: #2A61FF; + color: #2A61FF!important; } } .graph{ @@ -415,8 +480,32 @@ } } .ant-anchor-wrapper{ - padding-left: 2px; + padding-left: 2px!important; .ant-anchor-ink::before{ background-color: #fff; } +} +.coderSubPage{ + width: 1200px; + margin:0px auto; +} +.griditemAnchor{ + margin-left: 0px!important; + padding: 0px!important; + border-bottom: 1px solid #ddd; + .ant-anchor{ + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 20px; + } + .griditemCate{ + color: #333; + font-size: 16px; + display: flex; + align-items: center; + .catelogue{ + margin-left: 0px; + } + } } \ No newline at end of file diff --git a/src/forge/Main/IndexItem.js b/src/forge/Main/IndexItem.js index 4f9740c1..0cba9123 100644 --- a/src/forge/Main/IndexItem.js +++ b/src/forge/Main/IndexItem.js @@ -28,35 +28,35 @@ class IndexItem extends Component { : - + }
    - + {item.author.name}/{item.name} { !item.is_public && 私有 } { item.forked_from_project_id ? - + - + : "" } { item.type && item.type === 2 ? - + :"" } { item.type && item.type === 1 ? - + - :"" + :"" } diff --git a/src/forge/Main/img/tree-black.png b/src/forge/Main/img/tree-black.png new file mode 100644 index 00000000..02aa71c3 Binary files /dev/null and b/src/forge/Main/img/tree-black.png differ diff --git a/src/forge/Main/img/tree.png b/src/forge/Main/img/tree.png new file mode 100644 index 00000000..56247256 Binary files /dev/null and b/src/forge/Main/img/tree.png differ diff --git a/src/forge/Main/list.scss b/src/forge/Main/list.scss index b4a966b2..59589fb6 100644 --- a/src/forge/Main/list.scss +++ b/src/forge/Main/list.scss @@ -226,21 +226,20 @@ flex-direction: row; cursor: pointer; li{ - font-size: 14px; - position: relative; text-align: center; - height: 40px; - line-height: 28px; - padding:0px 20px; + padding:0px; + margin-right: 40px; + display: flex; & > a{ - color: #666; - &> img{ - margin-right: 8px; - } + position: relative; + font-size: 14px; + height: 36px; + line-height: 24px; + display: block; + color: #000!important; &> span.num{ line-height: 24px; margin-left: 5px; - margin-top: 2px; font-size: 12px; float: right; color: #666!important; @@ -250,25 +249,26 @@ height: 24px; } } - &.active a,&.active a i{ - color: #2A61FF!important; - } - &.active::after,&:hover::after{ + + &.active a::after,&:hover a::after{ position: absolute; bottom:0px; height:2px; - background-color: #2A61FF; + background-color:rgba(153, 153, 153, 0.2); content:''; left: 0px; width:100%; } - &:hover::after{ - background-color: rgba(153, 153, 153, 0.2);; + &.active span{ + font-weight: 500; + } + &.active a::after{ + background-color: #466AFF; } } } .detail_tag_btn{ - height:34px; + height:32px; line-height: 32px; border-radius:5px; border:1px solid #D0D0D0; @@ -278,18 +278,18 @@ padding:0px; background-color:#FAFBFC; box-shadow: none; - &:hover{ - background-color: #F3F4F6; - } .detail_tag_btn_name{ - padding:0px 18px; - min-width: 82px; + padding:0px 10px; text-align: center; - &:hover>span{ - color: #333!important; + height: 30px; + line-height: 30px; + border-radius:5px 0px 0px 5px; + &:hover + { + background-color: #F3F4F6; } - img{ - margin-right: 10px; + span{ + color: #333!important; } } .detail_tag_btn_count{ @@ -354,7 +354,7 @@ .gitAddressClone{ - margin:0px 20px 14px 20px!important; + margin:14px 20px!important; display: flex; height: 40px; align-items: center; @@ -426,14 +426,15 @@ border-right: none; } .gitAddressClone > input{ - border:none; outline: none; - padding:0px 8px; - height: 40px; - line-height: 40px; - border-radius: 0px; - border: 1px solid #eee; - flex:1; + padding: 0px 8px; + height: 38px; + line-height: 38px; + border: none!important; + border-right: 1px solid #eee!important; + border-radius: 4px 0px 0px 4px; + flex: 1; + max-width: 249px; } .wrap-commit-table .ant-table-small > .ant-table-content > .ant-table-body{ margin:0px; @@ -572,8 +573,11 @@ } .commonBox{ border:1px solid #ddd; - margin-top: 30px; + margin-top: 18px; border-radius: 4px; + .ant-anchor-wrapper{ + overflow: unset!important; + } } .commonBox .commonBox-title{ padding:0px 20px; @@ -598,8 +602,8 @@ .commonBox .commonBox-title.boxTitle{ display: flex; justify-content: space-between; - height: 65px; - line-height: 65px; + height: 55px; + line-height: 55px; background: #FAFCFF; border-radius: 4px 4px 0px 0px; border: 1px solid rgba(42, 97, 255, 0.23); @@ -623,8 +627,11 @@ } .commonBox-title-read{ vertical-align: middle; - color: #666; + color: #000; font-size: 14px; + &:hover { + color: #466AFF; + } } @media screen and (max-width: 370px){ @@ -715,12 +722,84 @@ a.color-grey-ccc:hover{ padding:0px 30px; min-height: 400px; } -.commitList > div{ - border-bottom: 1px solid #EEEEEE; - padding:16px 0px; -} -.commitList > div:last-child{ - border-bottom: none; + +.main{ + margin: 30px auto; + .ant-timeline{ + margin-top: 28px; + .commitList-item{ + position: relative; + padding: 20px 20px; + background: #FAFCFF; + border: 1px solid rgba(42, 97, 255, 0.23); + border-radius: 4px; + margin-left: 16px; + & .treecopy{ + margin-top: 20px; + } + & .markdown-body table{ + background: #FAFCFF; + } + &:after,&:before{ + content: ""; + position: absolute; + left: -10px; + top: 10px; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + border-right: 10px solid rgba(42, 97, 255, 0.23); + } + &:after{ + left: -8px; + border-right: 10px solid #FAFCFF; + &:hover{ + border-right: 10px solid #EEF6FF; + } + } + &:hover{ + background: #EEF6FF; + border: 1px solid rgba(42, 97, 255, 0.58); + &:after{ + border-right: 10px solid #EEF6FF; + } + &:before{ + border-right: 10px solid rgba(42, 97, 255, 0.58); + } + & .markdown-body table{ + background: #EEF6FF; + } + } + .treecopy-cont{ + padding: 4px 15px; + } + .btn-83{ + margin-left: 20px; + } + } + .ant-timeline-item{ + padding: 8px 0 20px; + } + .ant-timeline-item-tail{ + height: calc(100% - 20px); + border-left: 2px solid #EEEEEE; + top: 12px; + &:after{ + content: ' '; + height: 0; + position: absolute; + width: 0; + border: 7px solid transparent; + border-top-color: #EEEEEE; + top: 100%; + left: 50%; + margin-left: -8px; + } + } + .ant-timeline-item-head-custom{ + top:20px; + padding: 0 1px; + } + } } diff --git a/src/forge/Main/sub/Contribute.jsx b/src/forge/Main/sub/Contribute.jsx index f65b4524..76d56dc8 100644 --- a/src/forge/Main/sub/Contribute.jsx +++ b/src/forge/Main/sub/Contribute.jsx @@ -52,7 +52,7 @@ function Contribute(props){
    - {item.name} + {item.name}

    提交{item.contributions}次

    diff --git a/src/forge/Main/sub/DetailBanner.jsx b/src/forge/Main/sub/DetailBanner.jsx index 1a6bd4f6..22a5ce41 100644 --- a/src/forge/Main/sub/DetailBanner.jsx +++ b/src/forge/Main/sub/DetailBanner.jsx @@ -11,7 +11,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa if(pathname && pathname==="source"){ let a = list.filter(item=>item.menu_name === "resources"); if(a && a.length === 0){ - history.push(`/projects/${owner}/${projectsId}`); + history.push(`/${owner}/${projectsId}`); } } setMenuName(list); @@ -29,38 +29,38 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa { item.menu_name === "home" &&
  • - - + + 主页 - +
  • } { item.menu_name === "code" &&
  • - - + + 代码库 - +
  • } { item.menu_name === "issues" &&
  • - - - - 易修 + + + + 易修(Issue) + {projectDetail && projectDetail.issues_count ? {numFormat(projectDetail.issues_count)} : ""} -
  • } { item.menu_name === "pulls" && projectDetail && parseInt(projectDetail.type) !== 2 && platform ?
  • - - + + 合并请求 {projectDetail && projectDetail.pull_requests_count ? {numFormat(projectDetail.pull_requests_count)} : ""} @@ -69,8 +69,8 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa { item.menu_name === "wiki" &&
  • - - + + Wiki
  • @@ -78,47 +78,48 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa { item.menu_name === "devops" && platform ?
  • - - 工作流(beta版) - {projectDetail && projectDetail.ops_count ? {numFormat(projectDetail.ops_count)} : ""} + {/* */} + + 工作流(beta版) + {projectDetail && projectDetail.ops_count ? {projectDetail.ops_count} : ""}
  • :"" } - { + {/* { item.menu_name === "resources" &&
  • - - - 资源库 - {projectDetail && projectDetail.source_count ? {numFormat(projectDetail.source_count)} :""} + + + 资源库 + {projectDetail && projectDetail.source_count ? {projectDetail.source_count} :""}
  • - } + } */} { item.menu_name === "versions" &&
  • - - - 里程碑 - {projectDetail && projectDetail.versions_count ? {numFormat(projectDetail.versions_count)} :""} + + + 里程碑 + {projectDetail && projectDetail.versions_count ? {numFormat(projectDetail.versions_count)} :""}
  • } { item.menu_name === "activity" &&
  • - + 动态
  • } { - item.menu_name === "setting" && -
  • - - 0 ? "iconfont icon-cangkushezhiicon color-grey-3 mr5 font-14":"iconfont icon-cangkushezhiicon color-grey-6 font-14 mr5"}> + item.menu_name === "settings" && +
  • + + 0 ? "iconfont icon-cangkushezhiicon color-grey-3 mr5 font-14":"iconfont icon-cangkushezhiicon color-grey-6 font-14 mr5"}> 仓库设置
  • diff --git a/src/forge/Main/sub/Invite.jsx b/src/forge/Main/sub/Invite.jsx index e621bd6d..201cee6d 100644 --- a/src/forge/Main/sub/Invite.jsx +++ b/src/forge/Main/sub/Invite.jsx @@ -1,26 +1,15 @@ import React from 'react'; -import { Tooltip , message } from 'antd'; import './sub.scss'; +import CopyTool from '../../Component/CopyTool'; 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(
    邀请码
    - {code} - 可以通过邀请码邀请成员加入项目
    点击复制邀请码。

    } placement={"bottom"}> - jsCopy("#devitecode")}> -
    + + 可以通过邀请码邀请成员加入项目
    点击复制邀请码。

    } className="ml8 font-16" inputId="devitecode"/>
    ) diff --git a/src/forge/Main/sub/ReadmeCatelogue.jsx b/src/forge/Main/sub/ReadmeCatelogue.jsx index d1e018bb..6dab7d79 100644 --- a/src/forge/Main/sub/ReadmeCatelogue.jsx +++ b/src/forge/Main/sub/ReadmeCatelogue.jsx @@ -1,7 +1,7 @@ -import React , { useState , useEffect } from 'react'; +import React , { useState } from 'react'; import { Anchor , Input } from 'antd'; import './sub.scss'; -import { Base64 } from 'js-base64'; +import { useEffect } from 'react'; const { Link } = Anchor; @@ -18,7 +18,7 @@ function ReadmeCatelogue({ menuList , hash }) { function changeValue(e) { setValue(e.target.value); if(e.target.value){ - let m = menuList.filter(i=>i.text.indexOf(e.target.value)>-1); + let m = menuList.filter(i=>i.text.toLowerCase().indexOf(e.target.value.toLowerCase())>-1); setMenu(m); }else{ setMenu(menuList); diff --git a/src/forge/Main/sub/SubMenu.jsx b/src/forge/Main/sub/SubMenu.jsx new file mode 100644 index 00000000..78f37b4d --- /dev/null +++ b/src/forge/Main/sub/SubMenu.jsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import'./sub.scss' + +function SubMenu({tab,owner,projectsId}) { + return( +
      + 标签 + 发行版 +
    + ) +} +export default SubMenu; \ No newline at end of file diff --git a/src/forge/Main/sub/UpdateDescModal.jsx b/src/forge/Main/sub/UpdateDescModal.jsx index 5039123a..b0291f34 100644 --- a/src/forge/Main/sub/UpdateDescModal.jsx +++ b/src/forge/Main/sub/UpdateDescModal.jsx @@ -53,7 +53,7 @@ function UpdateDescModal({form , visible , onCancel , onOk,desc,website,lesson_u {getFieldDecorator("lesson_url",{ rules:[] })( - + )} diff --git a/src/forge/Main/sub/sub.scss b/src/forge/Main/sub/sub.scss index 4e6a3d8a..7716f0c5 100644 --- a/src/forge/Main/sub/sub.scss +++ b/src/forge/Main/sub/sub.scss @@ -64,4 +64,28 @@ background-color: #fff; } } +} +.subMenu{ + display: flex; + padding-top: 30px; + a{ + width: 83px; + font-weight: 500; + line-height: 30px; + height: 32px; + color: #333333!important; + text-align: center; + border: 1px solid #D0D0D0; + border-radius: 0px 4px 4px 0px; + background: rgba(250, 251, 252, 0); + &:first-child{ + border-right: none; + border-radius: 4px 0px 0px 4px; + } + &.active{ + background-color: #466AFF; + color: #fff!important; + border-color: #466AFF; + } + } } \ No newline at end of file diff --git a/src/forge/Main/tag/Index.jsx b/src/forge/Main/tag/Index.jsx new file mode 100644 index 00000000..ff764851 --- /dev/null +++ b/src/forge/Main/tag/Index.jsx @@ -0,0 +1,138 @@ +import React,{ useEffect , useState } from 'react'; +import SubMenu from '../sub/SubMenu'; +import { Table , Tooltip , Spin } from 'antd'; +import axios from 'axios'; +import { Link } from 'react-router-dom'; +import { truncateCommitId } from '../../common/util'; +import { getImageUrl } from 'educoder'; +import Nonedata from '../../Nodata'; +import './Index.scss'; +import Tree from '../img/tree.png' +import moment from 'moment'; + +function Tags(props) { + + const [ source , setSource ] = useState(undefined); + const [ isSpin , setIsSpin ] = useState(true); + + const { projectsId , owner } = props.match.params; + + useEffect(() => { + if (projectsId) { + const url = `/${owner}/${projectsId}/tags.json`; + axios.get(url).then((result) => { + if (result) { + setSource(result.data); + setIsSpin(false); + } + }).catch(error => {}) + } + }, [owner, projectsId]); + + const columns=[ + { + title:"标签名", + dataIndex:"name", + key:1, + ellipsis:true, + width:"200px", + render:(txt,item)=>{ + return( +
    + {item.name} +
    + ) + } + }, + { + title:"创建时间", + dataIndex:"time_ago", + key:2, + ellipsis:true, + render:(txt,item)=>{ + return ( + + { + item.tagger && + + { + item.tagger.id ? + + + + : + + + + } + + } + 创建于{txt} + + ) + } + }, + { + title:"提交ID", + dataIndex:"id", + key:3, + ellipsis:true, + render:(txt,item)=>{ + return ( + + 提交ID + {truncateCommitId(item.id)} + + ) + } + }, + { + title:"描述信息", + dataIndex:"message", + key:4, + ellipsis:true, + render:(txt,item)=>{ + return item.message || "--" + } + }, + { + title:"下载", + dataIndex:"stage_type", + key:5, + ellipsis:true, + align:"center", + width:"204px", + render:(txt,item)=>{ + return ( + + + TAR + + + ZIP + + + ) + } + } + ] + return( +
    + + +
    + { + source && source.length > 0 && +
    + } + { + source && source.length === 0 && + } +
    +
    +
    + ) +} +export default Tags; \ No newline at end of file diff --git a/src/forge/Main/tag/Index.scss b/src/forge/Main/tag/Index.scss new file mode 100644 index 00000000..6adba91e --- /dev/null +++ b/src/forge/Main/tag/Index.scss @@ -0,0 +1,58 @@ +.tagTable{ + margin-top: 30px; + thead{ + tr th{ + background-color: #fff; + padding:5px 0px; + width: 172px; + .ant-table-column-title{ + font-size: 16px; + font-weight: 500; + color: #333333; + } + } + } + tbody{ + .btn-83{ + margin:0px 8px; + } + tr{ + &:hover td{ + background-color: #fff!important; + } + td{ + padding:0px; + height: 69px; + line-height: 69px; + color:#333333; + div{ + font-weight: 500; + } + } + &:last-child{ + td{ + border-bottom: none!important; + } + } + } + } +} +.tagSpin{ + min-height: 300px; +} +.tagBranch{ + padding-right: 15px; + text-overflow: ellipsis; + overflow: hidden; + .tagClass{ + color:#333333; + } +} +.tagModel{ + font-weight: 400; + .tagModelImg img{ + width: 25px; + height: 25px; + border-radius: 50%; + } +} \ No newline at end of file diff --git a/src/forge/Main/tree/Index.jsx b/src/forge/Main/tree/Index.jsx new file mode 100644 index 00000000..2fc57434 --- /dev/null +++ b/src/forge/Main/tree/Index.jsx @@ -0,0 +1,114 @@ +import React , { useEffect , useState } from 'react'; +import CopyTool from '../../Component/CopyTool'; +import { truncateCommitId } from '../../common/util'; +import { Link } from 'react-router-dom'; +import { getImageUrl } from 'educoder'; +import { Dropdown , Menu , Spin } from 'antd'; +import './Index.scss'; + +import Tree from '../img/tree.png'; +import Axios from 'axios'; + +function turnbar(str){ + if(str && str.length>0 && str.indexOf("/")>-1){ + return str.replaceAll('/','%2F'); + } + return str; +} +function Index(props) { + const [ list , setList ] = useState([]); + const [ isSpin , setIsSpin ] = useState(true); + + const { projectsId , owner } = props.match.params; + const { isManager , isDeveloper , projectDetail } = props; + + useEffect(()=>{ + getList(); + },[]) + + + const menu =(zip_url,tar_url)=> ( + + ZIP + TAR.GZ + + ) + + function getList() { + const url = `/${owner}/${projectsId}/branches_slice.json`; + Axios.get(url).then(result=>{ + if(result){ + setList(result.data); + } + setIsSpin(false); + }).catch(error=>{setIsSpin(false);}) + } + + return( + +
    + { + list && list.length>0 && list.map((item,key)=>{ + return( + +

    {item.branch_type === "default" ? "默认分支" : item.branch_type==="protected"?"保护分支":"其它分支"}

    + { + item.list && item.list.length>0 && +
      + { + item.list.map((i,k)=>{ + let last_commit = i.last_commit; + return( +
    • +
      + {i.name} +
      + { + last_commit && last_commit.committer && last_commit.committer.id? + + + {last_commit && last_commit.committer && last_commit.committer.name} + + : + + + {last_commit && last_commit.committer && last_commit.committer.name} + + } + 更新于{last_commit && last_commit.time_from_now} +
      +
      +
      +
      + + sha + {truncateCommitId(last_commit && last_commit.sha)} + + + +
      +
      +
      + { + (isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) && + + 合并请求 + } + + 下载 + +
      +
    • + ) + }) + } +
    + } +
    + ) + }) + } +
    +
    + ) +} +export default Index; \ No newline at end of file diff --git a/src/forge/Main/tree/Index.scss b/src/forge/Main/tree/Index.scss new file mode 100644 index 00000000..f65a1c68 --- /dev/null +++ b/src/forge/Main/tree/Index.scss @@ -0,0 +1,101 @@ +.branchSort{ + font-weight: 500; + color: #333333; + font-size: 15px; + height: 20px; + line-height: 20px; + padding-left: 10px; + margin-top: 20px; + margin-bottom: 6px!important; +} +.treeUl{ + background: #FAFCFF; + border-radius: 4px; + border: 1px solid rgba(42, 97, 255, 0.23); + li{ + display: flex; + align-items: center; + justify-content: space-between; + padding: 12px 20px; + border-bottom: 1px solid rgba(42, 97, 255, 0.23); + &:last-child{ + border-bottom: none; + } + .treeinfo{ + width: 399px; + flex:1; + flex-direction: column; + &>a{ + display: block; + width: 399px; + + } + a:hover{ + span{ + color: #466AFF!important; + } + } + img{ + height: 20px; + width: 20px; + margin-right: 5px; + } + } + .treeabout{ + flex:1; + text-align: right; + } + } +} +.treecopy{ + flex:1; + display: flex; + justify-content: center; + &>div{ + height: 32px; + background: #FAFBFC; + border-radius: 4px; + border: 1px solid #D0D0D0; + position: relative; + z-index: 1; + display: flex; + align-items: center; + &>span{ + padding:0px 15px; + border-right: 1px solid rgba(153, 153, 153, 0.4); + height: 100%; + img{ + margin-right: 4px; + } + a{ + color: #466AFF; + &:hover{ + text-decoration: underline; + } + } + } + &>i{ + margin:0px 12px; + color: #333!important; + } + input{ + position: absolute; + z-index: 0; + opacity: 0; + top: 32px; + } + } +} +.new-conmmit{ + width: 30px; + height: 18px; + line-height: 18px; + display: block; + background: #FF6832; + color: white; + font-size: 12px; + border-radius: 4px; +} +.icon-a-yuanquan2x{ + color: #466AFF; +} \ No newline at end of file diff --git a/src/forge/Main/version/Empty.jsx b/src/forge/Main/version/Empty.jsx new file mode 100644 index 00000000..3200d3e8 --- /dev/null +++ b/src/forge/Main/version/Empty.jsx @@ -0,0 +1,22 @@ +import { Button } from 'antd'; +import React from 'react'; +import './version.scss'; + +function Empty({operation,addFunc}) { + return( +
    + + 这里暂未发布过任何版本 + 发行版功能基于仓库中的历史标记
    建议使用类似 V1.0 的版本标记作为发布点
    +
    + { + operation ? + + : + 该项目暂时没有发布版本 + } +
    +
    + ) +} +export default Empty; \ No newline at end of file diff --git a/src/forge/Main/version/Index.jsx b/src/forge/Main/version/Index.jsx new file mode 100644 index 00000000..37cc8c12 --- /dev/null +++ b/src/forge/Main/version/Index.jsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { Switch , Route } from 'react-router'; +import Loadable from 'react-loadable'; +import Loading from '../../../Loading'; +import SubMenu from '../sub/SubMenu'; +import "./version.scss"; + +const CoderRootVersion = Loadable({ + loader: () => import('./version'), + loading: Loading, +}) +const CoderRootVersionNew = Loadable({ + loader: () => import('./New'), + loading: Loading, +}) +function Index(props) { + const { projectsId , owner } = props.match.params; + return( +
    + + + () + } + > + () + } + > + () + } + > + +
    + ) +} +export default Index; \ No newline at end of file diff --git a/src/forge/Main/version/New.jsx b/src/forge/Main/version/New.jsx new file mode 100644 index 00000000..8adde9b0 --- /dev/null +++ b/src/forge/Main/version/New.jsx @@ -0,0 +1,266 @@ +import React, { useState, useEffect, forwardRef } from "react"; +import styled from "styled-components"; +import { AutoComplete , Input, Checkbox, Button, Form } from "antd"; +import SelectBranch from '../../Branch/Select'; + +import Editor from "../../../modules/tpm/challengesnew/tpm-md-editor"; +import Upload from "../../Upload/Index"; +import Attachments from "../../Upload/attachment"; +import axios from "axios"; +import "./version.scss"; +import { trim } from "lodash"; + +const { Option } = AutoComplete; + +const Span = styled.span` + margin: 0px 15px; + color: #bbb; + line-height: 35px; + font-size:16px; + font-weight:400; + color:#666; +`; +export default Form.create()( + forwardRef( + ( + { form, projectDetail , match, showNotification, history }, + ref + ) => { + const { getFieldDecorator, validateFields, setFieldsValue } = form; + const [tagList, setTagList] = useState(undefined); + const [desc, setDesc] = useState(null); + const [branch, setBranch ] = useState(null); + const [fileList, setFileList] = useState(undefined); + const [attachment, setAttachment] = useState(undefined); + const [options , setOptions] = useState(undefined); + const stable = history && history.location && history.location.state.stable; + const { projectsId, versionId , owner } = match.params; + + useEffect(()=>{ + if(projectDetail && projectDetail.default_branch){ + setBranch(projectDetail.default_branch); + } + },[projectDetail]) + + + useEffect(() => { + if (versionId) { + const url = `/${owner}/${projectsId}/releases/${versionId}/edit.json`; + axios.get(url).then(result => { + if (result) { + setFieldsValue(result.data); + setDesc(result.data.body); + setAttachment(result.data.attachments); + } + }); + } + }, [versionId]); + + useEffect(() => { + if (projectsId) { + const url = `/${owner}/${projectsId}/tags.json`; + axios + .get(url,{params:{ + limit:1000 + }}) + .then(result => { + if (result) { + setTagList(result.data); + setOptions(renderTagList(result.data)); + } + }) + .catch(error => { + console.log(error); + }); + } + }, [projectsId]); + + function renderTagList(list) { + if (list) { + let array = list.map((item, key) => { + return ( + + ); + }); + return array || undefined; + } + } + function submit() { + validateFields((err, value) => { + if(err)return; + if (versionId) { + let url = `/${owner}/${projectsId}/releases/${versionId}.json`; + axios + .put(url, { + ...value, + body: desc, + attachment_ids: fileList, + target_commitish:branch + }) + .then(result => { + if (result) { + showNotification("版本修改成功!"); + history.push(`/${owner}/${projectsId}/releases`); + } + }); + } else { + let url = `/${owner}/${projectsId}/releases.json`; + axios.post(url, { + ...value, + body: desc, + attachment_ids: fileList + }) + .then(result => { + if (result) { + showNotification("版本发布成功!"); + history.push(`/${owner}/${projectsId}/releases`); + } + }); + } + }); + } + // 输入标签名 + function changeAuto(value){ + let l = tagList.filter(item=>item.name.indexOf(value) > -1); + setOptions(renderTagList(l)); + } + + function changeBranch(params) { + setBranch(params); + } + + return ( +
    +
    +
    + + {getFieldDecorator("tag_name", + { rules:[ + { required: true, message: "请输入获取或选择一个标签" }, + { validator: (rule,val,callback) =>{ + if(val.length>30 || val.indexOf(' ')>0 || val.match(/^\s+$/) || trim(val).length!=val.length){ + callback('无效的标签名称,请参考右侧建议命名标签并确认长度在1~30个字符之间'); + }else{ + callback(); + } + }}], + validateFirst: true + })( + + {options} + + )} + + @ + +

    选择一个已经存在的标签,或者在发布时新建一个标签

    +
    + + {getFieldDecorator("name", + { rules:[ + { required: true, message: "请输入发行版的标题" }, + { validator: (rule,val,callback) =>{ + if(val.length>50){ + callback('标题长度在1~50个字符之间'); + }else{ + callback(); + } + }}], + validateFirst: true + })( + + )} + + + +
    + + } + size={100} + showNotification={showNotification} + /> + {versionId && attachment && attachment.length > 0 ? ( + + ) : ( + "" + )} +
    + + {getFieldDecorator("prerelease", + { rules:[], + validateFirst: true + })( + 这是一个预览版本 + )} + +

    + + +

    + +
    +
    +

    标签命名建议

    +

    + 通常的做法是在版本名称前加上字母 v 前缀, v1.0 或者 v2.3.4。 +

    +

    + 如果标签不适合在生产环境下使用,请在版本名称后添加预发行版本。例如:v0.2-alpha + 或者 v5.9-beta.3。 +

    +
    +
    +

    语义化版本

    +

    + 如果你是第一次发布版本,我们强烈建议你阅读语义化版本。 +

    +
    +
    +

    附件大小说明

    +

    + 单个附件不能超过 100M(GVP 项目200M),每个仓库总附件不可超过 + 1G(推荐项目不可超过 5G;GVP 项目不可超过 + 20G)。附件总容量统计包括仓库附件和发行版附件。 +

    +
    +
    +
    + ); + } + ) +); diff --git a/src/forge/Main/version/version.js b/src/forge/Main/version/version.js new file mode 100644 index 00000000..2896899f --- /dev/null +++ b/src/forge/Main/version/version.js @@ -0,0 +1,150 @@ +import React, { useEffect , useState } from "react"; +import { Link } from 'react-router-dom'; +import { Spin , Button } from 'antd'; +import { getImageUrl } from 'educoder'; +import {truncateCommitId} from '../../common/util'; +import Empty from './Empty'; +import './version.scss'; +import axios from 'axios'; +import Tree from '../img/tree-black.png'; +import RenderHtml from '../../../components/render-html'; +import User from "../../Component/User"; + +function version(props) { + const [ data , setData ] = useState(undefined); + const [ releases , setReleases ] = useState(undefined); + const [ isSpin , setIsSpin ] = useState(true); + const { projectsId ,owner } = props.match.params; + const { location } = props; + const type = props.projectDetail && props.projectDetail.type; + const turnFromNew = location && location.query && location.query.turnFromNew; + useEffect(()=>{ + getIssueList(); + },[]) + // 获取列表数据 + function getIssueList(){ + const url = `/${owner}/${projectsId}/releases.json`; + axios.get(url).then((result) => { + if (result) { + setData(result.data); + const { releases = [] } = result.data; + //默认第一个展开(body参数) + releases.length && (releases[0].bodyshow = true); + setReleases(result.data.releases); + setIsSpin(false); + } + }).catch((error) => { + console.log(error); + }) + } + // 显示版本描述 + function showBody(key,flag){ + var lists = releases.concat(); + lists[key].bodyshow = !flag ? true : false; + lists.splice(); + setReleases(lists); + } + //删除 + function deleteRelease(releaseId) { + if(releaseId){ + axios.delete(`/${owner}/${projectsId}/releases/${releaseId}.json`).then((result)=>{ + if(result){ + getIssueList(); + } + }) + } + } + function release(item,key){ + return ( +
    + + {item.draft} + + + {item.tag_name} + + + + {truncateCommitId(item.sha)} + + +
    +
    + {item.name} + + {data && data.user_admin_permission && type !== 2 && } + {data && data.user_admin_permission && type !== 2 && {deleteRelease(item.version_id)}}>} + +
    + + showBody(key,item.bodyshow)}> + + 发布于{item.created_at} + + { + item.bodyshow && +
    + +
    + } + +

    + {/* 发行版附件下载 */} + {item.attachments && item.attachments.map((item)=>{ + return(下载 {item.title}) + })} + {/* 发行版下载包 */} + 下载 {item.tag_name}.TAR.gz + 下载 {item.tag_name}.ZIP +

    +
    +
    + ) + } + function renderList(releases){ + if (releases && releases.length > 0) { + return ( + + { + data && data.user_admin_permission && type !== 2 && +
    + +
    + } +
    + {!turnFromNew ? releases.map((item, key) => release(item,key)) : release(releases[0],0)} +
    +
    + ) + } else if (releases && releases.length === 0) { + return ( + + ) + } else{ + return (
    ) + } + } + + function addFunc(){ + props.history.push({pathname:`/${owner}/${projectsId}/releases/new`,state:{stable:true}}); + } + + return ( +
    +
    + + {renderList(releases)} + +
    +
    + ) +} +export default version; \ No newline at end of file diff --git a/src/forge/Main/version/version.scss b/src/forge/Main/version/version.scss new file mode 100644 index 00000000..7cd5ddb4 --- /dev/null +++ b/src/forge/Main/version/version.scss @@ -0,0 +1,357 @@ +.topWrapper { + padding: 20px 0; + box-sizing: border-box; + display: flex; + justify-content: space-between; + border-bottom: 1px solid #EEEEEE; + align-items: center; +} +.topWrapper_btn_new { + background: #fff; + color: #5091FF!important; + padding:0px 12px; + text-align: center; + height: 32px; + line-height: 32px; + border-radius: 4px; + border:1px solid #5091FF; +} +.versionInfo{ + display: flex; + width: 100%; +} +.versionInfo_left{ + display: flex; + width: 182px; + flex-direction: column; + align-items: flex-end; + padding-right: 15px; + &>.color-grey-3{ + max-width: 10rem; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } +} +.versionInfo_right{ + flex: 1; + display: flex; + flex-direction: column; + align-items: flex-start; + border-left: 1px solid #eee; + position: relative; + padding: 0px 30px 60px 24px; + &::before{ + position: absolute; + left: -4px; + top:0px; + content: ''; + width: 8px; + height: 8px; + background-color: #466AFF; + border-radius: 50%; + } + .sendAuthorImg{ + width: 20px; + height: 20px; + border-radius: 50%; + margin-right: 5px; + } + .body-show{ + padding: 5px 10px 10px 10px; + } + & .version-user>a>span{ + display: inline-block; + & img{ + width: 20px; + height: 20px; + } + } +} +.versionTag{ + display: inline; + padding:0px 9px; + color: #fff; + position: relative; + margin-top: -8px; + height: 22px; + line-height: 20px; + border-radius: 4px; + &::before{ + position: absolute; + content: ""; + width: 0; + height: 0px; + border-left: 4px solid #cccccc; + border-top: 4px solid transparent; + border-bottom: 4px solid transparent; + border-right: 4px solid transparent; + z-index: 9; + top: 6px; + right: -9px; + } + &:after{ + width: 0px; + height: 0px; + top:6px; + right: -7px; + position: absolute; + border-left:4px solid #fff; + border-top:4px solid transparent; + border-bottom:4px solid transparent; + border-right:4px solid transparent; + content:''; + z-index:10; + } +} +.versionFile{ + margin-top: 5px; + padding-top: 20px; + border-top: 1px solid #eee; + // width: 100%; + a{ + display: block; + color: #333; + font-weight: 400; + height: 20px; + margin-bottom: 10px; + } +} +.versionTag.yellow{ + border: 1px solid #FBBC06; + color: #FBBC06; + &::before{ + border-left-color: #FBBC06; + } +} +.versionTag.green{ + border: 1px solid #2DB44D; + color: #2DB44D; + &::before{ + border-left-color: #2DB44D; + } +} +.versionTag.orange{ + border: 1px solid #FF6E23; + color: #FF6E23; + &::before{ + border-left-color: #FF6E23; + } +} +.addReleaseBtn{ + text-align: right; + margin-bottom: 30px; +} +.versionName{ + font-size: 16px; + color: #333; + margin-bottom: 15px; + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + height: 18px; + line-height: 18px; + margin-top: -5px; +} + + +.versionmilepostleft{ + padding: 15px; + margin-right: 50px; + width: 80%; + } +.topWrapper_btn_close { + background: #504b4b; + color: #FFFFFF!important; + padding:0px 12px; + text-align: center; + height: 32px; + line-height: 32px; + border-radius: 4px; + } + + .topWrapper_btn_delete { + background: #da1010; + color: #FFFFFF!important; + padding:0px 12px; + text-align: center; + height: 32px; + line-height: 32px; + border-radius: 4px; + } + + .versionrighe{ + flex: 2; + } + .versionleft{ + flex: 1; + text-align: right; + display: flex; + justify-content: right; + } + + /* .version_line{ + display: flex; + height: 30px; + margin: auto; + border-left:1px solid #eee; + } */ + .version_line_one{ + display: flex; + height: 45px; + margin: auto; + border-left:1px solid #eee; + } + + .version_line_tpw{ + display: flex; + height: 80px; + margin: auto; + border-left:1px solid #eee; + } + + .versiondiv{ + display: flex; + } + .verwinth{ + width: 80%; + } + + /*开启中 关闭中*/ +.opendversionetail{ + display: inline-block; + background: #21ba45; + color: #ffffff!important; + padding:0px 5px; + text-align: center; + height: 25px; + /*width: 110px;*/ + border-radius: 4px; + line-height: 25px; +} +.closedversionetail{ + display: inline-block; + background: #e60b0b; + color: #ffffff!important; + padding:0px 5px; + text-align: center; + height: 25px; + /*width: 110px;*/ + border-radius: 4px; + line-height: 25px; +} +.versionrectangle { + width: 8px; + height: 8px; + border-radius: 100%; + margin-top: 15px; + margin-left: -4px; + margin-bottom: 10px; + background: rgb(83, 81, 81); + } +.ver-middle{ + vertical-align: middle; +} +/* new */ +.versionForm{ + flex:1; + padding-right: 40px; + box-sizing: border-box; + .ant-select-auto-complete.ant-select .ant-input:hover,.ant-input:hover { + border-color: rgba(153, 153, 153, 0.8); + } +} +.versionTips{ + width:268px; + box-sizing: border-box; +} +.infosTip{ + border-bottom: 1px solid #EEEEEE; + color: #333; + padding-bottom: 26px; + margin-bottom: 26px; + font-weight: 400; + text-align: justify; + &:last-child{ + border-bottom: none; + } +} +.dragBox{ + background: rgba(153, 153, 153, 0.04); + border-radius: 4px; + border: 1px dashed #d9d9d9; + padding:20px; + .versionStyle{ + border: none!important; + padding-bottom:20px; + .dragIcon{ + font-size: 40px!important; + color: #666!important; + line-height: 40px; + height: 40px; + margin-bottom: 14px; + display: block; + } + } + .ant-upload-list-item:hover .ant-upload-list-item-info { + background-color: rgba(239, 244, 255, 1); + } + .ant-upload-list-item-info{ + padding:0px 20px 0px 8px; + &>span{ + display: flex; + align-items: center; + } + } +} + +.set-ant-row .ant-row{ + display: flex; + height: 20px; + align-items: center; +} +.itemInline{ + display: flex; + align-items: flex-start; + position: relative; + &>p{ + position: absolute; + bottom: -5px; + } +} +.itemInline .ant-row{ + margin-bottom: 0px; +} +.prerelease{ + padding-top: 20px; + .ant-form-item-control{ + height: 20px; + line-height: 20px; + } +} +.releaseIndex{ + margin: 30px auto; + width: 1200px; +} +.emptyPanel{ + width: 100%; + background: #FAFCFF; + border-radius: 4px; + border: 1px solid rgba(42, 97, 255, 0.23); + min-height: 418px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + .operation{ + width: 400px; + border-top: 1px solid #eee; + padding-top: 34px; + text-align: center; + margin-top: 30px; + } +} +.ant-form-item-control{ + line-height: initial; +} \ No newline at end of file diff --git a/src/forge/Merge/Commits.jsx b/src/forge/Merge/Commits.jsx index 37c254cc..93e867ae 100644 --- a/src/forge/Merge/Commits.jsx +++ b/src/forge/Merge/Commits.jsx @@ -16,10 +16,10 @@ function Commits({ commits , projectsId , owner }){
    - {truncateCommitId(`${item.sha}`)} + {truncateCommitId(`${item.sha}`)}

    {item.message}

    - 浏览代码 + 浏览代码
    :提交于{item.time_from_now} diff --git a/src/forge/Merge/CreateMerge.js b/src/forge/Merge/CreateMerge.js new file mode 100644 index 00000000..d7a32009 --- /dev/null +++ b/src/forge/Merge/CreateMerge.js @@ -0,0 +1,448 @@ +import React, { Component } from 'react'; +import { Input, Select, Spin, Alert } from 'antd'; +import axios from 'axios'; +import MergeForm from './merge_form'; +import MergeFooter from './merge_footer'; + +import '../Order/order.css'; +import './merge.css'; + +/** + * 根据url获取目标仓库、目标分支、源仓库、源分支 + * 路由规则:owner/projectId/compare/merge...pullowner:pullBranch + * 可能存在的情况 + * 1、代码库首页跳转,仓库相同,目标分支为默认分支,owner/projectId/compare/pullBranch + * 2、代码库分支列表,仓库相同,目标分支为默认分支,owner/projectId/compare/pullBranch + * 3、合并请求列表页(新建、无数据时的提示),仓库相同,源、目标都为默认分支,owner/projectId/compare + * 4、新建页面,切换分支、切换目标仓库、刷新页面等,存在所有可能情况 + */ +function getBranchParams(pathname) { + const result = { + // 目标仓库所有者 + mergeOwner: undefined, + // 目标分支 + mergeBranch: 'master', + // 源仓库所有者 + pullOwner: undefined, + // 源分支 + pullBranch: 'master', + // 仓库名称 + projectId: undefined, + }; + // 去掉第一个字符/ + const _pathname = pathname.slice(1); + const [ownerProject, branchUrl] = _pathname.split('/compare'); + const [mergeOwner, projectId] = ownerProject.split('/'); + // 同仓库时 + result.mergeOwner = mergeOwner; + result.pullOwner = mergeOwner; + result.projectId = projectId; + if (branchUrl) { + // 如果存在具体的分支 + const _branchUrl = branchUrl.slice(1); + if (_branchUrl.indexOf('...') > -1) { + // 存在源分支与目标分支 + const [mergeBranch, pullObj] = _branchUrl.split('...'); + result.mergeBranch = mergeBranch; + if (pullObj.indexOf(':') > -1) { + // 存在源仓库 + const [pullOwner, pullBranch] = pullObj.split(':'); + result.pullOwner = pullOwner; + result.pullBranch = pullBranch; + } else { + result.pullBranch = pullObj; + } + } else { + result.pullBranch = _branchUrl; + } + } + return result; +} + +const Option = Select.Option; + +class CreateMerge extends Component { + constructor(props) { + super(props); + const { pullBranch, mergeBranch } = getBranchParams( + this.props.location.pathname + ); + this.state = { + data: undefined, + pullBranches: undefined, + mergeBranches: undefined, + mergeProjects: undefined, + merge: mergeBranch || 'master', + pull: pullBranch || 'master', + id: undefined, + // isFork: false, + projects_names: undefined, + isSpin: true, + showMessage: false, + merge_head: false, // 是否向fork后的源项目发起合并请求 + defaultMessage: '必须选择不同的分支', + project_id: undefined, // 当前项目的id,也即开始发送合并请求的源项目id + merge_project_user: undefined, + comparesData: undefined, //提交和文件的内容,保存compare接口返回的数据 + // 比较分支时的加载效果 + isCompareSpin: true, + // 是否是初次加载,用这个字段来控制提示组件和文件组件的显示、隐藏比直接用isCompareSpin交互友好些 + isFirstLoading: true, + }; + } + + componentDidMount = () => { + // 初始化时根据url获取目标仓库、分支,源仓库、分支; + // 再获取对应的仓库列表、分支列表 + // 再调用比较接口 + const branchParams = getBranchParams(this.props.location.pathname); + this.getMergeInfo(branchParams); + }; + + componentDidUpdate = (preProps) => { + // url变化触发时(切换源分支、切换目标仓库、切换目标分支;回退) + const oldPathname = preProps.location.pathname; + const newPathname = this.props.location.pathname; + if (oldPathname !== newPathname) { + const branchParams = getBranchParams(newPathname); + this.getMergeInfo(branchParams); + } + }; + + //获取新建合并请求数据 + getMergeInfo = (branchParams) => { + this.setState({ isSpin: true }); + const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId } = + branchParams; + const url = `/${pullOwner}/${projectId}/pulls/new.json`; + axios + .get(url) + .then((result) => { + if (result) { + // 如果url上的分支不存在,取默认值master + const noMergeBranch = + (result.data.branches || []).filter( + (branch) => branch.name === mergeBranch + ).length === 0; + const noPullBranch = + (result.data.branches || []).filter( + (branch) => branch.name === pullBranch + ).length === 0; + this.setState({ + // isFork: result.data.is_fork, + projects_names: result.data.projects_names, + mergeProjects: result.data.merge_projects, + pullBranches: result.data.branches, + mergeBranches: result.data.branches, + project_id: result.data.project_id, + id: result.data.id, + merge: mergeBranch, + pull: pullBranch, + }); + + //判断源分支是否存在 + if(noPullBranch){ + this.setState({ + showMessage: true, + defaultMessage:'源分支不存在', + isCompareSpin: false, + }); + }else{ + if(pullOwner === mergeOwner){ + if (!noMergeBranch) { + this.compareProject(true, branchParams); + } else { + this.setState({ + showMessage: true, + defaultMessage:'目标分支不存在', + isCompareSpin: false, + }); + } + }else{ + this.getBranchList(branchParams); + } + } + } + this.setState({ isSpin: false }); + }) + .catch((error) => { + this.setState({ isSpin: false }); + console.log(error); + }); + }; + + // compare接口,获取分支对比信息 + compareProject = (sameProject, branchParams) => { + // const { project } = this.props; + // const { owner, projectsId } = this.props.match.params; + const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId } = + branchParams; + + let url = `/${mergeOwner}/${projectId}/compare`; + if (sameProject) { + url += `/${pullBranch}...${mergeBranch}.json`; + } else { + url += `/${mergeBranch}...${pullOwner}/${projectId}:${pullBranch}.json`; + } + this.setState({ isSpin: false, isCompareSpin: true }); + axios + .get(url) + .then((result) => { + if (result) { + if (result.data.status === 0) { + this.setState({ + showMessage: false, + }); + } else { + this.setState({ + showMessage: true, + defaultMessage: result.data.message, + }); + } + this.setState({ + comparesData: result.data, + }); + } + this.setState({ + isFirstLoading: false, + isSpin: false, + isCompareSpin: false, + }); + }) + .catch((error) => { + this.setState({ isSpin: false, isCompareSpin: false }); + }); + }; + + // 根据所有者、仓库名,获取分支列表,目前仅涉及目标仓库分支查询 + getBranchList = (branchParams) => { + const { mergeOwner, projectId, mergeBranch } = branchParams; + this.setState({ isSpin: true }); + const url = `/${mergeOwner}/${projectId}/pulls/get_branches.json`; + axios + .get(url) + .then((result) => { + if (result) { + const noMergeBranch = + (result.data || []).filter((branch) => branch.name === mergeBranch) + .length === 0; + this.setState({ + mergeBranches: result.data, + showMessage: noMergeBranch, + defaultMessage: '目标分支不存在', + isCompareSpin: false, + }); + !noMergeBranch && this.compareProject(false, branchParams); + } + this.setState({ isSpin: false }); + }) + .catch((error) => { + this.setState({ isSpin: false }); + console.log(error); + }); + }; + + // 切换分支事件 + selectBrach = (type, value) => { + const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId } = + getBranchParams(this.props.location.pathname); + let _url = `/${mergeOwner}/${projectId}/compare/`; + // type为pull时,pullBranch取value,否则取原有值 + // type为pull时,mergeBranch取原有值,否则取value + let _pullBranch = type === 'pull' ? value : pullBranch; + let _mergeBranch = type === 'pull' ? mergeBranch : value; + if (pullOwner === mergeOwner) { + // 如果仓库相同, compare/目标分支...源分支 + _url += `${_mergeBranch}...${_pullBranch}`; + } else { + // 如果仓库不同, compare/目标分支...源分支 + _url += `${_mergeBranch}...${pullOwner}:${_pullBranch}`; + } + this.props.history.push(_url); + }; + + // 切换仓库响应事件,目前仅目标分支可切换仓库 + selectProjectName = (value) => { + const { projects_names, id } = this.state; + const { pullOwner, pullBranch } = getBranchParams( + this.props.location.pathname + ); + let arr = + projects_names && projects_names.filter((item) => item.id === value); + let identifier = arr && arr[0].project_id; + let login = arr && arr[0].project_user_login; + // 目标仓库与源仓库不是一个仓库 + let is_fork = parseInt(value, 10) !== parseInt(id, 10); + this.setState({ + isSpin: true, + // merge_head: is_fork, + data: { + is_original: is_fork, + fork_project_id: is_fork ? id : '', + merge_user_login: is_fork + ? projects_names[0].project_user_login + : undefined, + }, + }); + if (login === pullOwner) { + // 如果切换后, 仓库与源仓库一致了 + this.props.history.push( + `/${login}/${identifier}/compare/master...${pullBranch}` + ); + } else { + this.props.history.push( + `/${login}/${identifier}/compare/master...${pullOwner}:${pullBranch}` + ); + } + // this.newMergelist(login, identifier); + }; + + // 渲染分支列表 + renderBrances = (list) => { + if (list && list.length > 0) { + return list.map((item, key) => { + return ( + + ); + }); + } + }; + + // 渲染项目列表 + renderProjectNames = (list) => { + if (list && list.length > 0) { + return list.map((item, key) => { + return ( + + ); + }); + } + }; + + // 渲染html内容 + withHtml = (html) => { + return
    ; + }; + + render() { + const { + data, + pullBranches, + mergeBranches, + mergeProjects, + pull, + merge, + isSpin, + isCompareSpin, + isFirstLoading, + showMessage, + defaultMessage, + projects_names, + id, + comparesData, + } = this.state; + + let { project } = this.props; + + return ( +
    + +
    +
    +
    +
    源分支:
    + + + + +
    +
    + +
    +
    +
    +
    目标分支:
    + + + + +
    +
    +
    + {/* 非加载状态且有提示 */} + {!isCompareSpin && showMessage && ( +
    + +
    + )} + {/* 非加载状态且可以提交 */} + {!isCompareSpin && !showMessage && ( + + )} +
    + {!isFirstLoading && ( + + )} +
    +
    + ); + } +} + +export default CreateMerge; diff --git a/src/forge/Merge/Files.jsx b/src/forge/Merge/Files.jsx index 40e617c2..b4cf5b48 100644 --- a/src/forge/Merge/Files.jsx +++ b/src/forge/Merge/Files.jsx @@ -1,17 +1,24 @@ import React ,{useEffect,useState } from 'react'; import { truncateCommitId } from '../common/util'; import { AlignCenter , FlexAJ } from '../Component/layout'; -import { Button } from 'antd'; +import { Tooltip,Progress } from 'antd'; import './merge.css'; +import './Index.scss'; -function Files({data,history,owner,projectsId}){ +function Files({ data,history,owner,projectsId , parentsSha }){ const [ files , setFiles ] = useState(data && data.files); - + const [ copyfileTipTitle, setCopyfileTipTitle] = useState("复制文件路径"); + const [ isOpen, setIsOpen] = useState(false); + useEffect(()=>{ if(data){ setFiles(data.files); } - },[data]) + },[data]); + + useEffect(()=>{ + document.addEventListener('click',()=>{setIsOpen(false)}) + }) function showDown(flag,index,isBin){ if(!isBin){ @@ -22,35 +29,86 @@ function Files({data,history,owner,projectsId}){ } } + function copyFileName(fileName){ + var copyCont = document.createElement('input'); + copyCont.defaultValue = fileName; + document.body.appendChild(copyCont); + copyCont.select(); // 选择对象 + document.execCommand("Copy"); // 执行浏览器复制命令 + copyCont.className = 'copyCont'; + copyCont.style.display='none'; + setCopyfileTipTitle("复制成功"); + } + + const folderOpen = ( + + ) + return( -
    - - - - 共有 {data && data.files_count} 个文件被更改,包括 +
    {e.nativeEvent.stopImmediatePropagation()}}> + +
    {setIsOpen(!isOpen)}}> + + + 共有 {data && data.files_count} 个文件 被更改,包括 { data && data.total_addition ? {data && data.total_addition} 次插入:"" } { data && data.total_addition && data.total_deletion ? " 和 ":""} { data && data.total_deletion ? {data && data.total_deletion} 次删除:""} - + +
    + {isOpen && folderOpen}
    { files && files.length>0 && -
    +
    { files.map((item,key)=>{ return(
    - showDown(item.flag,key,item.isBin)}> + + - {!item.isBin ? :""} - - {item.name} + {!item.isBin ? showDown(item.flag,key,item.isBin)}>:""} + showDown(item.flag,key,item.isBin)}>{item.name} + setCopyfileTipTitle("复制文件路径")} + > + copyFileName(item.name)}> + - - - +{item.addition} - -{item.deletion} - +
    + 0 ? ":":""} ${item.addition > 0 ? item.addition + "处添加" : ""}${item.addition > 0 && item.deletion > 0 ? "和" : ""}${item.deletion > 0 ? item.deletion + "处删除" : ""}`}> + + {item.addition+item.deletion}处 + + { + !item.isSubmodule && + {history.push(`/${owner}/${projectsId}${item.isDeleted ? `/commits/${truncateCommitId(parentsSha)}`:`/tree/${truncateCommitId(item.sha)}/${item.name}`}`)}}>查看文件 + } +
    { item.sections && item.sections.length >= 1 && !item.flag && diff --git a/src/forge/Merge/Index.scss b/src/forge/Merge/Index.scss index 936b868f..16cc9563 100644 --- a/src/forge/Merge/Index.scss +++ b/src/forge/Merge/Index.scss @@ -18,4 +18,86 @@ .pr_tags_closed{ border:1px solid #FA6400; color: #FA6400; +} +.update-file-count{ + cursor: pointer; + & .color-grey-3{ + font-weight: bold; + } +} +.fileList{ + .sc-bxivhb{ + width: 55rem; + overflow: hidden; + white-space: normal; + word-break: break-all; + } + .see-file{ + width: 14rem; + .ml10{ + display: inline-block; + width: 4.5rem; + cursor: default; + } + span{ + width: 7%; + } + } + .anchorPoint{ + position: relative; + top: -5rem; + display: block; + height: 0; + } +} +.filesInfo{ + background: #FAFCFF; + border-color:rgba(42, 97, 255, 0.23); + .ant-progress-line { + width: 5rem; + } + .ant-progress-inner{ + background-color: #D14A4A; + } +} +.folders,.ant-anchor{ + margin-left: 0; + padding-left: 0; +} +.folders{ + position: absolute; + z-index: 2; + left: 0px; + top: 37px; + color: #333333; + width: 75rem; + box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5); + border-radius: 4px; + border: 1px solid rgba(153, 153, 153, 0.32); + .ant-anchor-link-active > .ant-anchor-link-title { + color: #466AFF; + } + .ant-anchor-link { + padding: 0px; + } + .folderList{ + max-height: 275px; + overflow:auto; + .files{ + border: 0px; + } + .filesInfo { + padding: 10px 18px 10px 15px; + height: 55px; + background: #FFF; + border-bottom: 1px solid #EEEEEE; + &:hover{ + background: #F3F4F6; + } + .color-green,.color-red{ + width: 3%; + text-align: right; + } + } + } } \ No newline at end of file diff --git a/src/forge/Merge/MergeDetail.js b/src/forge/Merge/MergeDetail.js index a7e2f33e..11bd3858 100644 --- a/src/forge/Merge/MergeDetail.js +++ b/src/forge/Merge/MergeDetail.js @@ -228,7 +228,7 @@ class MergeDetail extends Component {
    { data && data.issue.user_permission ? - 编辑 + 编辑 : '' }
    @@ -248,8 +248,8 @@ class MergeDetail extends Component {
      -
    • 0 ? "active" : ""}>对话内容
    • -
    • 0 ? "active" : ""}>代码提交
    • +
    • 0 ? "active" : ""}>对话内容
    • +
    • 0 ? "active" : ""}>代码提交
    diff --git a/src/forge/Merge/MergeItem.js b/src/forge/Merge/MergeItem.js index 32f3f811..61477c14 100644 --- a/src/forge/Merge/MergeItem.js +++ b/src/forge/Merge/MergeItem.js @@ -49,7 +49,7 @@ class MergeItem extends Component { }; render() { - const { issues, project_name, project_author_name , user_admin_or_member} = this.props; + const { issues, project_name, project_author_name , user_admin_or_developer} = this.props; const { projectsId , owner } = this.props.match.params; const { current_user } = this.props; const renderList = () => { @@ -62,9 +62,9 @@ class MergeItem extends Component {

    {item.name} @@ -78,7 +78,7 @@ class MergeItem extends Component {

    {item && item.author_name} @@ -109,8 +109,8 @@ class MergeItem extends Component { item.pull_request_head && {item.is_original ? item.fork_project_user @@ -133,8 +133,8 @@ class MergeItem extends Component { item.pull_request_base && {/* {item.is_fork ? item.pull_request_base : `${item.author_name}:${item.pull_request_base}`} */} {project_author_name}:{item.pull_request_base} @@ -156,7 +156,7 @@ class MergeItem extends Component {

  • {item.assign_user_name ? ( {item.assign_user_name} @@ -175,7 +175,7 @@ class MergeItem extends Component { {item.journals_count ? ( {item.journals_count} @@ -183,7 +183,7 @@ class MergeItem extends Component { ) : ( "" )} - {user_admin_or_member && item.pull_request_status === 0 ? ( + {user_admin_or_developer && item.pull_request_status === 0 ? (
    diff --git a/src/forge/Merge/MergeLinkFooter.jsx b/src/forge/Merge/MergeLinkFooter.jsx new file mode 100644 index 00000000..2c9aa481 --- /dev/null +++ b/src/forge/Merge/MergeLinkFooter.jsx @@ -0,0 +1,210 @@ +import React, { Component } from 'react'; +import { Tabs, Spin } from 'antd'; +import { Link } from 'react-router-dom'; +import axios from 'axios'; + +import Commits from './Commits'; +import Comments from '../comments/comments'; +import Files from './Files'; + +import '../Order/order.css'; +import './merge.css'; + +const { TabPane } = Tabs; + +class MergeFooter extends Component { + constructor(props) { + super(props); + this.state = { + commitsData: [], + filesData: undefined, + isSpin: false, + activeKey: '1', + commitCount: 0, + filesCount: 0, + // 总评论数量,包含回复 + commentsTotalCount: 0, + }; + } + componentDidMount() { + this.Init(); + // 为父组件绑定当前,以方便调用方法 + this.props.bindFootRef && this.props.bindFootRef(this); + } + + componentDidUpdate(prevProps) { + // 解决切换tab后浏览器回退不刷新的问题、点击tab后url变化但tab未切换的问题 + const newPathname = this.props.location.pathname; + const prevPathname = prevProps.location.pathname; + if (newPathname !== prevPathname) { + this.Init(true); + } + } + + Init = (isTabChange) => { + const { data, location, match } = this.props; + const { pathname } = location; + const { projectsId, owner, mergeId } = match.params; + + let activeKey = '1'; + if (pathname.indexOf('commits') > -1) { + activeKey = '2'; + this.getCommit(owner, projectsId, mergeId); + } else if (pathname.indexOf('files') > -1) { + activeKey = '3'; + this.getFile(owner, projectsId, mergeId); + } + if (isTabChange && activeKey === '1') { + this.refreshComment(); + } + this.setState({ + activeKey: activeKey, + commitCount: data && data.commits_count, + filesCount: data && data.files_count, + }); + }; + + bindCommentRef = (commentRef) => { + this.childComment = commentRef; + } + + refreshComment = () => { + this.childComment && this.childComment.getjournalslist(); + } + + getCommit = (owner, projectsId, mergeId) => { + this.setState({ isSpin: true }); + const url = `/${owner}/${projectsId}/pulls/${mergeId}/commits.json`; + axios + .get(url) + .then((result) => { + if (result) { + this.setState({ + commitsData: result.data.commits, + commitCount: result.data.commits_count, + }); + } + this.setState({ isSpin: false }); + }) + .catch((error) => { + this.setState({ isSpin: false }); + }); + }; + + getFile = (owner, projectsId, mergeId) => { + this.setState({ isSpin: true }); + const url = `/${owner}/${projectsId}/pulls/${mergeId}/files.json`; + axios + .get(url) + .then((result) => { + if (result) { + this.setState({ + filesData: result.data, + filesCount: result.data.files_count, + }); + } + this.setState({ isSpin: false }); + }) + .catch((error) => { + this.setState({ isSpin: false }); + }); + }; + + render() { + const { projectsId, owner, mergeId } = this.props.match.params; + + const { order_id, data = {} } = this.props; + const { + isSpin, + activeKey, + filesCount, + commitCount, + filesData, + commitsData = [], + } = this.state; + + // 评论数量优先取Comment组件中列表接口返回的,其次取合并请求详情接口中的,都没有取默认值0 + const commentsTotalCount = parseInt( + this.state.commentsTotalCount || data.comments_total_count || 0, + 10 + ); + + return ( +
    + + + + 评论 + {commentsTotalCount > 0 && ( + {commentsTotalCount} + )} + + } + key="1" + > + { + this.setState({ commentsTotalCount: commentsCount || 0 }); + }} + {...this.props} + bindCommentRef={this.bindCommentRef} + /> + + {commitCount > 0 && ( + + 提交 + {commitCount > 0 && ( + {commitCount} + )} + + } + key="2" + > + {commitsData.length > 0 && ( + + )} + + )} + {filesCount > 0 && ( + + 文件 + {filesCount > 0 && ( + {filesCount} + )} + + } + key="3" + > + + + )} + + +
    + ); + } +} +export default MergeFooter; diff --git a/src/forge/Merge/MergeSubmit.js b/src/forge/Merge/MergeSubmit.js index 8f2275d8..d4b42c3b 100644 --- a/src/forge/Merge/MergeSubmit.js +++ b/src/forge/Merge/MergeSubmit.js @@ -100,7 +100,7 @@ class MergeSubmit extends Component{ width:"10%", render: (text,item) => ( - + @@ -110,7 +110,7 @@ class MergeSubmit extends Component{ title:"SHA", dataIndex: 'sha', render: (text) => ( - {text} + {text} ) },{ title:"备注", diff --git a/src/forge/Merge/MessageCount.js b/src/forge/Merge/MessageCount.js index f3e58657..6d01e8a3 100644 --- a/src/forge/Merge/MessageCount.js +++ b/src/forge/Merge/MessageCount.js @@ -1,7 +1,6 @@ import React, { Component } from "react"; import { Tabs } from 'antd'; import { Link } from "react-router-dom"; -import { AlignCenter } from '../Component/layout'; import axios from "axios"; import { getImageUrl } from "educoder"; import { @@ -11,7 +10,6 @@ import { Dropdown, Icon, Menu, - Select, Tag, Button, Alert, @@ -19,9 +17,8 @@ import { import "./merge.css"; import RenderHtml from "../../components/render-html"; import "../Order/order.css"; -import MergeFooter from "./merge_footer"; +import MergeLinkFooter from "./MergeLinkFooter"; -const Option = Select.Option; const TextArea = Input.TextArea; function turnbar(str){ @@ -61,6 +58,11 @@ class MessageCount extends Component { // this.clickBody(); }; + + bindFootRef = (footRef) => { + this.footRef = footRef; + } + clickBody=()=>{ document.body.addEventListener('click', e => { let name = e.target.className; @@ -150,6 +152,8 @@ class MessageCount extends Component { }); const { getDetail } = this.props; getDetail && getDetail(); + // 调用子组件的方法刷新评论列表 + this.footRef && this.footRef.refreshComment(); } else { this.setState({ SpinMerge: false }); } @@ -283,13 +287,13 @@ class MessageCount extends Component { conflict_files && conflict_files.length>0 &&

    如下文件有代码冲突:

    -

    +

    { conflict_files.map((i,k)=>{ - return

    {i}

    + return

    {i}

    }) } -

    +
    }
    @@ -336,11 +340,11 @@ class MessageCount extends Component {
    -
    -
    +
    +
    - + {data.issue.subject} @@ -361,10 +365,10 @@ class MessageCount extends Component {
    - {data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}: {turnbar(data.pull_request && data.pull_request.head)} + {data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}: {data.pull_request && data.pull_request.head} @@ -376,8 +380,8 @@ class MessageCount extends Component { {data.issue.project_author_name}:{data.pull_request.base} @@ -386,14 +390,14 @@ class MessageCount extends Component { }
    - + - + {data.issue.author_name} @@ -408,7 +412,7 @@ class MessageCount extends Component { 审查人员: {data.issue.assign_user_name ? ( {data.issue.assign_user_name} @@ -424,7 +428,7 @@ class MessageCount extends Component { - 标签: + 标记: {data.issue.issue_tags && data.issue.issue_tags.length > 0 @@ -441,14 +445,13 @@ class MessageCount extends Component {
    -
    -
    +
    {operate && ( @@ -465,7 +468,6 @@ class MessageCount extends Component { )}
    -
    { data.issue.description ? @@ -543,7 +545,7 @@ class MessageCount extends Component { onChange={this.changbodypr} />
    -

    @@ -558,19 +560,19 @@ class MessageCount extends Component { 取消 -

    +
    )}
    - + bindFootRef={this.bindFootRef} + >
    ) : ( "" diff --git a/src/forge/Merge/NewMerge.js b/src/forge/Merge/NewMerge.js index 97df7fb1..900dea82 100644 --- a/src/forge/Merge/NewMerge.js +++ b/src/forge/Merge/NewMerge.js @@ -6,6 +6,11 @@ import "./merge.css"; import MergeForm from "./merge_form"; import MergeFooter from "./merge_footer"; const Option = Select.Option; +/** + * 此文件已废弃,新文件为CreateMerge.js + * 2021.10.12 + */ + class NewMerge extends Component { constructor(props) { super(props); @@ -48,8 +53,10 @@ class NewMerge extends Component { this.compareProject(this.state.id,pull,"master"); } } + // 页面销毁取消监听 componentWillUnmount () { + console.log('----------destoyed---------'); window.removeEventListener('popstate', this.handleBack, false); }; @@ -60,8 +67,11 @@ class NewMerge extends Component { //获取新建分支数据 getmergelist = (projectsId) => { - this.setState({isSpin: true}) - const { owner } = this.props.match.params; + this.setState({isSpin: true}); + // const { owner } = this.props.match.params; + let owner =this.props.history.location.pathname.split('/')[1]; + console.log('owner:'+owner); + console.log(this.props); const url = `/${owner}/${projectsId}/pulls/new.json`; axios .get(url) @@ -105,6 +115,7 @@ class NewMerge extends Component { const { author , identifier } =oldProject; url += `/${mergeBranch}...${author && author.login}/${identifier}:${localBranch}.json`; } + this.setState({isSpin: true}); axios.get(url).then(result=>{ if(result){ if (result.data.status === 0) { @@ -123,7 +134,9 @@ class NewMerge extends Component { comparesData:result.data }) } - }).catch(error=>{}) + }).catch(error=>{ + this.setState({isSpin: false}); + }) } } @@ -186,7 +199,7 @@ class NewMerge extends Component { // this.ischeckmerge(); let { id ,merge , pull } = this.state; if(type==="pull"){ - this.props.history.push(`/projects/${owner}/${projectsId}/pulls/new/${pull}`) + this.props.history.push(`/${owner}/${projectsId}/compare/${pull}`) this.compareProject(id,value,merge); }else{ this.compareProject(id,pull,value); @@ -208,7 +221,7 @@ class NewMerge extends Component { merge_user_login: is_fork_id ? projects_names[0].project_user_login : undefined } }) - this.props.history.push(`/projects/${login}/${identifier}/pulls/new`); + this.props.history.push(`/${login}/${identifier}/compare`); this.newMergelist(login,identifier); }; @@ -264,7 +277,9 @@ class NewMerge extends Component { show_message, default_message, merge_head, - projects_names,id,comparesData + projects_names, + id, + comparesData } = this.state; const renderBrances = (list, type) => { @@ -298,6 +313,7 @@ class NewMerge extends Component { return
    ; }; let { project } = this.props; + return (
    diff --git a/src/forge/Merge/UpdateMerge.js b/src/forge/Merge/UpdateMerge.js index 8ed8034a..8918db6e 100644 --- a/src/forge/Merge/UpdateMerge.js +++ b/src/forge/Merge/UpdateMerge.js @@ -64,12 +64,12 @@ class UpdateMerge extends Component {
    源分支:
    - {" "} {" "} @@ -83,12 +83,12 @@ class UpdateMerge extends Component {
    目标分支 :
    {" "} - {" "} {" "} diff --git a/src/forge/Merge/merge.css b/src/forge/Merge/merge.css index 6b50eeb1..d61543b4 100644 --- a/src/forge/Merge/merge.css +++ b/src/forge/Merge/merge.css @@ -40,6 +40,7 @@ form .ant-cascader-picker, form .ant-select { } .merge-header-button{ background:rgba(241,248,255,1); + text-align: left; } .width70{ width:70%; @@ -152,13 +153,23 @@ form .ant-cascader-picker, form .ant-select { margin-top: 15px; border-radius: 2px; } +.see-file-btn{ + color: #466AFF; + cursor: pointer; +} .filesInfo{ padding:10px 15px; background-color: #fafafa; } +.filesInfo .cursor-pointer{ + cursor: pointer; +} .filesContent{ border-top: 1px solid #ddd; } +.icon-fuzhiicon:hover{ + color: #466AFF; +} .linesContent{ display: flex; min-height: 30px; @@ -198,4 +209,17 @@ form .ant-cascader-picker, form .ant-select { } .linesContent.add{ background: rgba(48, 232, 132, 0.15); -} \ No newline at end of file +} + +.mergeRequest .folders{ + /* width: 72rem; */ + width: 100%; + } + + .matchwidth .ant-select-selection__rendered{ + width: 200px; + } + .overlihide li{ + max-width: 450px; + + } \ No newline at end of file diff --git a/src/forge/Merge/merge.js b/src/forge/Merge/merge.js index 90e35dcc..8a0eaede 100644 --- a/src/forge/Merge/merge.js +++ b/src/forge/Merge/merge.js @@ -4,10 +4,11 @@ import "./merge.css"; import "../Order/order.css"; import "../Order/index.scss"; import NoneData from "./no_data"; -import OrderItem from "./MergeItem"; +import MergeItem from "./MergeItem"; import './Index.scss'; import axios from "axios"; +import CheckProfile from '../Component/ProfileModal/Profile'; const Search = Input.Search; /** @@ -42,7 +43,7 @@ class merge extends Component { //设置选择高亮 openselect: 1, closeselect: undefined, - issue_tag_ids: "标签", + issue_tag_ids: "标记", fixed_version_ids: "里程碑", assigned_to_ids: "审查人员", paix: "排序", @@ -197,7 +198,7 @@ class merge extends Component { }); this.setState({ status_type: type, - issue_tag_ids: "标签", + issue_tag_ids: "标记", fixed_version_ids: "里程碑", assigned_to_ids: "审查人员", paix: "排序", @@ -212,7 +213,7 @@ class merge extends Component { checkOperation() { const { projectsId,owner } = this.props.match.params; - this.props.history.push(`/projects/${owner}/${projectsId}/pulls/new`); + this.props.history.push(`/${owner}/${projectsId}/compare/master...master`); } render() { const { projectsId , owner } = this.props.match.params; @@ -255,10 +256,10 @@ class merge extends Component { />
    { - data && data.user_admin_or_member && - this.checkOperation()}> + data && data.user_admin_or_developer && + this.checkOperation()}> + 新建合并请求 - + }
    @@ -320,7 +321,7 @@ class merge extends Component { className="topWrapperSelect" overlay={this.renderMenu( issue_chosen && issue_chosen.issue_tag, - "标签", + "标记", "issue_tag_id" )} trigger={["click"]} @@ -387,7 +388,7 @@ class merge extends Component { {data && data.search_count && data.search_count > 0 ? (
    - + user_admin_or_developer={data && data.user_admin_or_developer} + >
    ):""} {search_count > select_params.limit ? ( diff --git a/src/forge/Merge/merge_footer.js b/src/forge/Merge/merge_footer.js index 6502827c..868e736f 100644 --- a/src/forge/Merge/merge_footer.js +++ b/src/forge/Merge/merge_footer.js @@ -1,169 +1,84 @@ -import React, { Component } from "react"; -import { Tabs, Spin } from "antd"; -import "../Order/order.css"; -import "./merge.css"; -import Commits from "./Commits"; -import Comments from "../comments/comments"; -import Files from "./Files"; -import axios from 'axios'; +import React, { Component } from 'react'; +import { Tabs } from 'antd'; +import Commits from './Commits'; +import Files from './Files'; + +import '../Order/order.css'; +import './merge.css'; + const { TabPane } = Tabs; class MergeFooter extends Component { - constructor(props){ + constructor(props) { super(props); - this.state={ - pageData:undefined, - commitsData:undefined, - filesData:undefined, - isSpin:false, - activeKey:"1", - commitCount:0, - filesCount:0 - } - } - componentDidMount=()=>{ - const { footer_type ,data } = this.props; - if(footer_type){ - const { projectsId , owner , mergeId } = this.props.match.params; - this.getCommit(owner,projectsId,mergeId); - this.getFile(owner,projectsId,mergeId); - } - this.setState({ - activeKey:footer_type ? "1" : "2", - commitCount:data && data.commits_count, - filesCount:data && data.files_count - }) - } - componentDidUpdate=(prevProps)=>{ - const { comparesData } = this.props; - const { footer_type } = this.props; - if(footer_type){ - const { data } = this.props; - if(data !== prevProps.data){ - this.setState({ - commitCount:data && data.commits_count, - filesCount:data && data.files_count - }) - } - } - if(comparesData !== prevProps.comparesData){ - this.setState({ - activeKey:footer_type ? "1" : "2" - }) - this.changeTab(footer_type ? "1" : "2"); - } + this.state = { + activeKey: '1', + }; } - changeTab=(index)=>{ + changeTab = (index) => { this.setState({ - isSpin:true - }) - this.setState({ - activeKey:index - }) - const { footer_type , comparesData } = this.props; - const { projectsId , owner , mergeId } = this.props.match.params; - - if(footer_type){ - if(index === "2"){ - this.getCommit(owner,projectsId,mergeId); - }else if(index === "3"){ - this.getFile(owner,projectsId,mergeId); - }else{ - this.setState({ - isSpin:false - }) - } - }else{ - this.setState({ - commitsData:comparesData.commits, - filesData:comparesData.diff, - commitCount:comparesData.commits_count, - filesCount:comparesData.diff && comparesData.diff.files_count, - isSpin:false - }) - } - } - - getCommit =(owner,projectsId,mergeId)=>{ - const url = `/${owner}/${projectsId}/pulls/${mergeId}/commits.json`; - axios.get(url).then(result=>{ - if(result){ - this.setState({ - commitsData:result.data.commits, - isSpin:false, - commitCount:result.data.commits_count - }) - } - }).catch(error=>{}) - } - - getFile =(owner,projectsId,mergeId)=>{ - const url = `/${owner}/${projectsId}/pulls/${mergeId}/files.json`; - axios.get(url).then(result=>{ - if(result){ - this.setState({ - filesData:result.data, - isSpin:false, - filesCount:result.data.files_count, - }) - } - }).catch(error=>{}) - } + activeKey: index, + }); + }; render() { - const { projectsId , owner } = this.props.match.params; + const { projectsId, owner } = this.props.match.params; + const { comparesData = {} } = this.props; + const { commits, diff, commits_count } = comparesData; + const { activeKey } = this.state; - const { footer_type, order_id, data , comparesData } = this.props; - let { isSpin , activeKey , filesCount, commitCount , filesData , commitsData } = this.state; - - return ( - !footer_type && !comparesData || (comparesData && ((comparesData.commits && comparesData.commits.length===0)||(comparesData && !comparesData.diff)) )?"": -
    - - - { - footer_type && - 评论 - {data && parseInt(data.comments_count) > 0 && {data.comments_count}} - - } key="1"> - - - } - { - commitsData && commitsData.length > 0 && - 提交 - {commitCount > 0 && {commitCount}} - } key="2"> - - - } - { - filesData && filesData.files && filesData.files.length>0 && - 文件 - {filesCount > 0 && {filesCount}} - - } key="3"> - - - } - - - + return (commits && commits.length === 0) || !diff ? ( + '' + ) : ( +
    + + {commits && commits.length > 0 && ( + + 提交 + {commits_count > 0 && ( + {commits_count} + )} + + } + key="1" + > + + + )} + {diff && diff.files && diff.files.length > 0 && ( + + 文件 + {diff.files_count > 0 && ( + {diff.files_count} + )} + + } + key="3" + > + + + )} +
    ); } diff --git a/src/forge/Merge/merge_form.js b/src/forge/Merge/merge_form.js index 3481cc8f..e6378139 100644 --- a/src/forge/Merge/merge_form.js +++ b/src/forge/Merge/merge_form.js @@ -165,7 +165,8 @@ class MergeForm extends Component { this.setState({ isSpin: false, }); - this.props.history.push(`/projects/${owner}/${projectsId}/pulls`); + const { pull_request_id } = result.data; + this.props.history.push(`/${owner}/${projectsId}/pulls/${pull_request_id}`); const { getDetail } = this.props; getDetail && getDetail(); } else { @@ -195,7 +196,7 @@ class MergeForm extends Component { isSpin: false, }); this.props.history.push( - `/projects/${owner}/${projectsId}/pulls/${mergeId}/Messagecount` + `/${owner}/${projectsId}/pulls/${mergeId}` ); } else { this.setState({ @@ -264,7 +265,7 @@ class MergeForm extends Component { }, ], initialValue: title, - })()} + })()} { - this.props.history.push(merge_type === "new" ? `/projects/${owner}/${projectsId}/pulls` : `/projects/${owner}/${projectsId}/pulls/${mergeId}/detail`) + this.props.history.push(merge_type === "new" ? `/${owner}/${projectsId}/pulls` : `/${owner}/${projectsId}/pulls/${mergeId}`) }} > 取消 @@ -300,7 +301,8 @@ class MergeForm extends Component { {getFieldDecorator("assigned_to_id", { initialValue: assigned_to_id, })( - + {this.renderSelect(members)} )} @@ -311,12 +313,11 @@ class MergeForm extends Component { })( )} @@ -327,12 +328,11 @@ class MergeForm extends Component { })( )} diff --git a/src/forge/Merge/no_data.js b/src/forge/Merge/no_data.js index 8ad550ab..d5e4ca89 100644 --- a/src/forge/Merge/no_data.js +++ b/src/forge/Merge/no_data.js @@ -12,7 +12,7 @@ class Nodata extends Component{

    欢迎使用合并请求!

    - 合并请求可以帮助您与他人协作编写代码。在使用之前,请先创建一个 合并请求 + 合并请求可以帮助您与他人协作编写代码。在使用之前,请先创建一个 合并请求
    diff --git a/src/forge/New/Index.js b/src/forge/New/Index.js index b0f07326..e9aa1f95 100644 --- a/src/forge/New/Index.js +++ b/src/forge/New/Index.js @@ -1,10 +1,11 @@ import React, { Component } from 'react'; import { Link } from 'react-router-dom'; -import { Input , Form , Select , Checkbox , Button , Spin , AutoComplete } from 'antd'; +import { Input , Form , Select , Checkbox , Button , Spin , AutoComplete, Modal } from 'antd'; import { Base64 } from 'js-base64'; +import { AlignCenter } from '../Component/layout'; import '../css/index.scss'; -import './new.css' +import './new.scss' import axios from 'axios'; const Option = Select.Option; @@ -44,7 +45,12 @@ class Index extends Component { project_category_name: undefined, license_name: undefined, ignore_name: undefined, - descNum:0 + descNum:0, + + categoreFlag:false, + languageFlag:false, + ignoreFlag:false, + licenseFlag:false, } } componentDidMount = () => { @@ -58,6 +64,8 @@ class Index extends Component { this.getGitignore(); // 获取开源许可证 this.getLicenses(); + //判断是否为删除新建项目失败后返回,并执行对应逻辑 + this.isDeleteProjectBack(); } componentDidUpdate=(prevPros)=>{ if(prevPros && this.props && !this.props.checkIfLogin()){ @@ -69,6 +77,7 @@ class Index extends Component { getOwner=()=>{ const { OIdentifier } = this.props.match.params; const { user_id } = this.props && this.props.current_user; + const url = `/owners.json`; axios.get(url).then(result=>{ if(result && result.data){ @@ -77,16 +86,13 @@ class Index extends Component { OwnerList: owner, }) if(OIdentifier){ - owner = owner.filter(item=>item.name === OIdentifier); - this.props.form.setFieldsValue({ - user_id:OIdentifier - }) + owner = owner.filter(item=>item.login === OIdentifier); }else if(user_id){ owner = owner.filter(item=>item.id === user_id); - this.props.form.setFieldsValue({ - user_id:owner && owner[0].name - }) } + this.props.form.setFieldsValue({ + user_id:owner && owner[0].name + }) owner && this.setState({ owners_id:owner[0].id, owners_name:owner[0].name @@ -144,6 +150,31 @@ class Index extends Component { }).catch((error) => { }) } + isDeleteProjectBack = () => { + let mirror_status = this.props.history.location.mirror_status; + if (mirror_status === 2 && sessionStorage.newProjectValue) { + Modal.warning({ + title: '警告', + content: '项目导入失败!请按操作规范重新导入项目!', + }); + let newProjectValue = JSON.parse(sessionStorage.newProjectValue); + if (newProjectValue) { + this.setState({ + project_language_id: newProjectValue.project_language_id, + project_category_id: newProjectValue.project_category_id, + license_id: newProjectValue.license_id, + ignore_id: newProjectValue.ignore_id + }); + delete newProjectValue.project_language_id; + delete newProjectValue.project_category_id; + delete newProjectValue.license_id; + delete newProjectValue.ignore_id; + this.props.form.setFieldsValue(newProjectValue); + } + + } + } + // 设置option setOptionsList = (data, _head, name) => { if (data && data.length > 0) { @@ -164,35 +195,40 @@ class Index extends Component { subMitFrom = () => { this.props.form.validateFieldsAndScroll((err, values) => { + console.log(values); if (!err) { this.setState({ isSpin: true }) const { projectsType } = this.props.match.params; - const { project_language_id, project_category_id, license_id, ignore_id , owners_id , owners_name } = this.state; + const { + project_language_id, project_category_id, license_id, ignore_id , owners_id , + ignoreFlag,licenseFlag,categoreFlag,languageFlag + } = this.state; const decoderPass = Base64.encode(values.password); const url = (projectsType && projectsType === "mirror") ? "/projects/migrate.json" : "/projects.json"; + // 新建项目的时候,暂存数据,如果失败,返回的时候可以重新赋值 + sessionStorage.newProjectValue=JSON.stringify({...values,project_language_id,project_category_id,license_id,ignore_id}); axios.post(url, { ...values, auth_password:decoderPass, - project_language_id, - project_category_id, - license_id, - ignore_id, + project_language_id:languageFlag ? project_language_id : undefined, + project_category_id:categoreFlag ? project_category_id : undefined, + license_id:licenseFlag ? license_id : undefined, + ignore_id:ignoreFlag ? ignore_id : undefined, user_id:owners_id }).then((result) => { if (result && result.data.id) { - this.setState({ - isSpin: false - }) - this.props.showNotification(`${projectsType && projectsType === "mirror" ? "镜像" : "托管"}项目创建成功!`); - this.props.history.push(`/projects/${result.data.login}/${result.data.identifier}`); + projectsType && projectsType !== "mirror" && this.props.showNotification(`项目创建成功!`); + this.props.history.push(`/${result.data.login}/${result.data.identifier}`); } + this.setState({ + isSpin: false + }) }).catch((error) => { this.setState({ isSpin: false }) - console.log(error); }) } else { this.setState({ @@ -249,12 +285,16 @@ class Index extends Component { if(value.indexOf("/") > -1){ let arr = value.split("/"); let first = arr[arr.length-1]; - if(first.indexOf(".git") > -1){ + if(first.indexOf(".") > -1){ let second = first.split('.')[0]; if(!second)return; this.props.form.setFieldsValue({ repository_name:second }) + }else{ + this.props.form.setFieldsValue({ + repository_name:first + }) } } } @@ -287,48 +327,35 @@ class Index extends Component { mirrorCheck, - descNum + descNum, + + ignoreFlag, + licenseFlag, + languageFlag, + categoreFlag } = this.state; return (
    -
    创建{projectsType && projectsType === "mirror" ? "镜像" : "托管"}项目
    +
    {projectsType && projectsType === "mirror" ? "导入" : "新建"}项目
    - - {getFieldDecorator('user_id', { - rules: [{ - required: true, message: '请选择拥有者' - },{ - validator:(rule, value, callback) => this.checkId(rule, value, callback, OwnerList, '拥有者') - }], - })( - this.ChangePlatform(value, e, 'owners', OwnerList)} - className="plateAutoComplete" - onBlur={(value) => this.blurCategory(value, OwnerList, "owners")} - > - {owners_list} - - )} - - { + + { projectsType && projectsType === "mirror" && {getFieldDecorator('clone_addr', { rules: [{ required: true, message: '请填写镜像版本库地址' }], })( - + )}

    示例:https://github.com/facebook/reack.git

    @@ -336,12 +363,16 @@ class Index extends Component { } { projectsType && projectsType === "mirror" && - -

    需要授权验证

    +
    +

    + 需要授权验证 + 如果导入项目为私有仓库,则必须填写相应平台正确的用户名和密码 +

    { mirrorCheck && -
    +
    用户名 + 密码 {getFieldDecorator('password', { rules: [], })( - + )}
    } - +
    } + + + {getFieldDecorator('user_id', { + rules: [{ + required: true, message: '请选择拥有者' + },{ + validator:(rule, value, callback) => this.checkId(rule, value, callback, OwnerList, '拥有者') + }], + })( + this.ChangePlatform(value, e, 'owners', OwnerList)} + className="plateAutoComplete" + onBlur={(value) => this.blurCategory(value, OwnerList, "owners")} + > + {owners_list} + + )} + + / + + {getFieldDecorator('name', { + rules: [{ + required: true, message: '请填写项目名称' + }], + })( + + )} + + 项目标识 (项目url标识部分)} + colon={false} > - {getFieldDecorator('name', { + {getFieldDecorator('repository_name', { rules: [{ - required: true, message: '请填写项目名称' + required: true, message: '请填写项目标识' }], })( - + )}
    {descNum}/200 {getFieldDecorator('description', { - rules: [{ - required: true, message: '请填写项目简介' - }], + rules: [], })( )}
    - - {getFieldDecorator('repository_name', { - rules: [{ - required: true, message: '请填写仓库名称' - }], - })( - - )} - - - {getFieldDecorator('project_category', { - rules: [{ - required: true, message: '请选择大类别', - }, { - validator: (rule, value, callback) => this.checkId(rule, value, callback, CategoryList, '项目类别') - }], - })( - this.ChangePlatform(value, e, 'project_category', CategoryList)} - className="plateAutoComplete" - onBlur={(value) => this.blurCategory(value, CategoryList, "project_category")} - > - {project_category_list} - - )} - - - {getFieldDecorator('project_language', { - rules: [{ - required: true, message: '请选择项目语言' - }, { - validator: (rule, value, callback) => this.checkId(rule, value, callback, LanguageList, '项目语言') - }], - })( - this.ChangePlatform(value, e, 'project_language', LanguageList)} - className="plateAutoComplete" - onBlur={(value) => this.blurCategory(value, LanguageList, "project_language")} - > - {project_language_list} - - )} - + { (projectsType === "deposit" || !projectsType) && - {getFieldDecorator('ignore', { - rules: [{ - required: true, message: '请选择gitignore' - }, { - validator: (rule, value, callback) => this.checkId(rule, value, callback, GitignoreList, 'gitignore') - }], - })( - this.ChangePlatform(value, e, 'ignore', GitignoreList)} - className="plateAutoComplete" - onBlur={(value) => this.blurCategory(value, GitignoreList, "ignore")} - > - {ignore_list} - + {getFieldDecorator('ignoreFlag')( + this.setState({ignoreFlag:e.target.checked})}>.gitignore )} + { ignoreFlag && + + {getFieldDecorator('ignore', { + rules: [{ + required: ignoreFlag, message: '请选择gitignore' + }, { + validator: (rule, value, callback) => this.checkId(rule, value, callback, GitignoreList, 'gitignore') + }], + })( + this.ChangePlatform(value, e, 'ignore', GitignoreList)} + className="plateAutoComplete" + onBlur={(value) => this.blurCategory(value, GitignoreList, "ignore")} + > + {ignore_list} + + )} + + } - {getFieldDecorator('license', { - rules: [{ - required: true, message: '请选择开源许可证' - }, { - validator: (rule, value, callback) => this.checkId(rule, value, callback, LicensesList, '开源许可证') - }], - })( - this.ChangePlatform(value, e, 'license', LicensesList)} - className="plateAutoComplete" - onBlur={(value) => this.blurCategory(value, LicensesList, "license")} - > - {license_list} - + {getFieldDecorator('licenseFlag')( + this.setState({licenseFlag:e.target.checked})}>开源许可证 )} + { licenseFlag && + + {getFieldDecorator('license', { + rules: [{ + required: licenseFlag, message: '请选择开源许可证' + }, { + validator: (rule, value, callback) => this.checkId(rule, value, callback, LicensesList, '开源许可证') + }], + })( + this.ChangePlatform(value, e, 'license', LicensesList)} + className="plateAutoComplete" + onBlur={(value) => this.blurCategory(value, LicensesList, "license")} + > + {license_list} + + )} + + } } {getFieldDecorator('private')( - 将项目设为私有(只有项目所有人或拥有权限的项目成员才能看到) + 将项目设为私有(只有项目所有人或拥有权限的项目成员才能看到) )} { projectsType && projectsType === "mirror" && {getFieldDecorator('is_mirror')( @@ -509,12 +540,69 @@ class Index extends Component { )} } -
    + + {getFieldDecorator('categoreFlag')( + this.setState({categoreFlag:e.target.checked})}>项目类别 + )} + + {categoreFlag && + + {getFieldDecorator('project_category', { + rules: [{ + required: categoreFlag, message: '请选择项目类别', + }, { + validator: (rule, value, callback) => this.checkId(rule, value, callback, CategoryList, '项目类别') + }], + })( + this.ChangePlatform(value, e, 'project_category', CategoryList)} + className="plateAutoComplete" + onBlur={(value) => this.blurCategory(value, CategoryList, "project_category")} + > + {project_category_list} + + )} + + } + + {getFieldDecorator('languageFlag')( + this.setState({languageFlag:e.target.checked})}>项目语言 + )} + + {languageFlag && + + {getFieldDecorator('project_language', { + rules: [{ + required: languageFlag, message: '请选择项目语言' + }, { + validator: (rule, value, callback) => this.checkId(rule, value, callback, LanguageList, '项目语言') + }], + })( + this.ChangePlatform(value, e, 'project_language', LanguageList)} + className="plateAutoComplete" + onBlur={(value) => this.blurCategory(value, LanguageList, "project_language")} + > + {project_language_list} + + )} + + } +
    注: 为必填项,否则为选填
    - - 取消 + + 取消
    diff --git a/src/forge/New/new.css b/src/forge/New/new.scss similarity index 72% rename from src/forge/New/new.css rename to src/forge/New/new.scss index fcb6fa8c..15aca70b 100644 --- a/src/forge/New/new.css +++ b/src/forge/New/new.scss @@ -12,7 +12,13 @@ border-bottom: 1px solid #f0f0f0 } .newPanel_content{ - padding:1rem 2rem; + padding:2rem; +} +.newPanel_content form .ant-row.ant-form-item{ + margin-bottom: 25px; +} +.newPanel_content .ant-form-item-label label{ + font-size: 16px; } .newPanel_content .ant-form-item-control-wrapper{ flex: 1; @@ -25,24 +31,35 @@ height: 35px; line-height: 35px; } - .newContent_inline{ display: flex; flex-wrap: wrap; justify-content: space-between; align-items:flex-end } +.explainPos{ + .ant-form-explain{ + position: absolute; + } +} .newContent_inline > .ant-form-item:nth-child(2){ margin-left: 20px; } -.newPanel_content .privatePart .ant-form-item-label{ - margin-left: 0px; +.privatePart{ + margin-bottom: 0px!important; + .ant-form-item-label{ + margin-left: 0px; + } } .newPanel_content .ant-form-item-label{ line-height: 25px; height: 25px; - margin-left: -0.8rem; +} +.plateAutoComplete{ + .ant-input{ + height: 34px!important; + } } @media screen and (max-width: 750px){ .newPanel_content{ diff --git a/src/forge/Newfile/Index.js b/src/forge/Newfile/Index.js index 9b776955..953f5072 100644 --- a/src/forge/Newfile/Index.js +++ b/src/forge/Newfile/Index.js @@ -65,16 +65,18 @@ class Index extends Component {
    - +
    + +
    diff --git a/src/forge/Newfile/UserSubmitComponent.js b/src/forge/Newfile/UserSubmitComponent.js index 5cba3cf6..aa4bba6e 100644 --- a/src/forge/Newfile/UserSubmitComponent.js +++ b/src/forge/Newfile/UserSubmitComponent.js @@ -83,10 +83,10 @@ class UserSubmitComponent extends Component { if (result.data && result.data.name) { this.props.showNotification("文件新建成功!"); if(submitType === "1"){ - const { getTopCount } = this.props; - getTopCount && getTopCount(values.branchname); + const { getDetail } = this.props; + getDetail && getDetail(); } - let url = `/projects/${owner}/${projectsId}${values.branchname ? `/tree/${turnbar(values.branchname)}`: (branch ? `/tree/${turnbar(branch)}` : "")}`; + let url = `/${owner}/${projectsId}${values.branchname ? `/tree/${turnbar(values.branchname)}`: (branch ? `/tree/${turnbar(branch)}` : "")}`; this.props.history.push(url); } }) @@ -123,7 +123,7 @@ class UserSubmitComponent extends Component { this.setState({ isSpin: false }); if (result.data && result.data.status === 1) { let b = currentBranch || branch; - let url = `/projects/${owner}/${projectsId}${(values.branchname ? `/tree/${turnbar(values.branchname)}` : (b ? `/tree/${turnbar(b)}`:""))}`; + let url = `/${owner}/${projectsId}${(values.branchname ? `/tree/${turnbar(values.branchname)}` : (b ? `/tree/${turnbar(b)}`:""))}`; this.props.history.push(url); this.props.showNotification("文件修改成功!"); } @@ -147,10 +147,11 @@ class UserSubmitComponent extends Component { const { current_user, filepath, projectDetail , currentBranch } = this.props; const { editor_type } = this.props; let b = currentBranch || branch; + return (
    - + { - this.props.history.push(`/projects/${owner}/${projectsId}`); + this.props.history.push(`/${owner}/${projectsId}`); }} className="mr20" > diff --git a/src/forge/Newfile/index.css b/src/forge/Newfile/index.css index 242fd451..746febe5 100644 --- a/src/forge/Newfile/index.css +++ b/src/forge/Newfile/index.css @@ -8,7 +8,13 @@ border: 1px solid #d9d9d9!important; border-right: none!important; } - +.editorBorder .editorBorderBox{ + border:1px solid #eee; + border-radius: 2px; +} +.editorBorder .editorBorderSubmitBox{ + padding:20px 0px!important; +} .userScrew{ margin:20px 0px; border:1px solid #f4f4f4; @@ -39,7 +45,7 @@ z-index: 1; } .ant-input-group .ant-input:focus{ - border-right: 1px solid #d9d9d9!important; + border-right: 1px solid rgba(70, 106, 255, 1)!important; } .ant-btn-primary.grey{ border:1px solid #BBBBBB; diff --git a/src/forge/Newfile/m_editor.js b/src/forge/Newfile/m_editor.js index 05a7b2ac..13d2ec46 100644 --- a/src/forge/Newfile/m_editor.js +++ b/src/forge/Newfile/m_editor.js @@ -1,5 +1,7 @@ import React, { Component } from "react"; import Editor from "react-monaco-editor"; +// import {UnControlled as CodeMirror} from 'react-codemirror2' + import UserSubmitComponent from "./UserSubmitComponent"; import "./index.css"; @@ -10,6 +12,7 @@ class m_editor extends Component { super(props); this.state = { editorValue: this.props.content, + prevHeight:0 }; } componentDidUpdate=(prevProps)=>{ @@ -41,42 +44,92 @@ class m_editor extends Component { folding: true, foldingStrategy: "indentation", // 代码可分小段折叠 automaticLayout: true, // 自适应布局 - // overviewRulerBorder: false, // 不要滚动条的边框 - // scrollBeyondLastLine: false, // 取消代码后面一大段空白 + overviewRulerBorder: false, // 不要滚动条的边框 + scrollBeyondLastLine: false, // 取消代码后面一大段空白 minimap: { // 不要小地图 enabled: false, }, }; + + const handleEditorMount = (editor, monaco) => { + editor.onDidChangeModelDecorations(() => { + requestAnimationFrame(updateEditorHeight); // folding + }); + + const updateEditorHeight = () => { + const editorElement = editor.getDomNode(); + + if (!editorElement) { + return; + } + + const padding = 40; + + const lineHeight = editor.getOption( + monaco.editor.EditorOption.lineHeight + ); + + const lineCount = editor.getModel().getLineCount() || 1; + let height = + editor.getTopForLineNumber(lineCount + 1) + + lineHeight + + padding ; + + if(height<400){height = 400;} + + if (this.state.prevHeight !== height) { + this.setState({ + prevHeight:height + }) + // setPrevHeight(height); + editorElement.style.height = `${height}px`; + editor.layout(); + } + }; + + updateEditorHeight(); // typing + }; + + return ( -
    -
    - -
    - {!readOnly && ( -
    - -
    - )} -
    +
    + + {/* */} +
    + {!readOnly && ( +
    + +
    + )}
    ); } diff --git a/src/forge/Nodata.js b/src/forge/Nodata.js index 3147e560..ccc74ac5 100644 --- a/src/forge/Nodata.js +++ b/src/forge/Nodata.js @@ -1,7 +1,7 @@ import React , { Component } from 'react'; import nodata from './Images/nodata.png'; - +import './css/index.scss'; class Nodata extends Component{ render(){ const { _html , small } = this.props; diff --git a/src/forge/Notice/Apply.jsx b/src/forge/Notice/Apply.jsx index 3c77edfa..aeacd67a 100644 --- a/src/forge/Notice/Apply.jsx +++ b/src/forge/Notice/Apply.jsx @@ -63,11 +63,11 @@ function Apply(props) { { list.map((i,k)=>{ return( -
  • - +
  • +

    - {i.user && i.user.name} + {i.user && i.user.name} {i.time_ago}

    diff --git a/src/forge/Notice/Index.jsx b/src/forge/Notice/Index.jsx index 63d09748..73a2561b 100644 --- a/src/forge/Notice/Index.jsx +++ b/src/forge/Notice/Index.jsx @@ -10,10 +10,6 @@ const Apply = Loadable({ loader: () => import("./Apply"), loading: Loading, }); -const Notify = Loadable({ - loader: () => import("./Notify"), - loading: Loading, -}); const UndoEvent = Loadable({ loader: () => import("./UndoEvent"), loading: Loading, @@ -23,7 +19,7 @@ function Index(props){ const pathname = props.history.location.pathname; const user = props.user; - const [ menu , setMenu ] = useState("notify"); + const [ menu , setMenu ] = useState("undo"); const [ messagesCount , setMessagesCount ] = useState(0); const [ transferCount , setTransferCount ] = useState(0); const [ applyCount , setApplyCount ] = useState(0); @@ -33,7 +29,7 @@ function Index(props){ useEffect(()=>{ if((username && current_user && (current_user.login !== username))){ - props.history.push(`/users/${username}`); + props.history.push(`/${username}`); } },[current_user,username]) @@ -47,14 +43,10 @@ function Index(props){ useEffect(()=>{ if(pathname && username){ - if(pathname === `/users/${username}/notice`){ - setMenu("notify"); - changeNum(user.undo_messages); - } - if(pathname === `/users/${username}/notice/undo`){ + if(pathname === `/${username}/notice`){ setMenu("undo"); } - if(pathname === `/users/${username}/notice/apply`){ + if(pathname === `/${username}/notice/apply`){ setMenu("apply"); } } @@ -70,9 +62,9 @@ function Index(props){ function deleteEvent(type,count) { let c = count; if(type==="apply"){ - setTransferCount(transferCount-count); - }else if(type==="undo"){ setApplyCount(applyCount-count); + }else if(type==="undo"){ + setTransferCount(transferCount-count); }else{ setMessagesCount(0); c = messagesCount; @@ -83,20 +75,14 @@ function Index(props){ return (
      -
    • - - 通知 - {messagesCount ? {messagesCount}:""} - -
    • - + 接收仓库 {transferCount ? {transferCount}:""}
    • - + 成员申请 {applyCount ? {applyCount}:""} @@ -104,23 +90,17 @@ function Index(props){
    { return ; }} > { return ; }} > - { - return ; - }} - >
    ); diff --git a/src/forge/Notice/Notify.jsx b/src/forge/Notice/Notify.jsx index 761366d3..31373908 100644 --- a/src/forge/Notice/Notify.jsx +++ b/src/forge/Notice/Notify.jsx @@ -44,13 +44,13 @@ function Notify(props){ if(status){ switch(status){ case 'canceled': - return

    取消转移【{project && project.name}】仓库

    + return

    取消转移【{project && project.name}】仓库

    case 'common': - return

    正在将【{project && project.name}】仓库转移给【{owner && owner.name}】

    + return

    正在将【{project && project.name}】仓库转移给【{owner && owner.name}】

    case 'successed': - return

    {project && project.name}】仓库成功转移给【{owner && owner.name}】

    + return

    {project && project.name}】仓库成功转移给【{owner && owner.name}】

    default: - return

    拒绝转移【{project && project.name}】仓库

    + return

    拒绝转移【{project && project.name}】仓库

    } }else{ return "" @@ -62,9 +62,9 @@ function Notify(props){ if(status){ switch(status){ case 'successed': - return

    已通过你加入【{project && project.name}】项目的申请

    + return

    已通过你加入【{project && project.name}】项目的申请

    default: - return

    已拒绝你加入【{project && project.name}】项目的申请

    + return

    已拒绝你加入【{project && project.name}】项目的申请

    } }else{ return "" @@ -80,12 +80,13 @@ function Notify(props){
      { list.map((i,k)=>{ + console.log(i); return( -
    • - +
    • +

      - {i.applied_user && i.applied_user.name} + {i.applied_user && i.applied_user.name} {i.time_ago}

      { i.applied_type === "AppliedProject" ? renderApplyStatus(i.status,i.applied):renderStatus(i.status,i.applied)} diff --git a/src/forge/Notice/UndoEvent.jsx b/src/forge/Notice/UndoEvent.jsx index d93a1f83..17dcc321 100644 --- a/src/forge/Notice/UndoEvent.jsx +++ b/src/forge/Notice/UndoEvent.jsx @@ -53,7 +53,7 @@ function UndoEvent(props){ Axios.post(url).then(result=>{ if(result && result.data){ getList(); - props && props.deleteEvent("apply",1); + props && props.deleteEvent("undo",1); } }).catch(error=>{}) } @@ -61,23 +61,23 @@ function UndoEvent(props){ return(
      -
      +
      { list && list.length > 0 ?
        { list.map((i,k)=>{ return( -
      • - +
      • +

        - {i.user && i.user.name} + {i.user && i.user.name} {i.time_ago}

        -

        请求将仓库【{i.project && i.project.name}】 - 转移给【{i.owner && i.owner.name}】,是否接受?

        +

        请求将仓库【{i.project && i.project.name}】 + 转移给【{i.owner && i.owner.name}】,是否接受?

        { i.status === "common" && diff --git a/src/forge/Order/CopyDetail.js b/src/forge/Order/CopyDetail.js index 1f61e736..906de4be 100644 --- a/src/forge/Order/CopyDetail.js +++ b/src/forge/Order/CopyDetail.js @@ -1,11 +1,13 @@ -import React, { Component } from "react"; +import React from "react"; import OrderItem from './order_form' -class CopyDetail extends Component { - render() { - return ( - - ) - } + + +function CopyDetail(props){ + const operate = props.match.params.operate; + console.log(operate); + return( + + ) } -export default CopyDetail; +export default CopyDetail; \ No newline at end of file diff --git a/src/forge/Order/Detail.js b/src/forge/Order/Detail.js index 644a653d..4d1b47cf 100644 --- a/src/forge/Order/Detail.js +++ b/src/forge/Order/Detail.js @@ -85,7 +85,7 @@ class Detail extends Component { }) .then((result) => { if (result) { - this.props.history.push(`/projects/${owner}/${projectsId}/issues`); + this.props.history.push(`/${owner}/${projectsId}/issues`); } }) .catch((error) => { @@ -123,22 +123,25 @@ class Detail extends Component { //复制 copydetail = () => { const { projectsId, orderId, owner } = this.props.match.params; - const url = `/${owner}/${projectsId}/issues/${orderId}/copy.json`; - axios - .post(url, { - project_id: projectsId, - id: orderId, - }) - .then((result) => { - if (result) { - this.props.history.push( - `/projects/${owner}/${projectsId}/issues/${result.data.issue_id}/copyetail` - ); - } - }) - .catch((error) => { - console.log(error); - }); + // const url = `/${owner}/${projectsId}/issues/${orderId}/copy.json`; + // axios + // .post(url, { + // project_id: projectsId, + // id: orderId, + // }) + // .then((result) => { + // if (result) { + // this.props.history.push( + // `/${owner}/${projectsId}/issues/${result.data.issue_id}/copyetail` + // ); + // } + // }) + // .catch((error) => { + // console.log(error); + // }); + this.props.history.push( + `/${owner}/${projectsId}/issues/${orderId}/copyetail` + ); }; // 翻页 @@ -207,7 +210,7 @@ class Detail extends Component {
        - {data && data.subject} + {data && data.subject} {data && data.priority && ( @@ -240,7 +243,7 @@ class Detail extends Component {
        {data && data.author_name} @@ -269,7 +272,7 @@ class Detail extends Component { 编辑 @@ -315,7 +318,7 @@ class Detail extends Component {

        - 标签: + 标记: {data && data.issue_tags ? ( diff --git a/src/forge/Order/Milepost.js b/src/forge/Order/Milepost.js index c18baf1b..48fc286b 100644 --- a/src/forge/Order/Milepost.js +++ b/src/forge/Order/Milepost.js @@ -4,6 +4,7 @@ import { Dropdown, Icon, Menu, Pagination, Typography, Popconfirm, Spin } from ' import NoneData from '../Nodata'; import axios from 'axios'; import './order.css'; +import CheckProfile from '../Component/ProfileModal/Profile'; const { Text } = Typography; @@ -188,7 +189,7 @@ class Milepost extends Component {

      { data && data.user_admin_or_member ? - 新的里程碑 + {this.props.history.push(`/${owner}/${projectsId}/milestones/new`)}}>新的里程碑 : '' }
      @@ -205,7 +206,7 @@ class Milepost extends Component {
      - {item.name} + {item.name}
      @@ -229,7 +230,7 @@ class Milepost extends Component {
      - 编辑 + 编辑
      diff --git a/src/forge/Order/MilepostDetail.js b/src/forge/Order/MilepostDetail.js index 30526750..0f5d191e 100644 --- a/src/forge/Order/MilepostDetail.js +++ b/src/forge/Order/MilepostDetail.js @@ -2,7 +2,8 @@ import React, { Component } from "react"; import { Link } from 'react-router-dom'; import { Dropdown, Menu, Icon, Pagination, Spin } from 'antd'; import './order.css'; -import { FlexAJ } from '../Component/layout' +import { FlexAJ } from '../Component/layout'; +import CheckProfile from '../Component/ProfileModal/Profile'; import NoneData from '../Nodata'; import OrderItem from './OrderItem'; @@ -39,7 +40,7 @@ class MilepostDetail extends Component { issue_type: undefined, status_type: '1', //设置选择高亮 - issue_tag_ids: '标签', + issue_tag_ids: '标记', tracker_ids: '类型', author_ids: '发布人', assigned_to_ids: '负责人', @@ -113,7 +114,7 @@ class MilepostDetail extends Component { this.setState({ data: result.data, issues: result.data.issues, - search_count: result.data.search_count, + search_count: params.status_type ==="1" ? result.data.open_issues_count : result.data.close_issues_count, isSpin: false }) } @@ -193,7 +194,7 @@ class MilepostDetail extends Component { done_ratio : undefined, status_id: undefined, assigned_to_id: undefined, - issue_tag_ids: '标签', + issue_tag_ids: '标记', tracker_ids: '类型', author_ids: '发布人', assigned_to_ids: '负责人', @@ -238,8 +239,8 @@ class MilepostDetail extends Component { {data && data.percent && data.percent.toFixed(2)}%完成
      - 编辑里程碑 - 创建易修 + 编辑里程碑 + {this.props.history.push(`/${owner}/${projectsId}/issues/${meilid}/new`)}} className="topWrapper_btn">创建易修
      @@ -253,7 +254,7 @@ class MilepostDetail extends Component {
    • - + {this.state.issue_tag_ids}
    • diff --git a/src/forge/Order/Milepostitem.js b/src/forge/Order/Milepostitem.js index 48bf65c1..d79c66fe 100644 --- a/src/forge/Order/Milepostitem.js +++ b/src/forge/Order/Milepostitem.js @@ -31,7 +31,7 @@ class OrderItem extends Component {
      - {item.name} + {item.name}
    @@ -65,7 +65,7 @@ class OrderItem extends Component {
    - 编辑 + 编辑
    diff --git a/src/forge/Order/Nav.js b/src/forge/Order/Nav.js index 93fbc101..3f5a20c5 100644 --- a/src/forge/Order/Nav.js +++ b/src/forge/Order/Nav.js @@ -7,8 +7,8 @@ class Nav extends Component{ const { projectsId , owner } = this.props.match.params; return(

    - 标签 - 里程碑 + 标记 + 里程碑

    ) } diff --git a/src/forge/Order/OrderItem.js b/src/forge/Order/OrderItem.js index 3c5e5cf8..08178864 100644 --- a/src/forge/Order/OrderItem.js +++ b/src/forge/Order/OrderItem.js @@ -44,6 +44,7 @@ class OrderItem extends Component { render() { const { item , checkbox , mile , user_admin_or_member } = this.props; const { projectsId , owner } = this.props.match.params; + const { orderid , isdisplay } = this.state; const { current_user } = this.props; return ( item && @@ -51,7 +52,7 @@ class OrderItem extends Component { {current_user && current_user.login && checkbox}

    - {item.name} + {item.name} {TagInfo(item.priority,"mr10")}

    @@ -67,7 +68,7 @@ class OrderItem extends Component {

  • { item.author_name ? - + {item.author_name} : "--" @@ -76,7 +77,7 @@ class OrderItem extends Component {
  • { item.assign_user_name ? - + {item.assign_user_name} : "--" @@ -88,15 +89,24 @@ class OrderItem extends Component {
  • {item.done_ratio || "--"}
  • - {item.journals_count} + {item.journals_count} { user_admin_or_member ? -
    +
    - + + +
    - document.getElementById("hoverBox")} title={'您确定要删除当前易修吗?'} okText="是" cancelText="否" onConfirm={() => this.deletedetail(item.id)}> + this.deletedetail(item.id)} + >
    diff --git a/src/forge/Order/Tags.js b/src/forge/Order/Tags.js index 174891aa..eeff8db2 100644 --- a/src/forge/Order/Tags.js +++ b/src/forge/Order/Tags.js @@ -324,11 +324,11 @@ class Tags extends Component { data && data.issue_tags && data.issue_tags.length > 0 ?
    - 共{data && data.issue_tags_count}个标签 + 共{data && data.issue_tags_count}个标记
    • - 标签 + 标记
    diff --git a/src/forge/Order/UpdateDetail.js b/src/forge/Order/UpdateDetail.js index 9cbb3cd6..0bf4f0f1 100644 --- a/src/forge/Order/UpdateDetail.js +++ b/src/forge/Order/UpdateDetail.js @@ -1,11 +1,11 @@ -import React, { Component } from "react"; +import React from "react"; import OrderForm from './order_form' -class UpdateDetail extends Component { - render() { - return ( - - ) - } + +function CopyDetail(props){ + const operateName = props.match.params.operateName; + return( + + ) } -export default UpdateDetail; +export default CopyDetail; diff --git a/src/forge/Order/UpdateMilepost.js b/src/forge/Order/UpdateMilepost.js index 88a73033..c4f38657 100644 --- a/src/forge/Order/UpdateMilepost.js +++ b/src/forge/Order/UpdateMilepost.js @@ -79,7 +79,7 @@ class UpdateMilepost extends Component { }).then(result => { if (result) { this.setState({ isSpin: false }) - this.props.history.push(`/projects/${owner}/${projectsId}/milestones`); + this.props.history.push(`/${owner}/${projectsId}/milestones`); } diff --git a/src/forge/Order/newMilepost.js b/src/forge/Order/newMilepost.js index b9513212..b7d1102d 100644 --- a/src/forge/Order/newMilepost.js +++ b/src/forge/Order/newMilepost.js @@ -63,7 +63,7 @@ class NewMilepost extends Component { }).then(result => { if (result) { this.setState({ isSpin: false }) - this.props.history.push(`/projects/${owner}/${projectsId}/milestones`); + this.props.history.push(`/${owner}/${projectsId}/milestones`); const { getDetail } = this.props; getDetail && getDetail(); } diff --git a/src/forge/Order/order.css b/src/forge/Order/order.css index 6a0f029e..0abd116f 100644 --- a/src/forge/Order/order.css +++ b/src/forge/Order/order.css @@ -20,6 +20,9 @@ .overlayBox{ width: 230px; } +.hideOverlay{ + display: none; +} .topmilepost { box-sizing: border-box; display: flex; diff --git a/src/forge/Order/order.js b/src/forge/Order/order.js index 1202f41f..7275c759 100644 --- a/src/forge/Order/order.js +++ b/src/forge/Order/order.js @@ -1,12 +1,12 @@ import React, { Component } from "react"; import { Input, Dropdown, Menu, Icon, Pagination, Spin, DatePicker, Checkbox } from "antd"; -import { Link } from 'react-router-dom'; import "./order.css"; import './index.scss'; import moment from 'moment'; import NoneData from "../Nodata"; import OrderItem from "./OrderItem"; +import CheckProfile from '../Component/ProfileModal/Profile'; import axios from "axios"; @@ -39,7 +39,7 @@ class order extends Component { search_count: undefined, issue_type: undefined, status_type: "1", // 默认显示开启中的 - issue_tag_ids: "标签", + issue_tag_ids: "标记", tracker_ids: "类型", author_ids: "发布人", assigned_to_ids: "负责人", @@ -58,7 +58,7 @@ class order extends Component { select_params: { assigned_to_id: undefined, // 负责人 author_id: undefined, // 发布人 - issue_tag_id: undefined, // 标签 + issue_tag_id: undefined, // 标记 tracker_id: undefined, //类型 done_ratio: undefined, // 完成度 status_id: undefined, // 优先级 @@ -257,7 +257,7 @@ class order extends Component { author_id: undefined, assigned_to_id: undefined, status_type: type, - issue_tag_ids: "标签", + issue_tag_ids: "标记", tracker_ids: "类型", author_ids: "发布人", assigned_to_ids: "负责人", @@ -351,9 +351,9 @@ class order extends Component { if(data && data.user_admin_or_member){ const { projectsId , owner } = this.props.match.params; return( - + {window.open(`/${owner}/${projectsId}/issues/new`,'_blank')}}> + 创建易修 - + ) } } @@ -677,7 +677,7 @@ class order extends Component { className="topWrapperSelect" overlay={this.renderMenu( issue_chosen && issue_chosen.issue_tag, - "标签", + "标记", "issue_tag_id" )} trigger={["click"]} diff --git a/src/forge/Order/order_form.js b/src/forge/Order/order_form.js index b6f065b2..3399a7fe 100644 --- a/src/forge/Order/order_form.js +++ b/src/forge/Order/order_form.js @@ -153,7 +153,7 @@ class order_form extends Component { values.issue_tag_ids = [values.issue_tag_ids]; } const { description, start_date, due_date, issue_type } = this.state; - if (form_type === "new") { + if (form_type !== "edit") { const url = `/${owner}/${projectsId}/issues.json`; axios.post(url, { ...values, @@ -165,7 +165,7 @@ class order_form extends Component { }).then((result) => { if (result && result.data.id) { this.props.showNotification("任务创建成功!"); - this.props.history.push(`/projects/${owner}/${projectsId}/issues/${result.data.id}/detail`); + this.props.history.push(`/${owner}/${projectsId}/issues/${result.data.id}`); this.setState({ description: "", isSpin: false, @@ -178,7 +178,6 @@ class order_form extends Component { this.setState({ isSpin: false, }); - console.log(error); }); } else { const url = `/${owner}/${projectsId}/issues/${orderId}.json`; @@ -191,7 +190,7 @@ class order_form extends Component { ...values, }).then((result) => { if (result) { - this.props.history.push(`/projects/${owner}/${projectsId}/issues/${orderId}/detail`); + this.props.history.push(`/${owner}/${projectsId}/issues/${orderId}`); this.props.showNotification("任务更新成功!"); const { getDetail } = this.props; getDetail && getDetail(); @@ -321,7 +320,7 @@ class order_form extends Component { message: "请填写易修标题", }, ] - })()} + })()}
    - this.props.history.push(form_type === "new" ? `/projects/${owner}/${projectsId || orderId}/issues` : `/projects/${owner}/${projectsId}/issues/${orderId}/detail`)} + this.props.history.push(form_type === "new" ? `/${owner}/${projectsId || orderId}/issues` : `/${owner}/${projectsId}/issues/${orderId}`)} > 取消 @@ -442,13 +441,13 @@ class order_form extends Component { )} - + {getFieldDecorator("issue_tag_ids", {rules: []})( diff --git a/src/forge/SecuritySetting/Index.jsx b/src/forge/SecuritySetting/Index.jsx index e314c66a..d9fa1bfa 100644 --- a/src/forge/SecuritySetting/Index.jsx +++ b/src/forge/SecuritySetting/Index.jsx @@ -14,17 +14,38 @@ import { Link } from 'react-router-dom'; import './Index.scss'; +const MyNoticeIndex = Loadable({ + loader: () => import("./notice/myNotice/Index"), + loading: Loading, +}); + +const NoticeManager = Loadable({ + loader: () => import("./notice/manager/Index"), + loading: Loading, +}); + const SSHNew = Loadable({ loader: () => import("./sub/New"), loading: Loading, }); +const Profile = Loadable({ + loader: () => import("../users/Material/Index"), + loading: Loading, +}); const SSHIndex = Loadable({ loader: () => import("./sub/SSH"), loading: Loading, }); + +const PrivateLetter = Loadable({ + loader: () => import("./notice/privateLetter/Index"), + loading: Loading, +}); + function Index(props){ - const { current_user } = props; + const { current_user,mygetHelmetapi } = props; const { pathname } = props.location; + const notice_url = mygetHelmetapi && mygetHelmetapi.common && mygetHelmetapi.common.notice; return(
    @@ -35,20 +56,53 @@ function Index(props){ {current_user && current_user.username}
    +
      +
    • 个人信息
    • +
    • -1 ?"active":""}>基本资料
    • +
    + {notice_url &&
      +
    • 消息通知
    • +
    • -1 && pathname.indexOf("/settings/notice/config") == -1) || pathname.indexOf("/settings/notice/privateLetter")>-1 ?"active":""}>我的通知
    • +
    • -1 ?"active":""}>通知管理
    • +
    }
    • 安全设置
    • -
    • -1 ?"active":""}>SSH密钥
    • +
    • -1 ?"active":""}>SSH密钥
    + ( + + )} + > + ( + + )} + > + ( + + )} + > ( )} > + ( + + )} + > ( @@ -60,7 +114,6 @@ function Index(props){
    -
    ) } diff --git a/src/forge/SecuritySetting/Index.scss b/src/forge/SecuritySetting/Index.scss index 664ed7ab..ede91c86 100644 --- a/src/forge/SecuritySetting/Index.scss +++ b/src/forge/SecuritySetting/Index.scss @@ -8,40 +8,44 @@ width: 198px; border: 1px solid rgba(153, 153, 153, 0.22); border-radius: 4px; - min-height: 400px; + // min-height: 400px; margin-bottom: 30px; .userDetail{ background: rgba(153, 153, 153, 0.05); border-radius: 4px 4px 0px 0px; padding:20px 25px; - display: flex; - align-items: center; - justify-content: flex-start; + text-align: center; + height: 105px; img{ height: 48px; width: 48px; border-radius: 50%; - margin-right: 12px; } span{ font-size: 16px; color: #333; - max-width: 90px; display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; + font-weight: 500; } } .securityUl{ - padding:20px 16px; + padding-left: 17px; color: #333; + margin-bottom: 0px; + padding-bottom: 12px; + padding-top: 5px; li{ + font-size: 14px; + margin-top: 10px; margin-bottom: 10px; height: 27px; line-height: 27px; position: relative; - cursor: pointer; + cursor: default; + a{ color: #666; &:hover{ @@ -50,32 +54,57 @@ } &.active a{ color: #333; - } - &:first-child{ - font-size: 16px; + .text-shodow-bold{ + font-weight: 400; + text-shadow: 0.5px 0 #333; + } } &.active::before{ position: absolute; - left: -16px; - top:0px; - height: 100%; - width: 2px; + left: -18px; + top:6px; + height: 15px; + width: 3px; + border-radius: 2px; content: ""; - background-color: #2A61FF; + background-color: #466AFF; + } + + i{ + font-size: 14px !important; + margin-right: 8px; } } } + .ul-border-buttom{ + border-bottom: 1px solid rgba(153, 153, 153, 0.22); + padding-bottom: 5px; + } } .sshHead{ display: flex; align-items: center; - padding:15px 20px; + padding:6px 0px; + margin-bottom: 15px; justify-content: space-between; border-bottom: 1px solid #EEEEEE; - &>span{ + &>.text-shadow07{ font-size: 18px; + font-weight: 400; + color: #333333; + text-shadow: 0.5px 0 #333; + } + &>.add-SSH-title{ + font-size: 16px; + font-weight: 400; + color: #333333; + text-shadow: 0.5px 0 #333; + } + & .but25{ + padding:0 12px; } } + .ant-list-item{ padding:20px; border-bottom: 1px solid #eee!important; @@ -107,7 +136,7 @@ .questionLink{ padding:15px 20px; a{ - color: #4B7AFF; + color: #466AFF; &:hover{ text-decoration: underline; } @@ -122,50 +151,6 @@ } } } -.deleteBox{ - .ant-modal-header{ - background-color: rgba(223, 0, 2, 0.06); - border-bottom: none; - .ant-modal-title{ - text-align: left; - font-size: 20px; - } - } - .ant-modal-body{ - padding:30px 50px; - p{ - font-size: 16px; - line-height: 26px; - color:#666 - } - .desc{ - .descMain{ - align-items: center; - justify-content: center; - font-size: 20px; - margin-bottom: 10px; - i{ - font-size: 38px!important; - color:#DF0002 - } - } - } - } - .ant-modal-footer{ - border-top: none; - text-align: center; - padding-bottom: 40px; - button{ - width: 120px; - margin:0px 20px; - &.ant-btn-danger{ - background-color: #fff; - color: #DF0002; - border-color: #D0D0D0; - } - } - } -} .descModal{ .ant-modal-title{ text-align: left; @@ -189,4 +174,23 @@ flex:1; } } +} +.but25{ + margin-bottom: 5px; + background-color: #466AFF; + color: #fff; + border-color: #466AFF; + &:hover{ + opacity: 0.8; + background-color: #466AFF; + border-color: #466AFF; + } + &:active{ + opacity: 1; + background-color: #466AFF; + border-color: #466AFF; + } +} +.blue-Purple{ + color: #466AFF !important; } \ No newline at end of file diff --git a/src/forge/SecuritySetting/img/miyao_middle_icon.png b/src/forge/SecuritySetting/img/miyao_middle_icon.png index 03584cfe..f69cba0e 100644 Binary files a/src/forge/SecuritySetting/img/miyao_middle_icon.png and b/src/forge/SecuritySetting/img/miyao_middle_icon.png differ diff --git a/src/forge/SecuritySetting/notice/api.js b/src/forge/SecuritySetting/notice/api.js new file mode 100644 index 00000000..07fc1838 --- /dev/null +++ b/src/forge/SecuritySetting/notice/api.js @@ -0,0 +1,46 @@ +import fetch from './fetch'; + +// 获取消息列表 +export function noticePages(params) { + return fetch({ + url: '/api/notice/noticePages', + method: 'get', + params + }); +} + +// 获取单个notice +export function getNotice(params) { + return fetch({ + url: '/api/notice/getNotice', + method: 'get', + params + }); +} + +//新增notice +export function addNotice(data) { + return fetch({ + url: '/api/notice/createNotice', + method: 'post', + data: data + }); +} + +//更新notice +export function updateNotice(data) { + return fetch({ + url: '/api/notice/updateNotice', + method: 'PUT', + data: data + }); +} + +//删除notice +export function deleteNotice(data) { + return fetch({ + url: '/api/notice/deleteNotice', + method: 'DELETE', + data, + }); +} diff --git a/src/forge/SecuritySetting/notice/fetch.js b/src/forge/SecuritySetting/notice/fetch.js new file mode 100644 index 00000000..dba00b14 --- /dev/null +++ b/src/forge/SecuritySetting/notice/fetch.js @@ -0,0 +1,10 @@ + +import javaFetch from '../../javaFetch'; + +const developUrl = "https://test-search.trustie.net"; +const testUrl = "https://test-search.trustie.net"; +const productUrl = "https://wiki-api.trustie.net"; + +const { service, actionUrl } = javaFetch(productUrl, testUrl, developUrl); +export const httpUrl = actionUrl; +export default service; \ No newline at end of file diff --git a/src/forge/SecuritySetting/notice/manager/Index.jsx b/src/forge/SecuritySetting/notice/manager/Index.jsx new file mode 100644 index 00000000..5ba82d60 --- /dev/null +++ b/src/forge/SecuritySetting/notice/manager/Index.jsx @@ -0,0 +1,79 @@ +import { Checkbox } from "antd"; +import React, { useEffect, useState } from "react"; +import axios from 'axios'; +import './Index.scss'; + +function NoticeManager(props){ + const {current_user} = props; + + const [settingTypes, setSettingTypes] = useState(); + const [userNotification, setUserNotification] = useState(); + const [userEmail, setUserEmail] = useState(); + + function onChange(type,e,setting){ + let notification_body = userNotification; + let email_body = userEmail; + if(type){//站内信 + notification_body[setting] = e.target.checked; + }else{//邮件 + email_body[setting] = e.target.checked; + } + axios.post(`/users/${current_user.login}/template_message_settings/update_setting.json`,{ + setting:{ + notification_body:notification_body, + email_body:email_body + } + }).then(response=>{ + if(response && response.status === 0){ + getUserSettings(); + } + }) + } + + function getUserSettings(){ + axios.get(`/users/${current_user.login}/template_message_settings.json`).then((response)=>{ + if(response && response.status === 200 ){ + setUserEmail(response.data.email_body); + setUserNotification(response.data.notification_body); + } + }) + } + + useEffect(()=>{ + axios.get("/template_message_settings.json").then(response => { + if (response && response.status === 200) { + setSettingTypes(response.data.setting_types); + } + }) + getUserSettings(); + },[]) + + return( +
    +
    + 通知管理 +
    +
    + 您可以通过通知管理来选择接受通知的方式 + {settingTypes && userNotification && userEmail && settingTypes.map((item,key)=>{ + return( + item.type_name &&
    +
    {item.type_name}
    + {item.settings.map((i, k) => { + const setting = item.type.substring(item.type.indexOf("::")+2)+"::"+i.key; + return ( +
    +
    {i.name}
    + {onChange(true,e,setting)}}>站内信 + {onChange(false,e,setting)}}>邮件 +
    + ) + })} +
    + ) + })} +
    +
    + ) +} +export default NoticeManager; \ No newline at end of file diff --git a/src/forge/SecuritySetting/notice/manager/Index.scss b/src/forge/SecuritySetting/notice/manager/Index.scss new file mode 100644 index 00000000..87a77a75 --- /dev/null +++ b/src/forge/SecuritySetting/notice/manager/Index.scss @@ -0,0 +1,87 @@ +.notice-manager-tip{ + font-size:16px; + font-weight:400; +} +.manager-cont-top{ + font-size: 14px; + font-weight: 600; + height: 44px; + padding-left: 20px; + background: #FAFCFF; + border: 1px solid #89a4f7; + line-height: 44px; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + margin-top: 25px; +} + +.manager-cont{ + padding: 8px 20px 6px; + display: flex; + align-items: center; + font-size: 14px; + + .manager-cont-title{ + width: 320px; + } +} + +.notice01{ + .ant-checkbox-disabled.ant-checkbox-checked .ant-checkbox-inner::after { + border-color: white; + } + .ant-checkbox-disabled .ant-checkbox-inner { + background-color: #999999 !important; + border-color: #999999 !important; + } + + .ant-checkbox-checked .ant-checkbox-inner { + background-color: #466AFF; + border: #466AFF; + } + + .ant-checkbox-checked::after{ + border: 1px solid #466AFF; + } + .ant-checkbox-wrapper:hover .ant-checkbox-inner, .ant-checkbox:hover .ant-checkbox-inner, .ant-checkbox-input:focus + .ant-checkbox-inner,.ant-radio-checked .ant-radio-inner,.ant-radio-wrapper:hover .ant-radio, .ant-radio:hover .ant-radio-inner, .ant-radio-input:focus + .ant-radio-inner { + border-color: #466AFF; + } + + .ant-checkbox + span,.manager-cont-title { + color: #000000; + } + + .ant-radio-inner::after{ + background-color:#466AFF; + } + + .but25{ + background-color: #466AFF; + color: #fff; + border-color: #466AFF; + &:hover{ + opacity: 0.8; + background-color: #466AFF; + border-color: #466AFF; + } + &:active{ + opacity: 1; + background-color: #466AFF; + border-color: #466AFF; + } + } + + ::-webkit-scrollbar { + width: 5px; /*对垂直流动条有效*/ + } + /*定义滑块颜色、内阴影及圆角*/ + ::-webkit-scrollbar-thumb { + border-radius: 6px; + box-shadow: inset 0 0 6px #FFF; + background-color: #D4D4D4; + } + ::-webkit-scrollbar-track { + box-shadow: inset 0 0 6px #fff; + background-color: #FFF; + } +} \ No newline at end of file diff --git a/src/forge/SecuritySetting/notice/myNotice/Index.jsx b/src/forge/SecuritySetting/notice/myNotice/Index.jsx new file mode 100644 index 00000000..22660691 --- /dev/null +++ b/src/forge/SecuritySetting/notice/myNotice/Index.jsx @@ -0,0 +1,274 @@ +import React, { useState, useEffect } from 'react'; +import { Link } from 'react-router-dom'; +import axios from 'axios'; +import { Badge, Button, Checkbox, Menu, Pagination } from 'antd'; +import DelModal from '../../../Component/ModalFun'; +import NoneData from '../../../Nodata.js'; +import { noticeSourceType } from '../../../common/static'; +import './Index.scss'; +import '../manager/Index.scss' + +function MyNotice(props) { + let { current_user, resetUserInfo, location, mygetHelmetapi, history}= props; + //消息悬停框选择tab + let popover = location && location.query && location.query.noticeType; + let pageSize = 15; + const [noticeType, setNoticeType] = useState(popover==="atme"?"2":"0");//消息类别tab栏选择 + const [selectedNum, setSelectedNum] = useState(0);//@我批量删除选择消息条数 + const [isBatchDelete, setIsBatchDelete] = useState(false);//@我是否批量删除 + const [batchDeleteCheckedAll, setBatchDeleteCheckAll] = useState(false);//@我批量删除--全选 + + const [noticeUnreadCount, setNoticeUnreadCount] = useState();//未读系统通知数量 + // const [letterUnreadCount, setLetterUnreadCount] = useState(0);//未读私信数量 + const [atUnreadCount, setAtUnreadCount] = useState();//未读@我数量 + const [messageList, setMessageList] = useState([]); + const [messTotalCount, setMessTotalCount] = useState();//消息总数 + const [currentPage, setCurrentPage] = useState(1);//当前页数 + const [onlyUnread, setOnlyUnread] = useState(); + + //登录情况下,通过地址访问,直接跳转:/settings/profile + //未登录情况下,通过地址访问,直接跳转:/explore + useEffect(()=>{ + let notice = mygetHelmetapi && mygetHelmetapi.common && mygetHelmetapi.common.notice; + let login = current_user && current_user.login; + if(!login){ + history.push(`/explore`); + }else if(!notice){ + history.push(`/settings/profile`); + } + },[mygetHelmetapi]) + + useEffect(()=>{ + popover==="atme" ? setNoticeType("2"):setNoticeType("0"); + },[popover]) + + useEffect(()=>{ + resetUserInfo(); + },[noticeUnreadCount,atUnreadCount]) + + useEffect(() => { + getMessageList(); + }, [noticeType, onlyUnread, currentPage, current_user]) + + function getMessageList() { + const params = { + type: noticeType === "0" ? "notification" : noticeType === "2" ? "atme" : "", + status: onlyUnread ? onlyUnread : "", + limit: pageSize, + page: currentPage, + }; + current_user && axios.get(`/users/${current_user.login}/messages.json`, { + params: params, + }).then((response) => { + if(response && response.data){ + setNoticeUnreadCount(response.data.unread_notification); + setAtUnreadCount(response.data.unread_atme); + setMessageList(response.data.messages); + setMessTotalCount(response.data.total_count); + } + }); + } + + function readNotice(id){ + if(id && current_user){ + const params = { + type: noticeType === "0" ? "notification" : noticeType === "2" ? "atme" : "", + ids:id, + }; + axios.post(`/users/${current_user.login}/messages/read.json`,params).then((response)=>{ + if(response.status === 200){ + getMessageList(); + //已读当前页码最后一条数据时跳转到前一页 + let totlaPage = Math.ceil((messTotalCount-1)/pageSize); + setCurrentPage(currentPage>=totlaPage? totlaPage : currentPage); + } + }); + } + } + + function handleClick(e) { + setNoticeType(e.key); + setCurrentPage(1); + setOnlyUnread(); + if (e.key != "2") { + setIsBatchDelete(false); + } + } + + function onChange(e) { + var checkboxNum = 0; + let messageListNew=messageList.slice(); + messageListNew.map((item)=>{ + if(item.id===e.target.value){ + item.checkedBatch = e.target.checked; + } + item.checkedBatch?checkboxNum++:""; + }); + setMessageList(messageListNew); + setSelectedNum(checkboxNum); + setBatchDeleteCheckAll(checkboxNum === messageList.length); + } + + + function onChangeAll(e) { + setBatchDeleteCheckAll(e.target.checked); + setSelectedNum(e.target.checked?messageList.length:0); + let messageListNew=messageList.slice(); + messageListNew.map((item)=>{ + item.checkedBatch = e.target.checked; + }); + setMessageList(messageListNew); + } + + function deleteNotice(id) { + const ids = []; + if(!id){ + messageList.map(item=>{ + item.checkedBatch && ids.push(item.id); + }); + } + DelModal({ + title: noticeType === "1" ? '删除私信用户' : id ? '删除消息' : '批量删除', + contentTitle: noticeType === "1" ? '您确定要删除与 xxx 的聊天吗?' : id ? '您确定要删除这条@我消息吗?' : '您确定要删除选中的' + selectedNum + '条消息吗?', + content: noticeType === "1" ? '此操作将删除与xxx的聊天框和xxx的所有聊天记录,请进行确认以防数据的丢失' : id ? '此操作将删除这条消息,请进行确认以防数据的丢失' : '此操作将删除选中的' + selectedNum + '条消息,请进行确认以防数据的丢失', + onOk: () => { + const params = { + type: noticeType === "0" ? "notification" : noticeType === "2" ? "atme" : "", + ids:id?id:ids, + }; + axios.delete(`/users/${current_user.login}/messages.json`,{ + data:params, + }).then((response)=>{ + if(response.status === 200){ + getMessageList(); + //删除当前页码最后一条数据时跳转到前一页 + let totlaPage = Math.ceil((messTotalCount-1)/pageSize); + setCurrentPage(currentPage>=totlaPage? totlaPage : currentPage); + setSelectedNum(0); + setBatchDeleteCheckAll(false); + } + }); + } + }); + } + + function cancelBatchDelete(){ + setIsBatchDelete(false); + setSelectedNum(0); + //取消选中效果 + let messageListNew=messageList.slice(); + messageListNew.map((item)=>{ + item.checkedBatch = false; + }); + setMessageList(messageListNew); + setBatchDeleteCheckAll(false); + } + + //跳转到消息详情页面 + function turnToMess(item){ + if(item.notification_url){ + window.open(`${item.notification_url}`); + readNotice([item.id]); + } + } + + return ( +
    +
    + + 系统通知 + {/* 私信 */} + @我 + + {(noticeType==="0" && noticeUnreadCount>0) || (noticeType==="2"&& atUnreadCount>0) ? :""} +
    + +
    +
    + {onlyUnread===1 || messageList && messageList.length>0 ? e.target.checked ? setOnlyUnread(1) : setOnlyUnread()}>仅看未读{noticeType === "1" ? `私信(12)` : noticeType === "0" ? `消息(${noticeUnreadCount})` : `消息(${atUnreadCount})`}:""} +
    + {noticeType === "2" && messageList && messageList.length > 0 ? : ""} +
    + + {messageList && messageList.length===0 ? :""} + + {messageList && messageList.length>0 &&
    +
    + 全选 +    已选择 {selectedNum} 项 +
    +
    +      + +
    +
    } + + {messageList && messageList.map(item => { + // 系统消息 + if (noticeType === "0") { + // 消息类别 + return ( +
    +
    + {item.status === 1 ? : } + + {turnToMess(item)}} dangerouslySetInnerHTML={{__html: item.content}}> +
    +
    + {item.time_ago} + {item.status === 1 && readNotice([item.id])}>标记为已读} +
    +
    + ) + } else if (noticeType === "2") { + //@我 + return ( +
    +
    + + {item.sender && {window.open(`/${item.sender && item.sender.login}`);}}/>} +
    {turnToMess(item)}}> + {item.status === 1 ? : } + {item.sender && " + item.sender.name+ " "+ item.content +" 中@我"}}>} +
    +
    +
    + {item.time_ago} + {!isBatchDelete && item.status === 1 && readNotice([item.id])}>标记为已读}    + {!isBatchDelete && deleteNotice([item.id])}>删除} +
    +
    + ) + } else{ + //私信 + {/*
    + +
    +
    + 蒋宇航 + 4分钟前 + 删除 +
    +
    props.history.push('/settings/notice/privateLetter')}> + 最好的OpenStack控制台,对标OpenStack社区Horizon项目,最好的OpenStack控制台,对标OpenStack社区Horizon项目,在易用性、页面性能等方面进行深度优化,提供简单控制台。 +
    +
    +
    */} + } + })} + + {/* 分页 */} + {!isBatchDelete &&
    + {setCurrentPage(page)}} + total = {messTotalCount} + hideOnSinglePage + > +
    } +
    + ) +} +export default MyNotice; \ No newline at end of file diff --git a/src/forge/SecuritySetting/notice/myNotice/Index.scss b/src/forge/SecuritySetting/notice/myNotice/Index.scss new file mode 100644 index 00000000..8eab84c0 --- /dev/null +++ b/src/forge/SecuritySetting/notice/myNotice/Index.scss @@ -0,0 +1,259 @@ +.whiteBack .boies .sshHead{ + padding:0 10px 0px 0px; +} +.sshHead{ + .ant-badge{ + font-size: 16px; + color: #333333; + } + .ant-menu-item{ + padding:0px; + margin-right:34px!important; + height: 34px; + width: 64px; + text-align: center; + line-height: 0px; + position: relative; + } + + li.ant-menu-item, .ant-menu-horizontal > .ant-menu-item { + border-bottom: 0px; + } + + & .ant-menu-item-selected{ + color: #333333; + font-weight: 400; + text-shadow: 0.5px 0 #333; + border-bottom: 2px solid #2A61FF !important; + } + + .ant-badge-count, .ant-badge-dot, .ant-badge .ant-scroll-number-custom-component { + right: -6px; + -webkit-box-shadow: 0 0 0 0; + box-shadow: 0 0 0 0; + } + .ant-badge-multiple-words { + padding: 0 0px; + } + + .ant-menu-horizontal { + border-bottom: 0px solid #e8e8e8; + } + + button{ + padding:0 5px; + } +} + +button { + color: #333333; + background: #FAFBFC; + border: 1px solid #D0D0D0; + border-radius: 4px; + height: 32px; +} +button:hover { + background: #F3F4F6; +} +button:active { + background: #EBECF0; +} + +.deleteBut{ + color: #DF0002; +} + +.deleteBut:hover{ + background: #DF0002; + border: 1px solid #DF0002; + color:#FFFFFF; +} + +.deleteBut:active{ + background: #CE0002; + border: 1px solid #CE0002; + color:#FFFFFF; +} + +.mynotice-content { + justify-content: space-between; + padding: 15px 0 15px 10px; + border-bottom: 1px solid #EEEEEE; + color: #333333; + &:hover{ + background: #F3F4F6; + } + + & img{ + cursor: pointer; + } + + & b{ + font-weight: 400; + text-shadow: 0.5px 0 #333; + } + + & .invisable-read{ + display: none; + } + + &:hover .invisable-read{ + display: block; + color: #466AFF; + opacity: 0.6; + cursor: pointer; + + &:hover{ + opacity: 1; + } + } + + &:hover .timeSpan{ + display: none; + } + + i{ + font-size: 16px !important; + margin-right: 5px; + } + + .boldSpan{ + font-weight: 400; + text-shadow: 0.5px 0 0 #333; + margin: 0 8px; + } + & .currentImg{ + width: 40px; + height: 40px; + margin-left: 0px; + } + + & .private-letter-img + .ant-badge-count{ + top: 2px; + right: 5px; + height: 18px; + min-width: 18px; + line-height: 18px; + padding: 0 0; + } + + & .highlightSpan:hover{ + color: #466AFF; + cursor: pointer; + } + + .mynotice-cont{ + padding:0; + cursor: default; + & .visible-checkbox{ + margin-right: 10px; + } + & .invisible-checkbox{ + display: none; + } + .atme-notice-text{ + margin-left: 6px; + + & .atme-notice-name{ + margin: 0 0 ; + } + + & .atme-length{ + max-width: 48rem; + word-break: break-all; + } + } + } + + & .ant-badge-count, .ant-badge-dot, .ant-badge .ant-scroll-number-custom-component { + -webkit-box-shadow: 0 0 0 0; + box-shadow: 0 0 0 0; + top: 3px; + right: 4px; + min-width: 8px; + height: 8px; + } + + & .system-notice-blank{ + margin-right: 14px; + } +} + +.batchDel{ + & .currentImg, & .atme-notice-text{ + pointer-events: none; + } +} + +.baselineDiv{ + align-items: baseline; +} + +.invisible { + display: none; +} + +.visible { + display: flex; + justify-content: space-between; + height: 30px; + padding: 0 10px; + color: #333333; + margin-bottom: 5px; + button{ + padding:0px 12px; + } + .batchDeleteBut{ + border:1px solid #466AFF; + color: #466AFF; + } +} + +.private-letter-right { + flex: auto; + margin: 0px 10px 0 16px; + & div{ + display: flex; + justify-content: space-between; + } +} + +.letter-length-limit{ + max-width: 50rem; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.sysNotice-length{ + max-width: 52rem; + word-break: break-all; +} + + +.numberSpan{ + color: #466AFF; +} + +.vertical-center-style{ + display: flex; + align-items: center; +} + +.stretch-style{ + display: flex; + align-items: baseline; +} + +.float-left-little{ + margin-right: 10px; +} + +.float-right-little{ + margin-left: 12px; +} + +.paging{ + text-align: center; + margin: 12px; +} \ No newline at end of file diff --git a/src/forge/SecuritySetting/notice/privateLetter/Index.jsx b/src/forge/SecuritySetting/notice/privateLetter/Index.jsx new file mode 100644 index 00000000..51758377 --- /dev/null +++ b/src/forge/SecuritySetting/notice/privateLetter/Index.jsx @@ -0,0 +1,200 @@ +import React, { useState, useEffect } from 'react'; +import './Index.scss' +import '../manager/Index.scss' +import { Button, Input, Icon, Badge } from 'antd'; +import { Link } from 'react-router-dom'; + +function PrivateLetter(props){ + + const { TextArea,Search } = Input; + + function deleteNotice(){ + alert("删除消息"); + } + + return( +
    +
    +
    + + 蒋宇航 +
    +
    +
    + +
    +
    + 嗨在吗?哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈 + 删除 +
    + 2021-08-29 11:59 +
    + +
    + +
    +
    + 哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈 + 删除 +
    + 2021-08-29 11:59 +
    + +
    +
    +
    + +