diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..7a73a41bf --- /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 a7b2c9f4e..4a9d94652 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 31e8c6291..9ea84263c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { - "name": "educoder", - "version": "0.1.0", + "name": "forge", + "version": "3.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -990,6 +990,18 @@ "react-lifecycles-compat": "^3.0.4", "warning": "^4.0.3" } + }, + "react-slick": { + "version": "0.25.2", + "resolved": "https://registry.nlark.com/react-slick/download/react-slick-0.25.2.tgz", + "integrity": "sha1-VjMbZ9R9i8/i3OtqyrHI/VvR9rw=", + "requires": { + "classnames": "^2.2.5", + "enquire.js": "^2.1.6", + "json2mq": "^0.2.0", + "lodash.debounce": "^4.0.8", + "resize-observer-polyfill": "^1.5.0" + } } } }, @@ -1261,7 +1273,7 @@ }, "babel-cli": { "version": "6.26.0", - "resolved": "https://registry.npm.taobao.org/babel-cli/download/babel-cli-6.26.0.tgz", + "resolved": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.26.0.tgz", "integrity": "sha1-UCq1SHTX24itALiHoGODzgPQAvE=", "dev": true, "requires": { @@ -1284,7 +1296,7 @@ "dependencies": { "chokidar": { "version": "1.7.0", - "resolved": "https://registry.npm.taobao.org/chokidar/download/chokidar-1.7.0.tgz?cache=0&sync_timestamp=1602585438968&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchokidar%2Fdownload%2Fchokidar-1.7.0.tgz", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", "dev": true, "optional": true, @@ -1302,7 +1314,7 @@ }, "source-map": { "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true } @@ -1401,7 +1413,7 @@ }, "babel-helper-bindify-decorators": { "version": "6.24.1", - "resolved": "https://registry.npm.taobao.org/babel-helper-bindify-decorators/download/babel-helper-bindify-decorators-6.24.1.tgz", + "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz", "integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=", "dev": true, "requires": { @@ -1464,7 +1476,7 @@ }, "babel-helper-explode-class": { "version": "6.24.1", - "resolved": "https://registry.npm.taobao.org/babel-helper-explode-class/download/babel-helper-explode-class-6.24.1.tgz", + "resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz", "integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=", "dev": true, "requires": { @@ -1664,7 +1676,7 @@ }, "babel-plugin-syntax-async-generators": { "version": "6.13.0", - "resolved": "https://registry.npm.taobao.org/babel-plugin-syntax-async-generators/download/babel-plugin-syntax-async-generators-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=", "dev": true }, @@ -1675,7 +1687,7 @@ }, "babel-plugin-syntax-decorators": { "version": "6.13.0", - "resolved": "https://registry.npm.taobao.org/babel-plugin-syntax-decorators/download/babel-plugin-syntax-decorators-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=", "dev": true }, @@ -1711,7 +1723,7 @@ }, "babel-plugin-transform-async-generator-functions": { "version": "6.24.1", - "resolved": "https://registry.npm.taobao.org/babel-plugin-transform-async-generator-functions/download/babel-plugin-transform-async-generator-functions-6.24.1.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz", "integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=", "dev": true, "requires": { @@ -1743,7 +1755,7 @@ }, "babel-plugin-transform-decorators": { "version": "6.24.1", - "resolved": "https://registry.npm.taobao.org/babel-plugin-transform-decorators/download/babel-plugin-transform-decorators-6.24.1.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz", "integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=", "dev": true, "requires": { @@ -2048,7 +2060,7 @@ }, "babel-plugin-transform-runtime": { "version": "6.23.0", - "resolved": "https://registry.npm.taobao.org/babel-plugin-transform-runtime/download/babel-plugin-transform-runtime-6.23.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz", "integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=", "requires": { "babel-runtime": "^6.22.0" @@ -2065,9 +2077,8 @@ }, "babel-polyfill": { "version": "6.26.0", - "resolved": "https://registry.npm.taobao.org/babel-polyfill/download/babel-polyfill-6.26.0.tgz", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", - "dev": true, "requires": { "babel-runtime": "^6.26.0", "core-js": "^2.5.0", @@ -2076,9 +2087,8 @@ "dependencies": { "regenerator-runtime": { "version": "0.10.5", - "resolved": "https://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.10.5.tgz?cache=0&sync_timestamp=1595456367497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.10.5.tgz", - "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", - "dev": true + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" } } }, @@ -2121,7 +2131,7 @@ }, "babel-preset-es2015": { "version": "6.24.1", - "resolved": "https://registry.npm.taobao.org/babel-preset-es2015/download/babel-preset-es2015-6.24.1.tgz", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", "dev": true, "requires": { @@ -2169,7 +2179,7 @@ }, "babel-preset-react": { "version": "6.24.1", - "resolved": "https://registry.npm.taobao.org/babel-preset-react/download/babel-preset-react-6.24.1.tgz", + "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz", "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=", "requires": { "babel-plugin-syntax-jsx": "^6.3.13", @@ -2202,7 +2212,7 @@ }, "babel-preset-stage-2": { "version": "6.24.1", - "resolved": "https://registry.npm.taobao.org/babel-preset-stage-2/download/babel-preset-stage-2-6.24.1.tgz", + "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz", "integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=", "dev": true, "requires": { @@ -2214,7 +2224,7 @@ }, "babel-preset-stage-3": { "version": "6.24.1", - "resolved": "https://registry.npm.taobao.org/babel-preset-stage-3/download/babel-preset-stage-3-6.24.1.tgz", + "resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz", "integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=", "dev": true, "requires": { @@ -2367,6 +2377,12 @@ } } }, + "base16": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/base16/download/base16-1.0.0.tgz", + "integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=", + "dev": true + }, "base64-js": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", @@ -3409,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", @@ -3491,7 +3507,7 @@ }, "code-prettify": { "version": "0.1.0", - "resolved": "https://registry.npm.taobao.org/code-prettify/download/code-prettify-0.1.0.tgz", + "resolved": "https://registry.npmjs.org/code-prettify/-/code-prettify-0.1.0.tgz", "integrity": "sha1-RocMyMGlDQm61TmzOpg9vUqjSx4=" }, "codemirror": { @@ -3859,6 +3875,69 @@ "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", + "integrity": "sha1-lyPzo6JHv4uJA586OAqSROj6Lzk=", + "dev": true, + "requires": { + "node-fetch": "2.6.1" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.nlark.com/node-fetch/download/node-fetch-2.6.1.tgz?cache=0&sync_timestamp=1626684741221&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fnode-fetch%2Fdownload%2Fnode-fetch-2.6.1.tgz", + "integrity": "sha1-BFvTI2Mfdu0uK1VXM5RBa2OaAFI=", + "dev": true + } + } + }, "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -3893,11 +3972,6 @@ "randomfill": "^1.0.3" } }, - "crypto-js": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/crypto-js/download/crypto-js-4.0.0.tgz", - "integrity": "sha1-KQSrJnep0EKFai6i74DekuSjbcw=" - }, "crypto-random-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", @@ -5063,11 +5137,11 @@ } }, "echarts": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/echarts/-/echarts-4.7.0.tgz", - "integrity": "sha512-NlOTdUcAsIyCCG+N4uh0ZEvXtrPW2jvcuqf03RyqYeCKzyPbiOQ4I3MdKXMhxG3lBdqQNdNXVT71SB4KTQjN0A==", + "version": "4.9.0", + "resolved": "https://registry.nlark.com/echarts/download/echarts-4.9.0.tgz", + "integrity": "sha1-qbm6oD8Doqcx5jQMVb77V6nhNH0=", "requires": { - "zrender": "4.3.0" + "zrender": "4.3.2" } }, "echarts-wordcloud": { @@ -6209,6 +6283,41 @@ "bser": "2.1.1" } }, + "fbemitter": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/fbemitter/download/fbemitter-3.0.0.tgz", + "integrity": "sha1-ALKhr1QRJUqrQWzXX55iib7kv/M=", + "dev": true, + "requires": { + "fbjs": "^3.0.0" + }, + "dependencies": { + "fbjs": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/fbjs/download/fbjs-3.0.0.tgz?cache=0&sync_timestamp=1602048313843&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffbjs%2Fdownload%2Ffbjs-3.0.0.tgz", + "integrity": "sha1-CQcGf7P1enj0XZXx6s/8rNYjwWU=", + "dev": true, + "requires": { + "cross-fetch": "^3.0.4", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npm.taobao.org/promise/download/promise-7.3.1.tgz", + "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", + "dev": true, + "requires": { + "asap": "~2.0.3" + } + } + } + }, "fbjs": { "version": "0.8.17", "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", @@ -6238,6 +6347,12 @@ } } }, + "fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/fbjs-css-vars/download/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha1-IWVRE2rgL+JVkyw+yHdfGOLAeLg=", + "dev": true + }, "fecha": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", @@ -6682,6 +6797,42 @@ "readable-stream": "^2.3.6" } }, + "flux": { + "version": "4.0.1", + "resolved": "https://registry.npm.taobao.org/flux/download/flux-4.0.1.tgz", + "integrity": "sha1-eENQKwKEHUqqU0rws3MDSh917lw=", + "dev": true, + "requires": { + "fbemitter": "^3.0.0", + "fbjs": "^3.0.0" + }, + "dependencies": { + "fbjs": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/fbjs/download/fbjs-3.0.0.tgz?cache=0&sync_timestamp=1602048313843&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffbjs%2Fdownload%2Ffbjs-3.0.0.tgz", + "integrity": "sha1-CQcGf7P1enj0XZXx6s/8rNYjwWU=", + "dev": true, + "requires": { + "cross-fetch": "^3.0.4", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npm.taobao.org/promise/download/promise-7.3.1.tgz", + "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", + "dev": true, + "requires": { + "asap": "~2.0.3" + } + } + } + }, "flv.js": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/flv.js/-/flv.js-1.5.0.tgz", @@ -9898,6 +10049,11 @@ "esprima": "^4.0.0" } }, + "js2wordcloud": { + "version": "1.1.12", + "resolved": "https://registry.npm.taobao.org/js2wordcloud/download/js2wordcloud-1.1.12.tgz", + "integrity": "sha1-8BdC2k5qyzAAsoY1dmQWjvn8o64=" + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -10320,6 +10476,12 @@ "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=" }, + "lodash.curry": { + "version": "4.1.1", + "resolved": "https://registry.npm.taobao.org/lodash.curry/download/lodash.curry-4.1.1.tgz", + "integrity": "sha1-JI42By7ekGUB11lmIAqG2riyMXA=", + "dev": true + }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -10330,6 +10492,12 @@ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" }, + "lodash.flow": { + "version": "3.5.0", + "resolved": "https://registry.npm.taobao.org/lodash.flow/download/lodash.flow-3.5.0.tgz", + "integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=", + "dev": true + }, "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", @@ -11551,7 +11719,7 @@ }, "output-file-sync": { "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/output-file-sync/download/output-file-sync-1.1.2.tgz", + "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz", "integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=", "dev": true, "requires": { @@ -13960,6 +14128,12 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, + "pure-color": { + "version": "1.3.0", + "resolved": "https://registry.npm.taobao.org/pure-color/download/pure-color-1.3.0.tgz", + "integrity": "sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=", + "dev": true + }, "purgecss": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-2.1.2.tgz", @@ -14034,9 +14208,9 @@ "integrity": "sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8=" }, "qrcode.react": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-1.0.0.tgz", - "integrity": "sha512-jBXleohRTwvGBe1ngV+62QvEZ/9IZqQivdwzo9pJM4LQMoCM2VnvNBnKdjvGnKyDZ/l0nCDgsPod19RzlPvm/Q==", + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/qrcode.react/download/qrcode.react-1.0.1.tgz", + "integrity": "sha1-KDS7UOXidf/lr2kG7/FTkf6eOKU=", "requires": { "loose-envify": "^1.4.0", "prop-types": "^15.6.0", @@ -14731,6 +14905,18 @@ "prop-types": "^15.6.2" } }, + "react-base16-styling": { + "version": "0.6.0", + "resolved": "https://registry.npm.taobao.org/react-base16-styling/download/react-base16-styling-0.6.0.tgz", + "integrity": "sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw=", + "dev": true, + "requires": { + "base16": "^1.0.0", + "lodash.curry": "^4.0.1", + "lodash.flow": "^3.3.0", + "pure-color": "^1.2.0" + } + }, "react-beautiful-dnd": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-10.1.1.tgz", @@ -15096,6 +15282,18 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "react-json-view": { + "version": "1.21.3", + "resolved": "https://registry.npm.taobao.org/react-json-view/download/react-json-view-1.21.3.tgz", + "integrity": "sha1-8YQgnujxvzdPsMQbCBPP9UVJxHU=", + "dev": true, + "requires": { + "flux": "^4.0.1", + "react-base16-styling": "^0.6.0", + "react-lifecycles-compat": "^3.0.4", + "react-textarea-autosize": "^8.3.2" + } + }, "react-jss": { "version": "8.6.1", "resolved": "https://registry.npmjs.org/react-jss/-/react-jss-8.6.1.tgz", @@ -15255,9 +15453,9 @@ } }, "react-slick": { - "version": "0.25.2", - "resolved": "https://registry.nlark.com/react-slick/download/react-slick-0.25.2.tgz", - "integrity": "sha1-VjMbZ9R9i8/i3OtqyrHI/VvR9rw=", + "version": "0.28.1", + "resolved": "https://registry.nlark.com/react-slick/download/react-slick-0.28.1.tgz", + "integrity": "sha1-EsGNmRtZQy35w3V7pUCiJ7P7hbk=", "requires": { "classnames": "^2.2.5", "enquire.js": "^2.1.6", @@ -15284,6 +15482,34 @@ "prop-types": "^15.5.4" } }, + "react-textarea-autosize": { + "version": "8.3.3", + "resolved": "https://registry.nlark.com/react-textarea-autosize/download/react-textarea-autosize-8.3.3.tgz?cache=0&sync_timestamp=1622628433420&other_urls=https%3A%2F%2Fregistry.nlark.com%2Freact-textarea-autosize%2Fdownload%2Freact-textarea-autosize-8.3.3.tgz", + "integrity": "sha1-9wkTlFNp2kU/1VTBaPa6rNH6BNg=", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "use-composed-ref": "^1.0.0", + "use-latest": "^1.0.0" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.14.8", + "resolved": "https://registry.nlark.com/@babel/runtime/download/@babel/runtime-7.14.8.tgz", + "integrity": "sha1-cRmlb0IQGIUmlCkLn5FICXORtEY=", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.nlark.com/regenerator-runtime/download/regenerator-runtime-0.13.9.tgz?cache=0&sync_timestamp=1626993001371&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.13.9.tgz", + "integrity": "sha1-iSV0Kpj/2QgUmI11Zq0wyjsmO1I=", + "dev": true + } + } + }, "react-transition-group": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", @@ -16406,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", @@ -17040,6 +17271,11 @@ "is-fullwidth-code-point": "^2.0.0" } }, + "slick-carousel": { + "version": "1.8.1", + "resolved": "https://registry.npm.taobao.org/slick-carousel/download/slick-carousel-1.8.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fslick-carousel%2Fdownload%2Fslick-carousel-1.8.1.tgz", + "integrity": "sha1-pL+ykBSIe7Zs5Si5C9DNomLMj40=" + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -18374,6 +18610,12 @@ "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", "dev": true }, + "ts-essentials": { + "version": "2.0.12", + "resolved": "https://registry.nlark.com/ts-essentials/download/ts-essentials-2.0.12.tgz", + "integrity": "sha1-yTA/PXT3X6dSjD1JuA4ImrCdh0U=", + "dev": true + }, "tslib": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", @@ -18883,9 +19125,33 @@ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, + "use-composed-ref": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/use-composed-ref/download/use-composed-ref-1.1.0.tgz", + "integrity": "sha1-kiDk6UqXt7AtfSfq6rCzcDRDi7w=", + "dev": true, + "requires": { + "ts-essentials": "^2.0.3" + } + }, + "use-isomorphic-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/use-isomorphic-layout-effect/download/use-isomorphic-layout-effect-1.1.1.tgz", + "integrity": "sha1-e7ZYkXDNKYehUgQvkIT57/t1wiU=", + "dev": true + }, + "use-latest": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/use-latest/download/use-latest-1.2.0.tgz", + "integrity": "sha1-pE9lcrgojgly7EEb3QhAraNm8jI=", + "dev": true, + "requires": { + "use-isomorphic-layout-effect": "^1.0.0" + } + }, "user-home": { "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/user-home/download/user-home-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", "dev": true }, @@ -18942,7 +19208,7 @@ }, "v8flags": { "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/v8flags/download/v8flags-2.1.1.tgz?cache=0&sync_timestamp=1590964281452&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fv8flags%2Fdownload%2Fv8flags-2.1.1.tgz", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", "dev": true, "requires": { @@ -20486,6 +20752,16 @@ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true }, + "xterm": { + "version": "4.8.1", + "resolved": "https://registry.npm.taobao.org/xterm/download/xterm-4.8.1.tgz", + "integrity": "sha1-FVoXKaQ+Gom0BlJOIsVjQznjnKE=" + }, + "xterm-addon-fit": { + "version": "0.4.0", + "resolved": "https://registry.npm.taobao.org/xterm-addon-fit/download/xterm-addon-fit-0.4.0.tgz", + "integrity": "sha1-BuDF0KaqrPsAnvVl76HIHpPZAZM=" + }, "y18n": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", @@ -20523,9 +20799,9 @@ } }, "zrender": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/zrender/-/zrender-4.3.0.tgz", - "integrity": "sha512-Dii6j2bDsPkxQayuVf2DXJeruIB/mKVxxcGRZQ9GExiBd4c3w7+oBuvo1O/JGHeFeA1nCmSDVDs/S7yKZG1nrA==" + "version": "4.3.2", + "resolved": "https://registry.npm.taobao.org/zrender/download/zrender-4.3.2.tgz", + "integrity": "sha1-7HQy+UFcgsc1hLa3uMR+GwFiCcY=" } } } diff --git a/package.json b/package.json index 2e61175be..04142cb4d 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", @@ -203,6 +206,7 @@ "node-sass": "^4.12.0", "optimize-css-assets-webpack-plugin": "^5.0.3", "purgecss": "^2.1.2", + "react-json-view": "^1.21.3", "reqwest": "^2.0.5", "resize-observer-polyfill": "^1.5.1", "terser-webpack-plugin": "^2.3.5", diff --git a/public/css/edu-common.css b/public/css/edu-common.css index 96a8277df..56790f055 100755 --- a/public/css/edu-common.css +++ b/public/css/edu-common.css @@ -114,14 +114,6 @@ a:visited { color: #898989; } -a:hover { - color: #FF7500; -} - -a:hover.fa { - color: #FF7500; -} - input, textarea, select { diff --git a/public/css/edu-main.css b/public/css/edu-main.css index 3cbe5fcbb..1d9959033 100644 --- a/public/css/edu-main.css +++ b/public/css/edu-main.css @@ -97,10 +97,6 @@ a:visited { color: #05101a; } -a:hover { - color: #459be5; -} - ol, ul, li { diff --git a/public/css/edu-purge.css b/public/css/edu-purge.css index 2c470f7a7..70478686f 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: #459be5; -} - ol, ul, li { @@ -1473,7 +1471,7 @@ a.edu-txt-w80, /*隐藏*/ .none { - display: none + display: none!important; } .block { @@ -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,12 +1760,20 @@ a.decoration { margin-bottom: 10px; } +.mb12 { + margin-bottom: 12px; +} + +.mb13 { + margin-bottom: 13px; +} + .mb14 { margin-bottom: 14px; } .mb15 { - margin-bottom: 15px; + margin-bottom: 15px!important; } .mb16 { @@ -2424,13 +2444,23 @@ input::-ms-clear { .color-grey-c { color: #ccc !important; } - +a.hoverLine:hover{ + text-decoration: underline; +} .color-grey-cd { color: #cdcdcd !important; } +.color-grey-d { + color: #ddd; +} + .color-grey-9 { - color: #999999 !important; + color: #999 !important; +} + +a:hover{ + color: #466AFF !important; } .color-grey-98 { @@ -2465,33 +2495,23 @@ input::-ms-clear { a.color-grey-name:hover, a.color-dark:hover, a.color-grey-6:hover, -a.color-grey-3:hover { - color: #4cacff !important; -} - -a.color-grey-9:hover, -a.color-grey-8:hover, -a.color-grey-c:hover { - color: #111C24 !important; +a.color-grey-3:hover,a.color-ooo:hover { + color: #2A61FF !important; } /*蓝色*/ .color-blue { - color: #4CACFF !important; + color: #2A61FF !important; +} +.color-blue-file { + color: #4598FA!important; } /* 绿色 */ -.color-green-file{ - color: #28BD6C; -} /*主*/ .color-blue_4C { color: #4CACFF !important; } -a.color-blue:hover, -a.color-blue_4C:hover { - color: #459BE6 !important; -} /*橙色*/ .color-orange { @@ -3409,7 +3429,7 @@ a.user_bluebg_btn { } .cdefault { - cursor: default + cursor: default!important; } @@ -3584,42 +3604,6 @@ a.user_bluebg_btn { margin-right: 5px; } -/*-------------------个人主页:右侧提示区域--------------------------*/ -.-task-sidebar { - position: fixed; - width: 40px; - height: 180px; - right: 0; - bottom: 80px; - z-index: 10; -} - -.-task-sidebar div { - height: 40px; - line-height: 40px; - box-sizing: border-box; - width: 40px; - background: #4CACFF; - color: #fff; - font-size: 20px; - text-align: center; - margin-bottom: 5px; - border-radius: 4px; -} - -.-task-sidebar div i { - color: #fff; -} - -.-task-sidebar div i:hover { - color: #fff !important; -} - -.gotop { - background-color: rgba(208, 207, 207, 0.5) !important; - padding: 0px !important; -} - /***** loading ******/ /*****载入中******/ @@ -3944,11 +3928,21 @@ html>body #ajax-indicator { max-height: 340px; }/*头部导航条样式---2018-03-19--by-cs*/ +.privateTag{ + display: block; + padding:0px 6px; + border-radius: 12px; + border:1px solid #2FC25B; + height: 18px; + line-height: 18px; + font-size: 12px; + margin-left: 10px; + color: #2FC25B; +} .head-nav { text-align: center; height: 70px; box-sizing: border-box; - min-width: 780px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -6711,4 +6705,13 @@ p{ right: 0px; top:4px; color: #999; +<<<<<<< HEAD +======= +} +.ant-input, .ant-input .ant-input-suffix{ + background-color: #fff!important; +} +.has-error .ant-input{ + background-color: #FEF1F0!important; +>>>>>>> pre_develop } \ No newline at end of file diff --git a/public/css/iconfont.css b/public/css/iconfont.css index 7035af055..3866189c2 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=1622517296245') format('woff2'), - url('iconfont.woff?t=1622517296245') format('woff'), - url('iconfont.ttf?t=1622517296245') 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,462 @@ -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"; +} + +.icon-xieyiicon:before { + content: "\e870"; +} + +.icon-neicunicon:before { + content: "\e891"; +} + +.icon-zishuwenjian_icon:before { + content: "\e8a6"; +} + +.icon-biaoqianicon:before { + content: "\e882"; +} + +.icon-a-bianji:before { + content: "\e883"; +} + +.icon-lianjieicon:before { + content: "\e887"; +} + +.icon-hebingqingqiuicon:before { + content: "\e888"; +} + +.icon-morendianzan_icon:before { + content: "\e88e"; +} + +.icon-muluicon:before { + content: "\e894"; +} + +.icon-a-shezhi:before { + content: "\e899"; +} + +.icon-tijiaoicon:before { + content: "\e89e"; +} + +.icon-morenguanzhu_ICON:before { + content: "\e89f"; +} + +.icon-xialaanniu1:before { + content: "\e8a4"; +} + +.icon-zuohuaicon:before { + content: "\e8b5"; +} + +.icon-master_icon:before { + content: "\e8b6"; +} + +.icon-morenfuke_icon:before { + content: "\e8b7"; +} + +.icon-a-wikiicon:before { + content: "\e8b8"; +} + +.icon-yixiuicon:before { + content: "\e8b9"; +} + +.icon-suofang:before { + content: "\e87f"; +} + +.icon-fangdaicon:before { + content: "\e881"; +} + +.icon-sousuo_icon1:before { + content: "\e873"; +} + +.icon-huanying_icon:before { + content: "\e878"; +} + +.icon-wenjianjia2:before { + content: "\e879"; +} + +.icon-shanchuicon1:before { + content: "\e87a"; +} + +.icon-qingqiuicon:before { + content: "\e871"; +} + +.icon-xiangyingicon:before { + content: "\e87c"; +} + +.icon-duoxuanxuanzhong:before { + content: "\e88f"; +} + +.icon-cuowuicon:before { + content: "\e890"; +} + +.icon-chenggongicon:before { + content: "\e892"; +} + +.icon-weixuanzhongxiangyingicon:before { + content: "\e893"; +} + +.icon-bitianicon:before { + content: "\e895"; +} + +.icon-weixuanzhongxiangmubiaoqianicon:before { + content: "\e897"; +} + +.icon-liebiaoicon:before { + content: "\e898"; +} + +.icon-xiezuozheguanliicon:before { + content: "\e8a1"; +} + +.icon-xuanzhongfenzhiicon:before { + content: "\e8a3"; +} + +.icon-xuanzhongjibenshezhiicon:before { + content: "\e8a5"; +} + +.icon-xuanzhongxiangmubiaoqianicon:before { + content: "\e8aa"; +} + +.icon-a-xuanzhongwebhookicon:before { + content: "\e8af"; +} + +.icon-shanchu_tc_icon:before { + content: "\e88c"; +} + +.icon-wiki_icon:before { + content: "\e88d"; +} + +.icon-daorumoban_icon:before { + content: "\e86f"; +} + +.icon-cuowu:before { + content: "\e872"; +} + +.icon-gengduo_icon:before { + content: "\e874"; +} + +.icon-fucengguanbi_icon:before { + content: "\e875"; +} + +.icon-shanchuicon:before { + content: "\e877"; +} + +.icon-sousuo_shanchuicon:before { + content: "\e87b"; +} + +.icon-sousuo_icon:before { + content: "\e87d"; +} + +.icon-wendangyulan_icon:before { + content: "\e87e"; +} + +.icon-xialaanniu:before { + content: "\e880"; +} + +.icon-erciqueren_icon:before { + content: "\e867"; +} + +.icon-xuanzhongssh_icon:before { + content: "\e868"; +} + +.icon-weixuanzhonganquanshezhi_icon:before { + content: "\e869"; +} + +.icon-weixuanzhongssh_icon:before { + content: "\e86a"; +} + +.icon-xuanzhonganquanshezhi_icon:before { + content: "\e86b"; +} + +.icon-shanchu_icon:before { + content: "\e86c"; +} + +.icon-liebiaossh_icon:before { + content: "\e86e"; +} + +.icon-file-submodule:before { + content: "\e866"; +} + +.icon-nv1:before { + content: "\e864"; +} + +.icon-nan1:before { + content: "\e865"; +} + .icon-youxiang:before { content: "\e8b2"; } diff --git a/public/css/iconfont.eot b/public/css/iconfont.eot deleted file mode 100644 index d13e3094f..000000000 Binary files a/public/css/iconfont.eot and /dev/null differ diff --git a/public/css/iconfont.js b/public/css/iconfont.js index 068c8e0a5..a32ef5e59 100644 --- a/public/css/iconfont.js +++ b/public/css/iconfont.js @@ -1 +1 @@ -!function(c){var l,a,h,i,o,z,t='',p=(p=document.getElementsByTagName("script"))[p.length-1].getAttribute("data-injectcss");if(p&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}function v(){o||(o=!0,h())}l=function(){var c,l,a;(a=document.createElement("div")).innerHTML=t,t=null,(l=a.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",c=l,(a=document.body).firstChild?(l=a.firstChild).parentNode.insertBefore(c,l):a.appendChild(c))},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,(z=function(){try{i.documentElement.doScroll("left")}catch(c){return void setTimeout(z,50)}v()})(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,v())})}(window); \ No newline at end of file +!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); diff --git a/public/css/iconfont.json b/public/css/iconfont.json index 877958d72..5acfb6e98 100644 --- a/public/css/iconfont.json +++ b/public/css/iconfont.json @@ -5,6 +5,804 @@ "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": "新建", + "font_class": "xinjian2", + "unicode": "e8b0", + "unicode_decimal": 59568 + }, + { + "icon_id": "23567674", + "name": "协议icon", + "font_class": "xieyiicon", + "unicode": "e870", + "unicode_decimal": 59504 + }, + { + "icon_id": "23567675", + "name": "内存icon", + "font_class": "neicunicon", + "unicode": "e891", + "unicode_decimal": 59537 + }, + { + "icon_id": "23567676", + "name": "自述文件_icon", + "font_class": "zishuwenjian_icon", + "unicode": "e8a6", + "unicode_decimal": 59558 + }, + { + "icon_id": "23472253", + "name": "标签icon", + "font_class": "biaoqianicon", + "unicode": "e882", + "unicode_decimal": 59522 + }, + { + "icon_id": "23472254", + "name": "编 辑", + "font_class": "a-bianji", + "unicode": "e883", + "unicode_decimal": 59523 + }, + { + "icon_id": "23472258", + "name": "链接icon", + "font_class": "lianjieicon", + "unicode": "e887", + "unicode_decimal": 59527 + }, + { + "icon_id": "23472259", + "name": "合并请求icon", + "font_class": "hebingqingqiuicon", + "unicode": "e888", + "unicode_decimal": 59528 + }, + { + "icon_id": "23472263", + "name": "默认点赞_icon", + "font_class": "morendianzan_icon", + "unicode": "e88e", + "unicode_decimal": 59534 + }, + { + "icon_id": "23472265", + "name": "目录icon", + "font_class": "muluicon", + "unicode": "e894", + "unicode_decimal": 59540 + }, + { + "icon_id": "23472267", + "name": "设 置", + "font_class": "a-shezhi", + "unicode": "e899", + "unicode_decimal": 59545 + }, + { + "icon_id": "23472269", + "name": "提交icon", + "font_class": "tijiaoicon", + "unicode": "e89e", + "unicode_decimal": 59550 + }, + { + "icon_id": "23472270", + "name": "默认关注_ICON", + "font_class": "morenguanzhu_ICON", + "unicode": "e89f", + "unicode_decimal": 59551 + }, + { + "icon_id": "23472272", + "name": "下拉按钮", + "font_class": "xialaanniu1", + "unicode": "e8a4", + "unicode_decimal": 59556 + }, + { + "icon_id": "23472276", + "name": "左滑icon", + "font_class": "zuohuaicon", + "unicode": "e8b5", + "unicode_decimal": 59573 + }, + { + "icon_id": "23472277", + "name": "master_icon", + "font_class": "master_icon", + "unicode": "e8b6", + "unicode_decimal": 59574 + }, + { + "icon_id": "23472278", + "name": "默认复刻_icon", + "font_class": "morenfuke_icon", + "unicode": "e8b7", + "unicode_decimal": 59575 + }, + { + "icon_id": "23472279", + "name": "wiki icon", + "font_class": "a-wikiicon", + "unicode": "e8b8", + "unicode_decimal": 59576 + }, + { + "icon_id": "23472280", + "name": "易修icon", + "font_class": "yixiuicon", + "unicode": "e8b9", + "unicode_decimal": 59577 + }, + { + "icon_id": "23436350", + "name": "缩放", + "font_class": "suofang", + "unicode": "e87f", + "unicode_decimal": 59519 + }, + { + "icon_id": "23436351", + "name": "放大icon", + "font_class": "fangdaicon", + "unicode": "e881", + "unicode_decimal": 59521 + }, + { + "icon_id": "23384231", + "name": "搜索_icon", + "font_class": "sousuo_icon1", + "unicode": "e873", + "unicode_decimal": 59507 + }, + { + "icon_id": "23384232", + "name": "欢迎_icon", + "font_class": "huanying_icon", + "unicode": "e878", + "unicode_decimal": 59512 + }, + { + "icon_id": "23384233", + "name": "文件夹", + "font_class": "wenjianjia2", + "unicode": "e879", + "unicode_decimal": 59513 + }, + { + "icon_id": "23384234", + "name": "删除icon", + "font_class": "shanchuicon1", + "unicode": "e87a", + "unicode_decimal": 59514 + }, + { + "icon_id": "23261798", + "name": "请求icon", + "font_class": "qingqiuicon", + "unicode": "e871", + "unicode_decimal": 59505 + }, + { + "icon_id": "23261799", + "name": "响应icon", + "font_class": "xiangyingicon", + "unicode": "e87c", + "unicode_decimal": 59516 + }, + { + "icon_id": "23144143", + "name": "多选选中", + "font_class": "duoxuanxuanzhong", + "unicode": "e88f", + "unicode_decimal": 59535 + }, + { + "icon_id": "23144144", + "name": "错误icon", + "font_class": "cuowuicon", + "unicode": "e890", + "unicode_decimal": 59536 + }, + { + "icon_id": "23144146", + "name": "成功icon", + "font_class": "chenggongicon", + "unicode": "e892", + "unicode_decimal": 59538 + }, + { + "icon_id": "23144147", + "name": "未选中响应icon", + "font_class": "weixuanzhongxiangyingicon", + "unicode": "e893", + "unicode_decimal": 59539 + }, + { + "icon_id": "23144149", + "name": "必填icon", + "font_class": "bitianicon", + "unicode": "e895", + "unicode_decimal": 59541 + }, + { + "icon_id": "23144151", + "name": "未选中项目标签icon", + "font_class": "weixuanzhongxiangmubiaoqianicon", + "unicode": "e897", + "unicode_decimal": 59543 + }, + { + "icon_id": "23144152", + "name": "列表icon", + "font_class": "liebiaoicon", + "unicode": "e898", + "unicode_decimal": 59544 + }, + { + "icon_id": "23144158", + "name": "协作者管理icon", + "font_class": "xiezuozheguanliicon", + "unicode": "e8a1", + "unicode_decimal": 59553 + }, + { + "icon_id": "23144160", + "name": "选中分支icon", + "font_class": "xuanzhongfenzhiicon", + "unicode": "e8a3", + "unicode_decimal": 59555 + }, + { + "icon_id": "23144162", + "name": "选中基本设置icon", + "font_class": "xuanzhongjibenshezhiicon", + "unicode": "e8a5", + "unicode_decimal": 59557 + }, + { + "icon_id": "23144165", + "name": "选中项目标签icon", + "font_class": "xuanzhongxiangmubiaoqianicon", + "unicode": "e8aa", + "unicode_decimal": 59562 + }, + { + "icon_id": "23144167", + "name": "选中webhook icon", + "font_class": "a-xuanzhongwebhookicon", + "unicode": "e8af", + "unicode_decimal": 59567 + }, + { + "icon_id": "23046290", + "name": "shanchu_tc_icon", + "font_class": "shanchu_tc_icon", + "unicode": "e88c", + "unicode_decimal": 59532 + }, + { + "icon_id": "23046293", + "name": "wiki_icon", + "font_class": "wiki_icon", + "unicode": "e88d", + "unicode_decimal": 59533 + }, + { + "icon_id": "23046244", + "name": "导入模版_icon", + "font_class": "daorumoban_icon", + "unicode": "e86f", + "unicode_decimal": 59503 + }, + { + "icon_id": "23046252", + "name": "错误", + "font_class": "cuowu", + "unicode": "e872", + "unicode_decimal": 59506 + }, + { + "icon_id": "23046255", + "name": "更多_icon", + "font_class": "gengduo_icon", + "unicode": "e874", + "unicode_decimal": 59508 + }, + { + "icon_id": "23046258", + "name": "复层关闭_icon", + "font_class": "fucengguanbi_icon", + "unicode": "e875", + "unicode_decimal": 59509 + }, + { + "icon_id": "23046268", + "name": "删除icon", + "font_class": "shanchuicon", + "unicode": "e877", + "unicode_decimal": 59511 + }, + { + "icon_id": "23046273", + "name": "搜索_删除icon", + "font_class": "sousuo_shanchuicon", + "unicode": "e87b", + "unicode_decimal": 59515 + }, + { + "icon_id": "23046275", + "name": "搜索_icon", + "font_class": "sousuo_icon", + "unicode": "e87d", + "unicode_decimal": 59517 + }, + { + "icon_id": "23046276", + "name": "文档预览_icon", + "font_class": "wendangyulan_icon", + "unicode": "e87e", + "unicode_decimal": 59518 + }, + { + "icon_id": "23046278", + "name": "下拉按钮", + "font_class": "xialaanniu", + "unicode": "e880", + "unicode_decimal": 59520 + }, + { + "icon_id": "22906287", + "name": "二次确认_icon", + "font_class": "erciqueren_icon", + "unicode": "e867", + "unicode_decimal": 59495 + }, + { + "icon_id": "22906288", + "name": "选中ssh_icon", + "font_class": "xuanzhongssh_icon", + "unicode": "e868", + "unicode_decimal": 59496 + }, + { + "icon_id": "22906289", + "name": "未选中安全设置_icon", + "font_class": "weixuanzhonganquanshezhi_icon", + "unicode": "e869", + "unicode_decimal": 59497 + }, + { + "icon_id": "22906290", + "name": "未选中ssh_icon", + "font_class": "weixuanzhongssh_icon", + "unicode": "e86a", + "unicode_decimal": 59498 + }, + { + "icon_id": "22906291", + "name": "选中安全设置_icon", + "font_class": "xuanzhonganquanshezhi_icon", + "unicode": "e86b", + "unicode_decimal": 59499 + }, + { + "icon_id": "22906292", + "name": "删除_icon", + "font_class": "shanchu_icon", + "unicode": "e86c", + "unicode_decimal": 59500 + }, + { + "icon_id": "22906293", + "name": "列表ssh_icon", + "font_class": "liebiaossh_icon", + "unicode": "e86e", + "unicode_decimal": 59502 + }, + { + "icon_id": "17575494", + "name": "file-submodule", + "font_class": "file-submodule", + "unicode": "e866", + "unicode_decimal": 59494 + }, + { + "icon_id": "7539612", + "name": "nv", + "font_class": "nv1", + "unicode": "e864", + "unicode_decimal": 59492 + }, + { + "icon_id": "7539613", + "name": "nan", + "font_class": "nan1", + "unicode": "e865", + "unicode_decimal": 59493 + }, { "icon_id": "21936935", "name": "邮箱", diff --git a/public/css/iconfont.svg b/public/css/iconfont.svg deleted file mode 100644 index d6d0adbc5..000000000 --- a/public/css/iconfont.svg +++ /dev/null @@ -1,1874 +0,0 @@ - - - - - -Created by iconfont - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/index.html b/public/index.html index f039d86ef..9489fe428 100755 --- a/public/index.html +++ b/public/index.html @@ -1,5 +1,5 @@ - + diff --git a/public/js/editormd/editormd.min.js b/public/js/editormd/editormd.min.js index 0add3b370..860a4de0e 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.css b/src/App.css index 205c64f7d..8d916d390 100644 --- a/src/App.css +++ b/src/App.css @@ -60,12 +60,13 @@ body { .ant-progress-textno { color: #f5222d; } - +.CodeMirror pre.CodeMirror-line{ + font-size: 16px!important; +} /* md多空格 */ .markdown-body p { margin:10px 0px!important; font-size: 16px !important; - line-height: 2 !important; white-space: pre-wrap; } @@ -87,6 +88,10 @@ body { border-left: 1px solid rgb(221, 221, 221); /* 某些情况下,被cm盖住了 */ z-index: 99; + padding:8px 8px 50px; +} +.editormd-preview .markdown-body{ + padding:0px !important; } /* 图片点击放大的场景,隐藏图片链接 */ diff --git a/src/App.js b/src/App.js index 6c3382455..8e6a9af24 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'; @@ -17,10 +17,9 @@ import marked from './common/marked'; import moment from 'moment' import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles'; +import SiderBar from './forge/Component/SiderBar' -import history from './history'; - -import { SnackbarHOC } from 'educoder' +import { SnackbarHOC } from 'educoder'; import { initAxiosInterceptors } from './AppConfig' import { Provider } from 'react-redux'; import configureStore from './redux/stores/configureStore'; @@ -40,6 +39,16 @@ 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'), + loading: Loading, +}) //forge项目-devOps详情 const OpsDetail = Loadable({ loader: () => import('./forge/DevOps/opsDetail'), @@ -74,6 +83,27 @@ const EducoderLogin = Loadable({ loader: () => import('./modules/login/EducoderLogin'), loading: Loading, }) +const Search = Loadable({ + loader: () => import('./modules/search/'), + loading: Loading, +}) +const WikiPreview = Loadable({ + loader: () => import('./forge/Wiki/Preview'), + loading: Loading, +}) + +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) { @@ -84,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, + }); } } @@ -100,43 +175,22 @@ class App extends Component { Addcoursestypes: false }) }; - ModalCancelsy = () => { - this.setState({ - mydisplay: false, - }) - window.location.href = "/"; - }; - ModalshowCancelsy = () => { - this.setState({ - mydisplay: true, - }) - }; - disableVideoContextMenu = () => { - window.$("body").on("mousedown", "video", function (event) { - if (event.which === 3) { - window.$('video').bind('contextmenu', function () { return false; }); - } else { - window.$('video').unbind('contextmenu'); - } - }); - } componentDidMount() { document.title = "loading..."; - this.disableVideoContextMenu(); - history.listen(() => { - this.forceUpdate() - const $ = window.$ - $("html").animate({ scrollTop: $('html').scrollTop() - 0 }) - }); - initAxiosInterceptors(this.props); this.getAppdata(); window.addEventListener('error', (event) => { const msg = `${event.type}: ${event.message}`; }); + } + + componentWillUnmount() { + this.unlisten && this.unlisten(); // 执行解绑 + } + //修改登录方法 Modifyloginvalue = () => { this.setState({ @@ -207,69 +261,139 @@ class App extends Component { }; render() { + const { mygetHelmetapi, pathType} = this.state; + let personal = mygetHelmetapi && mygetHelmetapi.personal; return ( this.Modifyloginvalue()}> - - - {/*项目*/} - { - return () - } - }> - - {/*项目*/} - { - return () - } - }> - - { - return () - } - } - /> - {/*403*/} - + + {/* */} + + {/* wiki预览 */} + { + return () + } + } /> - - { - return () - } - }> - - {/*404*/} - - {/* 个人主页 */} - { - return () - } - }> - ( - - ) + {/* 项目PR */} + () + } + > + + {/*项目*/} + { + return () } - /> - - - + }> + + { + return () + } + }> + + + { + 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 034612ece..ea85a4e52 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/Loading.js b/src/Loading.js index f99057471..8175b7df8 100644 --- a/src/Loading.js +++ b/src/Loading.js @@ -9,20 +9,7 @@ class Loading extends Component { } render() { - return ( -
- - -
- ); + return "" } } diff --git a/src/college/College.js b/src/college/College.js index 85d43fb7e..f7a3ab6c7 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/college/colleagecss/colleage.css b/src/college/colleagecss/colleage.css index 9220b8acc..65f32322a 100644 --- a/src/college/colleagecss/colleage.css +++ b/src/college/colleagecss/colleage.css @@ -218,7 +218,7 @@ a:hover { } .color-blue { - color: #4CACFF; + color: #2A61FF; } .color-huang { diff --git a/src/common/DateUtil.js b/src/common/DateUtil.js index 859182e18..8846d274c 100644 --- a/src/common/DateUtil.js +++ b/src/common/DateUtil.js @@ -1,4 +1,5 @@ import moment from "moment"; +import { number } from "prop-types"; // 处理整点 半点 // 取传入时间往后的第一个半点 @@ -97,3 +98,41 @@ export function formatDuring(mss){ } return days + "天" + hours + "小时" + minutes + "分"; } + +/* + 返回:多久以前 + backDate:以前的某个日期 +*/ +export function timeAgo(backDate) { + try { + moment(backDate); + } catch (e) { + return '刚刚'; + } + if(typeof backDate ==='number'){ + backDate=backDate*1000 + }else{ + backDate= moment(backDate); + } + let time = new Date() - backDate; + var days = Math.floor(time / (1000 * 60 * 60 * 24)); + var hours = Math.floor((time % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + var minutes = Math.floor((time % (1000 * 60 * 60)) / (1000 * 60)); + var seconds = Math.floor((time % (1000 * 60 * 60)) / 1000); + if (time <= 0) { + return "刚刚"; + } + if (days) { + return days + "天前"; + } + if (hours) { + return hours + "小时前"; + } + if (minutes) { + return minutes + "分前"; + } + if (seconds) { + return seconds + "秒前"; + } + return "刚刚"; +} \ No newline at end of file diff --git a/src/common/TextUtil.js b/src/common/TextUtil.js index 94e736314..d1aa0e9cd 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/common/UrlTool.js b/src/common/UrlTool.js index 6ccea6a92..f1800a75d 100644 --- a/src/common/UrlTool.js +++ b/src/common/UrlTool.js @@ -18,6 +18,23 @@ export function getImageUrl(path) { return `${path}`; } +export function numFormat(num, digits){ + let d = digits || 1; + var si = [ + { value: 1, symbol: "" }, + { value: 1E3, symbol: "k" }, + { value: 1E4, symbol: "W" } + ]; + var rx = /\.0+$|(\.[0-9]*[1-9])0+$/; + var i; + for (i = si.length - 1; i > 0; i--) { + if (num >= si[i].value) { + break; + } + } + return (num / si[i].value).toFixed(d).replace(rx, "$1") + si[i].symbol; +} + export function getImage(path) { // https://www.educoder.net // https://testbdweb.trustie.net @@ -162,28 +179,28 @@ export function getmyUrl(geturl) { } export function getUploadActionUrl(path, goTest) { - return `${getUrl()}/api/attachments.json?debug=${window._debugType || 'admin'}`; + return `${getUrl()}/api/attachments.json${isDev ?`${isDev ?`?debug=${window._debugType || 'admin'}` : ""}` : ""}`; } export function getUploadLogoActionUrl() { - return `${getUrl()}/api/resumes/logo.json?debug=${window._debugType || 'admin'}`; + return `${getUrl()}/api/resumes/logo.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`; } export function getUploadActionUrltwo(id) { - return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json?debug=${window._debugType || 'admin'}` + return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}` } export function getUploadActionUrlthree() { - return `${getUrlmys()}/api/jupyters/import_with_tpm.json?debug=${window._debugType || 'admin'}` + return `${getUrlmys()}/api/jupyters/import_with_tpm.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}` } export function getupload_git_file(id) { - return `${getUrlmys()}/api/shixuns/${id}/upload_git_file.json?debug=${window._debugType || 'admin'}` + return `${getUrlmys()}/api/shixuns/${id}/upload_git_file.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}` } export function getUploadActionUrlOfAuth(id) { - return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json?debug=${window._debugType || 'admin'}` + return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}` } export function getRandomNumber(type) { diff --git a/src/common/educoder.js b/src/common/educoder.js index 1fc868930..1a063d823 100644 --- a/src/common/educoder.js +++ b/src/common/educoder.js @@ -3,7 +3,7 @@ // export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil'; export { - getUploadLogoActionUrl as getUploadLogoActionUrl, + getUploadLogoActionUrl as getUploadLogoActionUrl,numFormat as numFormat, getImageUrl as getImageUrl,getImage as getImage, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl , getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth , getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode, getupload_git_file as getupload_git_file, getcdnImageUrl as getcdnImageUrl @@ -27,7 +27,7 @@ export { markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension, downloadFile, sortDirections, validateLength, mdJSONParse, exportMdtoHtml } from './TextUtil' -export { handleDateString, getNextHalfHourOfMoment, formatDuring, formatSeconds } from './DateUtil' +export { handleDateString, getNextHalfHourOfMoment, formatDuring, formatSeconds ,timeAgo} from './DateUtil' export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil' diff --git a/src/components/render-html.jsx b/src/components/render-html.jsx index 3601ea323..b24fc092a 100644 --- a/src/components/render-html.jsx +++ b/src/components/render-html.jsx @@ -46,18 +46,18 @@ export default ({ let id = decodeURIComponent(u.split("#")[1]); let ele = document.getElementById(id); if(ele){ - window.scrollTo(0, ele.offsetTop + 220); + window.scrollTo(0, ele.offsetTop + 120); } } } - },[url]) + },[url,html]) const el = useRef(); function onAncherHandler(e) { - let target = e.target + let target = e.target; if (target.tagName.toUpperCase() === 'A') { - let ancher = target.getAttribute('href') - if (ancher.startsWith('#')) { + let ancher = target.getAttribute('href'); + if (ancher && ancher.startsWith('#')) { e.preventDefault() let viewEl = document.getElementById(ancher.replace('#', '')) if (viewEl) { diff --git a/src/context/TPIContextProvider.js b/src/context/TPIContextProvider.js index 22b247272..f3ea3e0fd 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 163495bdb..4a7a1d345 100644 --- a/src/forge/Activity/Activity.js +++ b/src/forge/Activity/Activity.js @@ -1,7 +1,7 @@ import React , { Component } from 'react'; import { Dropdown , Menu , Icon , Pagination , Spin } from 'antd'; import '../css/index.scss'; -import '../Branch/branch.css'; +import '../Branch/branch.scss'; import './activity.css'; import NoneData from '../Nodata'; @@ -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 b726a4af0..48a72e797 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 89cd3f4e0..c2e6dd746 100644 --- a/src/forge/Branch/CloneAddress.js +++ b/src/forge/Branch/CloneAddress.js @@ -1,39 +1,27 @@ -import React, { Component } from 'react'; -import { Dropdown, Icon, Tooltip } from 'antd'; -import "./branch.css"; +import React, { useState } from 'react'; +import { Menu } from 'antd'; +import "./branch.scss"; +import CopyTool from '../Component/CopyTool'; -class CloneAddress extends Component { - // 点击按钮复制功能 - jsCopy = () => { - var e = document.getElementById("copy_rep_content"); - e.select(); - document.execCommand("Copy"); - } - - render() { - const { http_url, downloadUrl } = this.props; - return ( -

- {/*

版本库地址已变更,请基于新地址提交代码

*/} - { - http_url && HTTP - } - - - this.jsCopy()}> - - { - downloadUrl && - - -
- - - - - } +function CloneAddress({http_url , ssh_url , zip_url , tar_url}) { + const [ key , setKey ] = useState("HTTP"); + return ( +
+
+ + {setKey(e.key)}}>HTTP + {setKey(e.key)}}>SSH + +
+ + +
- ) - } + + 下载 ZIP + 下载 TAR.GZ + +
+ ) } export default CloneAddress; \ No newline at end of file diff --git a/src/forge/Branch/Select.jsx b/src/forge/Branch/Select.jsx index 0f0b0de40..ff3dd829e 100644 --- a/src/forge/Branch/Select.jsx +++ b/src/forge/Branch/Select.jsx @@ -1,116 +1,65 @@ -import React , { useState , useEffect } from 'react'; -import { Popover , Input , Spin } from 'antd'; -import './branch.css'; -import { getBranch , getTag } from '../GetData/getData'; - +import React , { useState , useEffect , useRef } from 'react'; +import { Dropdown} from 'antd'; +import './branch.scss'; +import SelectOverlay from './SelectOverlay'; +import { findDOMNode } from 'react-dom'; export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true })=>{ const [ showValue , setShowValue ] = useState(branch); - const [ inputValue , setInputValue] = useState(undefined); - const [ nav , setNav ] = useState(0); - const [ isSpin , setIsSpin ] = useState(true); - const [ flag , setFlag ] = useState(false); + const [ visible , setVisible ] = useState(false); - const [ data , setData ] = useState(undefined); - const [ datas , setDatas ] = useState(undefined); + 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]) - useEffect(()=>{ - document.body.addEventListener('click', e => { - let name = e.target.className; - let turn = name === "ant-input OptionsInput" || name === "navli active"|| name === "navli" || name === "padding10 bor-bottom-greyE"; - if(turn){ - return; - }else{ - setFlag(false); - } - }) - }) - - useEffect(()=>{ - if(branchList){ - setData(branchList); - setDatas(branchList); - setIsSpin(false); - } - },[branchList]) - - - async function getBranchs(id,owner){ - let result = await getBranch(id,owner); - setData(result); - setDatas(result); - setIsSpin(false); + function ChangeB(params) { + setVisible(false); + changeBranch(params); } - async function getTags(id,owner){ - let result = await getTag(id,owner); - setData(result); - setDatas(result); - setIsSpin(false); - } - - function changeInputValue(e){ - setInputValue(e.target.value); - let filter = e.target.value ? data && data.length>0 && data.filter(item=>item.name.indexOf(e.target.value)>-1) : data; - setDatas(filter); - } - - function changeNav(nav){ - setNav(nav); - setIsSpin(true); - if(nav === 0){ - getBranchs(projectsId,owner); - }else{ - getTags(projectsId,owner); - } - } - function chooseitem(value){ - // setShowValue(value); - changeBranch(value); - } - const menu = ( -
-
- -
    -
  • changeNav(0)}>分支列表
  • - { tagflag &&
  • changeNav(1)}>标签列表
  • } -
-
- -
    - { - datas && datas.length>0 ? - datas.map((item,key)=>{ - return( -
  • chooseitem(item.name)}>{item.name}
  • - ) - }): -

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

    - } -
-
+
+
); return( - setFlag(!flag)} overlayClassName="branch-tagBox-list"> -
+ +
setVisible(visible ? false : true)}> {/* {nav === 0 ?"分支":"标签"} */} - + {showValue} - - + +
- +
) }) \ No newline at end of file diff --git a/src/forge/Branch/SelectOverlay.jsx b/src/forge/Branch/SelectOverlay.jsx new file mode 100644 index 000000000..0be567324 --- /dev/null +++ b/src/forge/Branch/SelectOverlay.jsx @@ -0,0 +1,90 @@ +import React , { useState , useEffect } from 'react'; +import { Input , Spin , Menu } from 'antd'; +import { getBranch , getTag } from '../GetData/getData'; + +function SelectOverlay({ changeBranch , tagflag , projectsId , owner , visible }) { + const [ inputValue , setInputValue] = useState(undefined); + const [ nav , setNav ] = useState(0); + const [ isSpin , setIsSpin ] = useState(true); + + const [ data , setData ] = useState(undefined); + const [ datas , setDatas ] = useState(undefined); + const [ keys ,setKeys] = useState("branch"); + + useEffect(()=>{ + if(visible){ + setKeys("branch"); + getBranchs(projectsId,owner); + setIsSpin(true); + } + },[visible]) + + async function getBranchs(id,owner){ + let result = await getBranch(id,owner); + setData(result); + setDatas(result); + setIsSpin(false); + } + async function getTags(id,owner){ + let result = await getTag(id,owner); + setData(result); + setDatas(result); + setIsSpin(false); + } + function chooseitem(value){ + changeBranch(value); + } + function changeInputValue(e){ + setInputValue(e.target.value); + let filter = e.target.value ? data && data.length>0 && data.filter(item=>item.name.indexOf(e.target.value)>-1) : data; + setDatas(filter); + } + + function changeNav(e){ + setKeys(e.key); + setIsSpin(true); + if(e.key === "branch"){ + getBranchs(projectsId,owner); + setNav(0); + }else{ + getTags(projectsId,owner); + setNav(1); + } + } + + return( +
+
+ } + placeholder={`请输入分支${tagflag ? "或标签" :""}名称搜索`} + autocomplete="off" className="OptionsInput" + value={inputValue} + onChange={changeInputValue} + /> +
+ + 分支 + { tagflag && 标签 } + + +
    + { + datas && datas.length>0 && + datas.map((item,key)=>{ + return( +
  • chooseitem(item.name)}>{item.name}
  • + ) + }) + + } + { + datas && datas.length === 0 && +

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

    + } +
+
+
+ ) +} +export default SelectOverlay; \ No newline at end of file diff --git a/src/forge/Branch/branch.css b/src/forge/Branch/branch.css deleted file mode 100644 index 962b01970..000000000 --- a/src/forge/Branch/branch.css +++ /dev/null @@ -1,84 +0,0 @@ -.branchDropdown{ - border:1px solid #eee; - border-radius: 4px; - display: flex; - justify-content: center; - height: 40px; - line-height: 40px; - min-width: 220px; -} -.branchDropdown .ant-dropdown-trigger{ - width: 100%; - padding:0px 15px; - display: flex; - justify-content: space-between; - align-items: center; - cursor: pointer; -} -.branchOptions{ - width: 220px; - box-shadow: 0px 0px 3px 1px rgba(134, 134, 134, 0.4); - border-radius: 3px; - background: #fff; - max-height: 300px; -} -.OptionsUl{ - max-height: 220px; - overflow-y: auto; -} -.OptionsUl li{ - height: 35px; - line-height: 35px; - cursor: pointer; - padding:0px 10px; -} -.OptionsUl li:hover{ - background-color: #F0F0F0; -} -.OptionsUl li a{ - display: block; -} -.OptionsInput{ - height: 32px; - padding-left: 4px; - line-height: 32px; - width: 100%; -} -.branch-tagBox{ - border:1px solid #eee; - border-radius: 3px; - height: 40px; - display: flex; - align-items: center; - cursor: pointer; - min-width: 140px; -} -.branch-tagBox-list .ant-popover-arrow{ - display: none; -} -.branch-tagBox-list.ant-popover.ant-popover-placement-bottom{ - padding-top:0px; -} -.branch-tagBox .ant-dropdown-link{ - display: block; - flex:1; -} -.branch-tagBox-list .ant-popover-inner-content{ - padding:0px; -} -.navUl{ - display: flex; - justify-content: space-between; - align-items: center; - margin-top: 5px; -} -.navUl li{ - cursor: pointer; -} -.navUl li.active{ - color:#5091FF; -} -.listTips{ - padding:20px 0px; - text-align: center; -} \ No newline at end of file diff --git a/src/forge/Branch/branch.scss b/src/forge/Branch/branch.scss new file mode 100644 index 000000000..030b05cd1 --- /dev/null +++ b/src/forge/Branch/branch.scss @@ -0,0 +1,129 @@ +.branchDropdown{ + border:1px solid #eee; + border-radius: 4px; + display: flex; + justify-content: center; + height: 40px; + line-height: 40px; + min-width: 220px; +} +.branchDropdown .ant-dropdown-trigger{ + width: 100%; + padding:0px 15px; + display: flex; + justify-content: space-between; + align-items: center; + cursor: pointer; +} +.branchOptions{ + width: 220px; + box-shadow: 0px 0px 3px 1px rgba(134, 134, 134, 0.4); + border-radius: 3px; + background: #fff; + max-height: 300px; +} +.OptionsUl{ + min-height: 50px; + max-height: 220px; + overflow-y: auto; +} +.OptionsUl li{ + height: 30px; + line-height: 30px; + cursor: pointer; + padding:0px 20px; + margin:5px 0px; +} +.OptionsUl li:hover{ + background-color: #F0F0F0; +} +.OptionsUl li a{ + display: block; +} +.OptionsInput{ + height: 32px; + padding-left: 4px; + line-height: 32px; + width: 100%; +} +.branch-tagBox{ + border:1px solid #D0D0D0; + border-radius: 3px; + height: 32px; + display: flex; + align-items: center; + cursor: pointer; + min-width: 104px; +} +.branch-tagBox:hover{ + background-color: #F3F4F6; +} +.branch-tagBox-list{ + background: #FFFFFF; + box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5); + border-radius: 4px; + .ant-popover-arrow{ + display: none; + } + &.ant-popover.ant-popover-placement-bottom{ + padding-top:0px; + } + .branch-tagBox .ant-dropdown-link{ + display: block; + flex:1; + max-width: 105px; + } + .ant-popover-inner-content{ + padding:0px; + } +} +.overlayBranch{ + width: 325px; + .navUl{ + margin-top: 8px; + height: 30px; + line-height: 30px; + li{ + height: 30px; + 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 ; + } + } + } +} +.listTips{ + padding:20px 0px; + text-align: center; +} + +.urlMenu{ + line-height: 30px; + margin-bottom: 10px; + padding:15px 20px 0px 20px; + border-bottom: none; + li.ant-menu-item{ + height: 30px; + line-height: 30px; + padding:0px 5px; + margin-right: 20px!important; + &.ant-menu-item-selected,&.ant-menu-item-active{ + color: #333; + } + &.ant-menu-item-selected{ + 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 656175d5f..feff6f372 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/AddMember.jsx b/src/forge/Component/AddMember.jsx index f1c14f07f..f927850c8 100644 --- a/src/forge/Component/AddMember.jsx +++ b/src/forge/Component/AddMember.jsx @@ -4,7 +4,7 @@ import axios from 'axios'; import { getImageUrl } from 'educoder'; const { Option } = AutoComplete; -function AddMember({getID,login}){ +function AddMember({getID,login,showNotification}){ const [ id , setID ] = useState(undefined); const [ source , setSource ] = useState(undefined); const [ searchKey , setSearchKey ] = useState(undefined); @@ -66,8 +66,12 @@ function AddMember({getID,login}){ }; function addCollaborator(){ - getID && getID(id); - setSearchKey(undefined); + if(source && source.length>0){ + getID && getID(id); + setSearchKey(undefined); + }else{ + showNotification("请选择存在的用户!"); + } } return( diff --git a/src/forge/Component/Cards.jsx b/src/forge/Component/Cards.jsx index 498b375c1..f9a3d52e9 100644 --- a/src/forge/Component/Cards.jsx +++ b/src/forge/Component/Cards.jsx @@ -3,7 +3,7 @@ import { getImageUrl } from 'educoder'; import { Link } from 'react-router-dom'; import './Component.scss'; -function Cards({img , title, desc , rightBtn , src}){ +function Cards({img , title, desc , rightBtn , src , bottomInfos}){ return(
{img &&
} @@ -15,6 +15,7 @@ function Cards({img , title, desc , rightBtn , src}){
{desc}
+ {bottomInfos}
) diff --git a/src/forge/Component/Component.scss b/src/forge/Component/Component.scss index 46aa8fcce..30a62005c 100644 --- a/src/forge/Component/Component.scss +++ b/src/forge/Component/Component.scss @@ -112,6 +112,16 @@ li.ant-menu-item{ right:240px; z-index: 10000; } +.laterest{ + background-color: #EF3131; + color: #fff; + font-size: 12px; + margin-left: 10px; + padding:0px 5px; + border-radius: 2px; + height: 18px; + line-height: 18px; +} @media screen and (max-width: 1800px){ .handleBox{ @@ -152,41 +162,280 @@ li.ant-menu-item{ margin:0px 20px!important; } } - +.hoverA{ + display:flex; + align-items: center; + max-width: 78px; + &:hover a{ + color:#2A61FF !important ; + } +} .menuPanels{ - width: 240px; - height: 180px; + width: 295px; + .leftline{ + position: relative; + color: #666; + height: 16px; + margin-left: 14px; + font-size: 12px; + &::before{ + position: absolute; + left: -7px; + top:3px; + height: 12px; + width: 1px; + background-color: #999; + content: ""; + } + } + .ant-btn{ + height: 36px; + line-height: 34px; + width: 83px; + text-align: center; + padding:0px ; + font-weight: 500; + font-size: 14px; + &.currentBtn{ + cursor: default; + color: #333; + &:hover{ + color: #333; + border-color: #d0d0d0; + } + } + } + .ant-btn-default{ + color: #333; + border-color: #d0d0d0; + &:hover{ + background: #F3F4F6; + } + } + .ant-btn{ + width: 102px; + height: 32px; + line-height: 30px; + } + .ant-btn-primary{ + color: #fff; + background-color: #466AFF; + border:none; + &:hover{ + background-color: rgba(70,106,255,0.85); + } + } + .focusPanelHeadInfo{ + padding:14px 16px; + border-bottom: 1px solid #eee; + } .ant-popover-content,.ant-popover-inner{ height: 100%; width: 100%; } + .ant-popover-inner-content{ + padding:0px; + } } .halfs{ margin-top: 24px; padding:24px 0px 0px 0px; border-top: 1px solid #e8e8e8; - .attrPerson{ - padding-bottom: 24px; - } +} +.aboutSubTitle{ + display: flex; + align-items: center; +} +.menuMaininfos{ + padding:10px 16px 14px; + border-bottom: 1px solid #eee; } .menuinfos{ - padding:15px 0px; + padding:10px 20px 16px; &>a{ display: flex; flex-direction: column; align-items: center; - border-right: 1px solid #eee; flex: 1; & >span:first-child{ - font-size: 18px; - font-weight: 400; + font-size: 16px; + font-weight: 500; color: #333; + line-height: 22px; } & >span:last-child{ color: #666; - } - &:last-child{ - border-right: none; + font-weight: 400; + line-height: 20px; + margin-top: 6px; } } -} \ No newline at end of file +} + +/*-------------------个人主页:右侧提示区域--------------------------*/ +.-task-sidebar { + position: fixed; + width: 40px; + right: 0; + bottom: 80px; + z-index: 10; +} + +@media screen and (max-width: 1920px){ + .-task-sidebar{ + right:220px; + } +} +@media screen and (max-width: 1750px){ + .-task-sidebar{ + right:160px; + } +} +@media screen and (max-width: 1650px){ + .-task-sidebar{ + right:115px; + } +} +@media screen and (max-width: 1550px){ + .-task-sidebar{ + right:90px; + } +} +@media screen and (max-width: 1450px){ + .-task-sidebar{ + right:45px; + } +} +@media screen and (max-width: 1200px){ + .-task-sidebar{ + right:0px; + display: none; + } +} +.-task-sidebar>div { + height: 40px; + line-height: 40px; + box-sizing: border-box; + width: 40px; + color: #999; + font-size: 20px; + text-align: center; + margin-bottom: 20px; + border-radius: 50%; + background: #FFFFFF; + box-shadow: 0px 0px 10px 1px #F1F1F1; +} + +.-task-sidebar>div i { + color: #999; +} + +.-task-sidebar>div:hover i { + color: #fff !important; +} +.-task-sidebar>div:hover{ + background: #1890FF; + box-shadow: 0px 0px 10px 2px #B6D0FC; +} +.helpBox{ + width: 260px; + z-index: 103; + &.shareContent{ + width: 200px; + } + .ant-popover-inner-content{ + padding:0px; + } + p.titlecontent{ + font-size: 18px; + color: #333; + line-height: 20px; + padding:15px 20px; + } + .faqUl{ + padding:0px 20px 10px; + max-height: 230px; + overflow-y: auto; + li{ + background: #F5F5F5; + border-radius: 20px; + padding:0px 20px; + color: #333; + height: 34px; + line-height: 34px; + margin-bottom: 10px; + a{ + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + &:hover{ + background-color: #D1E9FF; + a{ + color: #333!important; + } + } + } + } + .shareUl{ + padding:10px 0px; + display: flex; + align-items: center; + .titlecontent{ + margin-right: 20px; + } + li > i{ + font-size: 32px!important; + } + } +} + + + +.-task-desc { + background: #494949; + width: 90px; + line-height: 36px; + text-align: center; + position: absolute; + color: #fff; + font-size: 13px; + z-index: 999999; + opacity: 0; +} + +.-task-desc div { + position: absolute; + top: 10px; + right: -7px; + height: 13px; +} + +.-task-desc div img { + float: left +} + +.-task-sidebar .scan_ewm { + position: absolute !important; + right: 45px !important; + bottom: 0px !important; + background-color: #494949 !important; + -webkit-box-sizing: border-box !important; + box-sizing: border-box !important; + font-size: 14px !important; + line-height: 16px !important; + display: none; + height: 213px !important; +} + +.trangle_right { + position: absolute; + right: -5px; + bottom: 15px; + width: 0; + height: 0px; + border-top: 6px solid transparent; + border-left: 5px solid #494949; + border-bottom: 6px solid transparent +} diff --git a/src/forge/Component/Contributors.jsx b/src/forge/Component/Contributors.jsx index 1e26354a5..e88acc056 100644 --- a/src/forge/Component/Contributors.jsx +++ b/src/forge/Component/Contributors.jsx @@ -1,13 +1,13 @@ import React, { useEffect, useState } from 'react'; import { AlignCenter , FlexAJ } from '../Component/layout'; import { Link } from 'react-router-dom'; -import { Popover , Spin } from 'antd'; +import { Popover , Spin , Button } from 'antd'; import { getImageUrl } from 'educoder'; import './Component.scss'; import { getUser } from '../GetData/getData'; import axios from 'axios'; -function Contributors({contributors,owner,projectsId}){ +function Contributors({contributors,owner,projectsId,currentLogin}){ const [ menuList ,setMenuList ]= useState([]); const [ list , setList ]= useState(undefined); const [ total , setTotal ]= useState(0); @@ -46,46 +46,60 @@ function Contributors({contributors,owner,projectsId}){ } } + 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.is_watch ? FocusFunc(false,data.login)}>取消关注:FocusFunc(true,data.login)}>关注 - } - - - - {data.projects_count} - 项目数 - - - {data.followers_count} - 粉丝数 - - - {data.following_count} - 关注数 - - - { - data.organizations && data.organizations.length > 0 ? - - 所属组织: -
- {renderArray(data.organizations)} + + +
+ {data.name} + { data.location && {data.location} } + { + data.organizations && data.organizations.length>0&& +

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

+ }
- :"" - } - { - data.location && 所在地址:{data.location} - } + + + + {data.projects_count} + 项目数 + + + {data.followers_count} + 粉丝数 + + + {data.following_count} + 关注数 + + +
+ { + currentLogin && (currentLogin === data.login) + ? + + : + data.is_watch ? + + : + + } +
) setMenu(ele); @@ -135,17 +149,17 @@ function Contributors({contributors,owner,projectsId}){ return(
- - 贡献者{ contributors && contributors.total_count > 0 && {contributors.total_count}} - 全部 - + + 贡献者 + { contributors && contributors.total_count > 0 && {contributors.total_count}} +
setVisibleFunc(false)}> { total > 0 ? 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 000000000..36ed1d8c1 --- /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 new file mode 100644 index 000000000..c3c136899 --- /dev/null +++ b/src/forge/Component/DeleteModal/Index.jsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { AlignCenter } from '../layout'; +import { Button } from 'antd'; +import Modals from '../PublicModal/Index'; + +function DeleteBox({ + visible , + onCancel , + onSuccess , + title , + subTitle, + content +}) { + return( + + + +
+ } + onCancel={onCancel} + visible={visible} + > +
+ {content} +

{subTitle}

+
+ + ) +} +export default DeleteBox; \ No newline at end of file diff --git a/src/forge/Component/DrawerPanel.jsx b/src/forge/Component/DrawerPanel.jsx index 8070f3fa3..fa99e6c6f 100644 --- a/src/forge/Component/DrawerPanel.jsx +++ b/src/forge/Component/DrawerPanel.jsx @@ -4,6 +4,12 @@ import './Component.scss'; import axios from 'axios'; const { TreeNode , DirectoryTree } = Tree; +function turnbar(str){ + if(str && str.length>0 && str.indexOf("/")>-1){ + return str.replaceAll('/','%2F'); + } + return str; +} function DrawerPanel({visible,onClose,branch,owner,projectsId,history, name , list}){ const [ treeData , setTreeData ] = useState(undefined); const [ isSpin , setIsSpin ] = useState(true); @@ -71,7 +77,8 @@ function DrawerPanel({visible,onClose,branch,owner,projectsId,history, name , li let dataref = event.node.props.dataRef; if(dataref.type==="file"){ onClose(); - history.push(`/projects/${owner}/${projectsId}/tree/${branch}/${dataref.path}`); + let value = turnbar(branch); + history.push(`/${owner}/${projectsId}/tree/${value}/${dataref.path}`); } } diff --git a/src/forge/Component/EAccount.scss b/src/forge/Component/EAccount.scss new file mode 100644 index 000000000..6fe44ab3a --- /dev/null +++ b/src/forge/Component/EAccount.scss @@ -0,0 +1,6 @@ +.ant-modal-mask{ + z-index: 1031; +} +.ant-modal-wrap{ + z-index: 1032; +} \ No newline at end of file diff --git a/src/forge/Component/EducoderAccount.jsx b/src/forge/Component/EducoderAccount.jsx new file mode 100644 index 000000000..51fe0ded5 --- /dev/null +++ b/src/forge/Component/EducoderAccount.jsx @@ -0,0 +1,60 @@ +import React , {forwardRef, useEffect} from 'react'; +import { Modal , Form , Input , Button } from 'antd'; +import './EAccount.scss'; + +function EducoderAccount({form , visible , onOk , email}){ + const { getFieldDecorator, validateFields , setFieldsValue } = form; + + useEffect(()=>{ + if(email){ + setFieldsValue({email}) + } + },[email]) + + function onSure(){ + validateFields((error,values)=>{ + if(!error){ + onOk(values); + } + }) + } + const layout = { + labelCol: { span: 5 }, + wrapperCol: { span: 18 }, + }; + return( + 确定 + } + centered + > +
+

+ 为确保您能正常使用平台功能,请确认以下信息: +

+
+ + {getFieldDecorator("email",{ + rules:[{required:true,message:"请输入邮箱账号"}] + })( + + )} + + + {getFieldDecorator("password",{ + rules:[{required:true,message:"请输入邮箱密码"}] + })( + + )} + +
+
+
+ ) +} +export default Form.create()(forwardRef(EducoderAccount)); \ No newline at end of file diff --git a/src/forge/Component/HeadSearch.jsx b/src/forge/Component/HeadSearch.jsx new file mode 100644 index 000000000..fb7c9f25a --- /dev/null +++ b/src/forge/Component/HeadSearch.jsx @@ -0,0 +1,41 @@ +import React, { useState } from "react"; +import { Input ,notification} from "antd"; + +const { Search } = Input; +export default ({history}) => { + const [openSearch, setOpenSearch] = useState(false); + + function onGlobalSearch(value) { + history.push('/search?value=' + value); + // window.location.href = `search?value=` + value; + // history.push({ + // pathname:'/search', + // state:value + // }) + } + return ( + + { + openSearch ? +
{ + setTimeout(() => { + setOpenSearch(false) + }, 500) + }} + > + +
+ : + { + setOpenSearch(true) + }} /> + } +
+ ) +}; diff --git a/src/forge/Component/LanguagePower.jsx b/src/forge/Component/LanguagePower.jsx index 3197309c4..8d3e361b5 100644 --- a/src/forge/Component/LanguagePower.jsx +++ b/src/forge/Component/LanguagePower.jsx @@ -25,7 +25,7 @@ function LanguagePower({languages}){ } return(
-

开发语言

+

开发语言

{ array && array.map((item,key)=>{ diff --git a/src/forge/Component/MemberCards.jsx b/src/forge/Component/MemberCards.jsx index 393ddbb17..48d90e136 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 000000000..8fee2c73e --- /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/Component/ModalFun/index.scss b/src/forge/Component/ModalFun/index.scss new file mode 100644 index 000000000..24f7b0219 --- /dev/null +++ b/src/forge/Component/ModalFun/index.scss @@ -0,0 +1,63 @@ +.myself-modal { + .ant-modal-header { + padding: 9px 24px; + background: #f8f8f8; + border-bottom: 1px solid #eee; + } + .ant-modal-title { + text-align: left; + } + .ant-modal-close { + top: 0px !important; + } + .ant-modal-close-x { + font-size: 24px; + } + .ant-modal-body { + text-align: center; + } + .content-title { + display: flex; + justify-content: center; + align-items: center; + margin: 2rem 0 1rem !important; + font-size: 16px; + color: #333; + letter-spacing: 0; + line-height: 29px; + font-weight: 400; + } + .red-circle { + align-self: flex-start; + color: #ca0002; + font-size: 1.5rem !important; + } + .content-descibe { + font-size: 14px; + color: #666; + line-height: 33px; + font-weight: 400; + } + .ant-modal-footer { + padding: 2rem 0; + text-align: center; + border: 0; + .ant-btn { + width: 6rem; + } + } + .foot-submit { + margin-left: 3rem; + color: #df0002; + &:hover { + 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/Monaco.jsx b/src/forge/Component/Monaco.jsx new file mode 100644 index 000000000..aa70d8031 --- /dev/null +++ b/src/forge/Component/Monaco.jsx @@ -0,0 +1,62 @@ +import React, {useEffect, useRef, useState} from 'react'; +import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'; +import './Component.scss'; + +function Monaco(props) { + const { + style = { // dom节点样式 + height: '400px', + }, + value = '', // 代码文本 + onChange = () => { // 改变的事件 + }, + fontSize = 14, // 代码字体大小 + monacoOptions = { + scrollBeyondLastLine: false, + lineNumbers: "off", + wordWrap: true, + overviewRulerBorder: true, + lineHeight: 24, + readOnly:true + }, // monaco 自定义属性 + language = 'html', // 语言 支持 js ts sql css json html等 + } = props; + const editOrRef = useRef(); + const ThisEditor = useRef(); + useEffect(() => { + ThisEditor.current = monaco.editor.create(editOrRef.current, { + value: value || '', + language, + theme: "vs-grey", + fontSize: fontSize + 'px', + minimap: { // 关闭代码缩略图 + enabled: false, + }, + ...monacoOptions, + }); + + ThisEditor.current.onDidChangeModelContent((e) => { + let newValue = ThisEditor.current.getValue(); + onChange(newValue); + }); + return () => { + ThisEditor.current.dispose(); + ThisEditor.current = undefined; // 清除编辑器对象 + } + }, []); + useEffect(() => { + if (ThisEditor.current) { + ThisEditor.current.updateOptions({ + fontSize: fontSize + 'px', + }) + } + }, [fontSize]); + + return ( +
+ +
+ ); +} + +export default Monaco; \ 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 000000000..18e4dcda0 --- /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 000000000..1560c1ffc --- /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 000000000..625b3c311 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 000000000..7cead761b --- /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 000000000..cf13121ed --- /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 000000000..e63c1286d --- /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 000000000..6dbed21fc 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 000000000..c12e12b18 --- /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 000000000..1a0fbf31a --- /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 501c6b632..260e6bd2d 100644 --- a/src/forge/Component/Releases.jsx +++ b/src/forge/Component/Releases.jsx @@ -1,38 +1,35 @@ 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}){ - +function Releases({ owner, projectsId, releaseVersions, distribution }) { return(
- - 发行版 - { releaseVersions && releaseVersions.total_count > 0 && {releaseVersions.total_count}} - - { releaseVersions && releaseVersions.total_count > 0 ? - 全部 - : - 新建 - } - + + 发行版 + { releaseVersions && releaseVersions.total_count > 0 && {releaseVersions.total_count}} + { releaseVersions && releaseVersions.total_count>0 ? releaseVersions.list.map((item,key)=>{ return( key === 0 && -
-

- {item.name} +

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

-

{item.created_at}

+

{item.created_at}

) }) - :"" + : +
+ 您暂未发布任何版本 + {distribution && 创建新版本} +
}
diff --git a/src/forge/Component/SearchUser.jsx b/src/forge/Component/SearchUser.jsx index 0203d24f5..79d23fb65 100644 --- a/src/forge/Component/SearchUser.jsx +++ b/src/forge/Component/SearchUser.jsx @@ -1,45 +1,49 @@ -import React , { useState } from 'react'; +import React , { useState , useEffect } from 'react'; import { AutoComplete } from 'antd'; import { getImageUrl } from "educoder"; import axios from 'axios'; const Option = AutoComplete.Option; -export default ({ getUser })=>{ +export default ({ getUser , placeholder, width ,value })=>{ + const [ source , setSource ] = useState(undefined); const [ searchKey , setSearchKey ] = useState(undefined); - const [ userDataSource , setUserDataSource ] = useState(undefined); + + useEffect(()=>{ + if(!value){ + setSearchKey(undefined); + } + },[value]) + + useEffect(()=>{ + getUserList(); + },[searchKey]) function getUserList(e){ const url = `/users/list.json`; axios.get(url, { params: { - search: e, + search: searchKey, }, - }) - .then((result) => { + }).then((result) => { if (result) { - setUserDataSource(result.data.users); + sourceOptions(result.data.users); } }) .catch((error) => { console.log(error); }); }; - - function changeInputUser(value){ - setSearchKey(value); - getUserList(value); - } - function selectInputUser(id, option){ - setSearchKey(option.props.value); - getUserList(option.props.value); - getUser && getUser(id); - } - const source = - userDataSource && userDataSource.map((item, key) => { + function sourceOptions(userDataSource){ + const s = userDataSource && userDataSource.map((item, key) => { return ( - ); }); + setSource(s); + } + + function changeInputUser(e){ + setSearchKey(e); + }; + + // 选择用户 + function selectInputUser(e, option){ + setSearchKey(option.props.name); + getUser(option.props.login); + }; + return( - +
+ trigger.parentNode} + dataSource={source} + value={searchKey} + style={{ width: width || 300 }} + onChange={changeInputUser} + onSelect={selectInputUser} + placeholder={placeholder || "搜索需要添加的用户..."} + allowClear + /> +
) } \ No newline at end of file diff --git a/src/forge/Component/SiderBar.js b/src/forge/Component/SiderBar.js new file mode 100644 index 000000000..3d6b8acf8 --- /dev/null +++ b/src/forge/Component/SiderBar.js @@ -0,0 +1,91 @@ +import React, { useEffect, useState } from 'react'; +import { Popover , Tooltip } from 'antd'; +import './Component.scss'; +import axios from 'axios'; +import ShareModal from './SiderBarShareModal'; + +const $ = window.$; + +$(window).scroll(function () { + if ($(".gotop").length > 0) { + if ($(document).scrollTop() > 0) { + $(".-task-sidebar .gotop").show(); + $(".gotop").click(function () { + $("html,body").scrollTop(0); + }); + } + if ($(document).scrollTop() === 0) { + $(".-task-sidebar .gotop").hide(); + } + } +}); + +function SiderBar() { + const [ data , setData ] = useState([]); + const [ visible , setVisible ] = useState(false); + + useEffect(()=>{ + getFAQ(); + },[]) + + function getFAQ(){ + const url = `/faqs.json`; + axios.get(url).then(result=>{ + if(result && result.data){ + setData(result.data); + } + }).catch(error=>{}) + } + function content(list){ + return
+

帮助

+
    + { + list && list.map((i,k)=>{ + return( +
  • {i.question}
  • + ) + }) + } +
+
+ } + + function shareContent(){ + return
+
    +

    分享到

    +
  • setVisible(true)}>
  • +
+
+ } + return ( +
+ setVisible(false)}/> + { + data && data.length > 0 && (data[0] && data[0].question) ? + +
+ +
+
+ :"" + } + {/*
+ +
*/} + +
+ +
+
+
+ + + +
+
+ ) +} + +export default SiderBar; diff --git a/src/forge/Component/SiderBarShareModal.jsx b/src/forge/Component/SiderBarShareModal.jsx new file mode 100644 index 000000000..aa8db379e --- /dev/null +++ b/src/forge/Component/SiderBarShareModal.jsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { Modal } from 'antd'; +import QRCode from 'qrcode.react'; + +function SiderBarShareModal({visible,urlValue,onCancel}) { + return( + +
+ {urlValue &&} +

打开微信“扫一扫”,点击右上角菜单,即可将网页分享至朋友圈

+
+
+ ) +} +export default SiderBarShareModal; \ No newline at end of file diff --git a/src/forge/Component/Sort.jsx b/src/forge/Component/Sort.jsx index 58f8a5d2f..a15f04da9 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 8701e607e..0d970173f 100644 --- a/src/forge/Component/User.jsx +++ b/src/forge/Component/User.jsx @@ -1,10 +1,11 @@ import React from 'react'; import styled from 'styled-components'; +import { Link } from 'react-router-dom'; - -export default ({ url , name , column })=>{ +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{ @@ -19,6 +20,14 @@ export default ({ url , name , column })=>{ } `; return( + id? + + + { url && } + {name} + + + : { url && } {name} diff --git a/src/forge/DevOps/About.jsx b/src/forge/DevOps/About.jsx index b9b10dada..31ced2204 100644 --- a/src/forge/DevOps/About.jsx +++ b/src/forge/DevOps/About.jsx @@ -36,8 +36,7 @@ function About(props, ref) { const [ disabled, setDisabled ] = useState(false); const [ typeFlag, setTypeFlag] = useState(false); - - const AuthorLogin = props.author && props.author.login; + const AuthorLogin = props.projectDetail && props.projectDetail.author && props.projectDetail.author.login; const CurrentLogin = props.current_user && props.current_user.login; useEffect(()=>{ if(CurrentLogin === AuthorLogin){ @@ -56,11 +55,6 @@ function About(props, ref) { setIsSpining(false); if(result && result.data ){ setStep(result.data.step); - // setStep(0); - // setFieldsValue({...result.data.cloud_account}); - // if(result.data.cloud_account){ - // setDisabled(true); - // } } }).catch(error=>{ setIsSpining(false); @@ -155,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 2211dbb59..1e08cdab0 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 72a267853..297c5556d 100644 --- a/src/forge/DevOps/Dispose/List.jsx +++ b/src/forge/DevOps/Dispose/List.jsx @@ -10,6 +10,12 @@ import { Link } from 'react-router-dom'; // killed:"已撤销", // pending:"准备中" // } +function turnbar(str){ + if(str && str.length>0 && str.indexOf("/")>-1){ + return str.replaceAll('/','%2F'); + } + return str; +} function renderTableStatus(status) { switch (status) { case "running": @@ -65,8 +71,9 @@ function List({ list, operate , projectsId , owner , showModal , deleteFunc }){ width:"15%", ellipsis:true, render:(value,item)=>{ + let v = turnbar(item.branch); return( - {value} + {value} ) } }, @@ -110,7 +117,7 @@ function List({ list, operate , projectsId , owner , showModal , deleteFunc }){ return( { operate ? - + 编辑 :"" } { operate ? @@ -118,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 3cf7f96ab..63ee54378 100644 --- a/src/forge/DevOps/Dispose/PipelineName.jsx +++ b/src/forge/DevOps/Dispose/PipelineName.jsx @@ -42,7 +42,7 @@ function PipelineName({visible,onCancel,onOk,value ,branchList}){
触发条件: - setBranchValue(e)}> { branchList && branchList.length>0 && branchList.map((item,key)=>{ return( @@ -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 c3a29a3ec..3302f603a 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 b5220138d..99029cdef 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 7cb55276e..6df62dd47 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 933299d6b..204fd161d 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/OpsDetailRightpanel.jsx b/src/forge/DevOps/OpsDetailRightpanel.jsx index 1e0ed86ad..93bf370cb 100644 --- a/src/forge/DevOps/OpsDetailRightpanel.jsx +++ b/src/forge/DevOps/OpsDetailRightpanel.jsx @@ -1,7 +1,8 @@ import React, { useState, useEffect } from "react"; -import { Spin } from "antd"; +import { Spin , Menu } from "antd"; import { FlexAJ, AlignCenter } from "../Component/layout"; import axios from "axios"; +import CodeSSH from './ssh/Index'; export default ({ data, @@ -17,6 +18,8 @@ export default ({ const [spining, setSpining] = useState(true); const [stage, setStage] = useState(undefined); const [step, setStep] = useState(undefined); + const [nav, setNav] = useState("0"); + useEffect(() => { setSpining(rightSpin); }, [rightSpin]); @@ -35,6 +38,7 @@ export default ({ : p[0]; setStep(sub); + setNav("0"); if (sub && sub.status !== "skipped") { getStep(pre.number, sub.number); } @@ -65,43 +69,55 @@ export default ({ } } return ( - -
- {data && data.status !== "error" ? ( -
- - {step && step.name} - - {step && step.duration_time} - - - -
- {coders && coders.length > 0 ? ( - coders.map((item, key) => { - return ( + + {/* {setNav(e.key)}} selectedKeys={[nav]} mode="horizontal"> + 开发流水线 + 命令行 + */} + { + nav === "0" && + +
+ {data && data.status !== "error" ? ( +
+ + {step && step.name} + + {step && step.duration_time} + + + +
+ {coders && coders.length > 0 ? ( + coders.map((item, key) => { + return ( +
+ {key + 1} +

{item.out}

+
+ ); + }) + ) : empty ? (
- {key + 1} -

{item.out}

+ 1 +

+ {stage && stage.name} – {step && step.name}: Skipped +

- ); - }) - ) : empty ? ( -
- 1 -

- {stage && stage.name} – {step && step.name}: Skipped -

+ ) : ( + "" + )}
- ) : ( - "" - )} -
+
+ ) : ( +
error:{data && data.error}
+ )}
- ) : ( -
error:{data && data.error}
- )} -
- + + } + { + nav === "1" && + } + ); }; diff --git a/src/forge/DevOps/Structure.jsx b/src/forge/DevOps/Structure.jsx index 45f734bdf..99040d386 100644 --- a/src/forge/DevOps/Structure.jsx +++ b/src/forge/DevOps/Structure.jsx @@ -2,7 +2,7 @@ import React, { useState, useEffect , useImperativeHandle ,forwardRef } from "re import { FlexAJ, AlignCenter , Banner } from "../Component/layout"; import { Table, Pagination, Popconfirm } from "antd"; import { truncateCommitId } from "../common/util"; -import {getUrl} from 'educoder'; +import { getImageUrl } from 'educoder'; import axios from "axios"; import { Link } from 'react-router-dom'; @@ -58,6 +58,7 @@ function Structure(props,ref){ return { ...item, author:item.author && item.author.name, + image_url:item.author && item.author.image_url, message: { branch: item.branch_target, message: item.message, @@ -197,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 = [ { @@ -244,7 +245,7 @@ function Structure(props,ref){ {meg.sha && {meg.sha}}
- +
{meg.message}
@@ -289,7 +290,7 @@ function Structure(props,ref){ 构建列表 - 返回 + 返回
diff --git a/src/forge/DevOps/disposePipeline.jsx b/src/forge/DevOps/disposePipeline.jsx index 1da142f64..deabc1495 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/ops.scss b/src/forge/DevOps/ops.scss index 538247f38..94838095d 100644 --- a/src/forge/DevOps/ops.scss +++ b/src/forge/DevOps/ops.scss @@ -194,6 +194,18 @@ &.rightSection{ width:100%; background-color: #081930; + .devopsNav{ + background-color: #111c24; + border-bottom: none; + .ant-menu-item{ + color: #ccc; + padding:0px; + margin:0px 20px!important; + } + .ant-menu-item.ant-menu-item-selected{ + color: #1890ff; + } + } .rightMainContent{ padding:24px 30px; height:100vh; @@ -379,6 +391,9 @@ } } } +.chooseCon.ant-select-dropdown{ + z-index: 100001; +} .choosenList{ display: flex; diff --git a/src/forge/DevOps/opsDetail.jsx b/src/forge/DevOps/opsDetail.jsx index 6ac3dc449..1944dfe61 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/Index.jsx b/src/forge/DevOps/ssh/Index.jsx new file mode 100644 index 000000000..9a896a837 --- /dev/null +++ b/src/forge/DevOps/ssh/Index.jsx @@ -0,0 +1,42 @@ +import React, { useState, useEffect } from "react"; +import XmlPanel from "./XmlPanel"; +import mediator from "./mediator"; +import axios from "axios"; + +// const defaulturl = `http://47.111.130.18:48088`; +const defaultValue = { + host: "106.75.231.63", + port: "2021", + ws_url: "wss://pre-webssh.educoder.net/ws", + username: "root", + secret: "Dron_123123", +}; +function Index() { + const [sshConfigData, setSshConfigData] = useState(undefined); + + useEffect(() => { + if (!sshConfigData) { + init(); + } + setTimeout(() => { + mediator.publish("create-socket", 1); + }, 300); + }, [sshConfigData]); + + // 获取服务器连接信息 + function init() { + const url = `/api/ci/pipelines/ssh_server.json`; + axios.get(url).then(result=>{ + if(result && result.data){ + setSshConfigData({...result.data}) + } + }).catch(error=>{}) + } + return ( + + ); +} +export default Index; diff --git a/src/forge/DevOps/ssh/XmlPanel.jsx b/src/forge/DevOps/ssh/XmlPanel.jsx new file mode 100644 index 000000000..295d96ce0 --- /dev/null +++ b/src/forge/DevOps/ssh/XmlPanel.jsx @@ -0,0 +1,216 @@ +import React, { useRef, useEffect, useState } from 'react'; +import { Base64 } from 'js-base64'; + +import { Terminal } from 'xterm'; +import 'xterm/css/xterm.css'; +import mediator from './mediator'; +import ResizeObserver from 'resize-observer-polyfill'; + +function getColsAndRows(width, height, term) { + let w = term._core._renderService.dimensions.actualCellWidth || 9.5; + let h = term._core._renderService.dimensions.actualCellHeight || 18; + const rows = Math.floor(height / h); + const cols = Math.floor(width / w); + return [cols, rows]; +} + +function onLayout(term, el) { + const ro = new ResizeObserver(entries => { + console.log(entries); + for (let entry of entries) { + if (entry.target.offsetHeight > 0 || entry.target.offsetWidth > 0) { + const [cols, rows] = getColsAndRows( + entry.target.offsetWidth, + entry.target.offsetHeight, + term, + ); + term.resize(cols, rows); + mediator.publish('ssh-xterm-resize', { + columns: cols, + rows: rows, + width: entry.target.offsetWidth, + height: entry.target.offsetHeight, + }); + } + } + }); + ro.observe(el); + return ro; +} + +const TimeTicket = 30000; + +//建立 websockt 来交互 +//根据容器大小计算行数和列数并做到自适应 +//socket 与 term 需要分开初始化 因为socket 可能重置连接 +//mediator 监听消息,如果和id匹配,则建立连接,重置,或关闭连接 + +export default ({ sshConfigData, sid }) => { + const [term, setTerm] = useState(null); + + const { ws_url, password, port, secret } = sshConfigData; + const el = useRef(); + const socket = useRef(); + const isFirstConnected = useRef(false); + + //term init + useEffect(() => { + if (el.current && ws_url) { + const term = new Terminal({ fontSize: 16, rendererType: 'dom' }); + term.open(el.current); + + term.onData(data => { + if (socket.current) { + if (socket.current.readyState === 1) { + socket.current.send(JSON.stringify({ tp: 'client', data: data })); + mediator.publish('on-operating-ssh'); //有操作则自动延时 + } else { + //断开连接后重连 + // socket.current = null + // mediator.publish('create-socket', sid) + } + } + }); + term.write('Connecting...'); + setTerm(term); + const ro = onLayout(term, el.current); + return () => { + term.dispose(); + ro.unobserve(el.current); + }; + } + }, [ws_url, el.current]); + + useEffect(() => { + if (term && ws_url) { + function createSocket() { + const socketInstance = new WebSocket(ws_url); + socket.current = socketInstance; + + socketInstance.onopen = () => { + let container = term.element.parentElement; + if (container) { + let width = container.offsetWidth; + let height = container.offsetHeight; + console.log('init', { + tp: 'init', + data: { + ...sshConfigData, + secret: secret, + width, + height, + rows: term.rows, + columns: term.cols, + }, + }); + socketInstance.send( + JSON.stringify({ + tp: 'init', + data: { + ...sshConfigData, + secret: secret, + width, + height, + rows: term.rows, + columns: term.cols, + }, + }), + ); + } + term.focus(); + }; + socketInstance.onerror = error => { + console.log( + '------in socket error----', + error, + socketInstance, + ws_url, + ); + //连接报错后,重新请求资源 + // mediator.publish('on-recreate-socket') + }; + socketInstance.onmessage = event => { + if (!isFirstConnected.current) { + term.write('\r'); + // term.focus() + setTimeout(() => { + // term.clear(); + }, 1000); + } + isFirstConnected.current = true; + + const data = Base64.decode(event.data.toString()); + let w = term._core._renderService.dimensions.actualCellWidth || 9.5; + + term.write(data); + }; + + socketInstance.onclose = evt => { + if (tid) { + clearInterval(tid); + } + term.write('\r\nconnection closed'); + }; + } + + const tid = setInterval(() => { + if (socket.current) { + socket.current.send(JSON.stringify({ tp: 'h' })); + } + }, TimeTicket); + + const unSubCreate = mediator.subscribe('create-socket', id => { + if (sid === id) { + if (socket.current && socket.current.readyState === 1) { + term.focus(); + } else { + createSocket(); + } + term.focus(); + } + }); + + const unSubClose = mediator.subscribe('close-socket', id => { + if (sid === id) { + if (socket.current) { + socket.current.close(); + isFirstConnected.current = false; + term.clear(); + } + socket.current = null; + } + }); + + const unSubResize = mediator.subscribe('ssh-xterm-resize', option => { + if (socket.current && socket.current.readyState === 1) { + socket.current.send( + JSON.stringify({ tp: 'resize', data: { ...option } }), + ); + } + }); + + const unSubAddTime = mediator.subscribe('ssh-add-connect-time', () => { + if (socket.current && socket.current.readyState === 1) { + socket.current.send(JSON.stringify({ tp: 'overtime' })); + } + }); + + return () => { + unSubClose(); + unSubCreate(); + unSubResize(); + unSubAddTime(); + if (socket.current) { + socket.current.close(); + isFirstConnected.current = false; + } + }; + } + }, [term, ws_url, port]); + + return ( +
+ {!ws_url ?

正在连接命令行服务...

: null} +
+ ); +}; \ No newline at end of file diff --git a/src/forge/DevOps/ssh/mediator.jsx b/src/forge/DevOps/ssh/mediator.jsx new file mode 100644 index 000000000..70a4e30f8 --- /dev/null +++ b/src/forge/DevOps/ssh/mediator.jsx @@ -0,0 +1,46 @@ +function Mediator(obj) { + const channels = {}; + + const mediator = { + subscribe: function(channel, cb) { + if (!channels[channel]) { + channels[channel] = []; + } + channels[channel].push(cb); + return this.unsubscribe.bind(null, channel, cb); + }, + + unsubscribe: function(channel, cb) { + let rs = channels[channel]; + let index = -1; + if (rs) { + for (let i = 0; i < rs.length; i++) { + if (rs[i].name === cb.name) { + index = i; + break; + } + } + if (index >= 0) { + channels[channel].splice(index, 1); + return true; + } + } + return false; + }, + + publish: function(channel) { + if (!channels[channel]) { + return false; + } + const args = Array.prototype.slice.call(arguments, 1); + channels[channel].forEach(subscription => { + subscription.apply(null, args); + }); + return this; + }, + }; + + return obj ? Object.assign(obj, mediator) : mediator; +} +const mediator = new Mediator(); +export default mediator; \ No newline at end of file diff --git a/src/forge/Divert/DivertModal.jsx b/src/forge/Divert/DivertModal.jsx index dd9475010..d4c1f2014 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进行修改
  • 转移仓库到组织后,你和组织创建者/管理员同时拥有对该仓库的管理操作
@@ -152,20 +153,21 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){ } - + {getFieldDecorator("identifier", { rules:[ - {required:true,message:"请输入仓库名称"}, + {required:true,message:"请输入仓库标识!"}, { validator:checkIdentifier } ] } )( - + )} + 请输入当前项目的标识:{repo}进行确认!
diff --git a/src/forge/Divert/Index.scss b/src/forge/Divert/Index.scss new file mode 100644 index 000000000..0a39e4e2d --- /dev/null +++ b/src/forge/Divert/Index.scss @@ -0,0 +1,12 @@ +.diverModal{ + .descUl{ + background-color: #fffae6; + border-radius: 4px; + padding:10px 15px; + color: #efc16b; + border:1px solid #efc16b; + } + .ant-form-item-required::before{ + content: ""; + } +} \ No newline at end of file diff --git a/src/forge/Head/AddProjectModal.jsx b/src/forge/Head/AddProjectModal.jsx new file mode 100644 index 000000000..81f1d27cc --- /dev/null +++ b/src/forge/Head/AddProjectModal.jsx @@ -0,0 +1,85 @@ +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)=>{ + const { getFieldDecorator, validateFields , setFieldsValue } = props && props.form; + const [ visible , setVisible ] = useState(false); + + useEffect(()=>{ + if(!visible){ + setFieldsValue({ + code:undefined, + role:"developer" + }) + } + },[visible]) + + function onOk() { + validateFields((error,values)=>{ + if(!error){ + const url = `/applied_projects.json`; + Axios.post(url,{ + applied_project:{ + ...values + } + }).then(result=>{ + if(result && result.data){ + setVisible(false); + props.showNotification("申请加入项目成功,等待审核!"); + } + }).catch(error=>{}) + } + }) + } + function checkValue(rule, value, callback){ + if(!value){ + callback(); + } + if(value.length < 6 || value.length > 6){ + callback("请输入6位数的邀请码"); + } + callback(); + } + + return( + + setVisible(false)} + > +
+ + {getFieldDecorator("code",{ + rules:[ + {required:true,message:"请输入6位项目邀请码"}, + {validator:checkValue} + ] + })( + + )} + + + {getFieldDecorator("role",{ + rules:[{required:true,message:"请选择角色"}] + })( + + 管理员 + 开发者 + 报告者 + + )} + +
+
+ setVisible(true)}>加入项目 +
+ ) + }) +) \ No newline at end of file diff --git a/src/forge/Head/AppPullRefresh.jsx b/src/forge/Head/AppPullRefresh.jsx new file mode 100644 index 000000000..2b9c76606 --- /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 8a69c2ad1..52c068586 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 8c4cdd15a..ac139351e 100644 --- a/src/forge/Head/Header.js +++ b/src/forge/Head/Header.js @@ -2,14 +2,18 @@ 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'; -import GotoQQgroup from '../../modal/GotoQQgroup' +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; @@ -44,6 +48,7 @@ class NewHeader extends Component { settings: null, visiblemyss: false, openSearch:false, + visible:false, //浮动消息框展示控制 } } componentDidMount() { @@ -77,36 +82,6 @@ class NewHeader extends Component { } catch (e) {} } - SearchInput = (open,item)=>{ - if(open){ - return( -
{ - setTimeout(() => { - this.setState({ - openSearch:false - }) - }, 300) - }} - > - this.onGlobalSearch(value,item)} - autoFocus={true} - /> -
- ) - }else{ - return { - this.setState({openSearch:true}) - }} /> - } - } - - onGlobalSearch=(value,item)=>{ - window.location.href=`${item}?value=` + value; - } - openNotification = (messge) => { notification.open({ message: "提示", @@ -115,18 +90,12 @@ class NewHeader extends Component { }); }; - - componentWillReceiveProps(newProps, oldProps) { this.setState({ user: newProps.user }) - if (newProps.Headertop !== undefined) { - old_url = newProps.Headertop.old_url - } } - educoderlogin = () => { //登录账号 this.setState({ @@ -151,7 +120,6 @@ class NewHeader extends Component { }) }; HideAddcoursestypess = (i) => { - console.log("调用了"); this.setState({ Addcoursestypes: false, mydisplay: true, @@ -164,13 +132,11 @@ class NewHeader extends Component { }) }; - // 关闭 cancelModulationModels = () => { this.setState({ isRenders: false }) } - setevaluatinghides = () => { this.setState({ setevaluatinghides: true @@ -255,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( @@ -264,10 +239,16 @@ 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} + ) }) } + + +
) @@ -278,7 +259,7 @@ class NewHeader extends Component { return( - {current_user && current_user.username} + {current_user && current_user.username} { personal && personal.length > 0 && personal.map((item,key)=>{ @@ -287,25 +268,27 @@ 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 { Addcoursestypes, - tojoinitemtype, - tojoinclasstitle, - code_notice, + let { AccountProfiletype, user, isRender, headtypesonClickbool, headtypess, settings, - openSearch, + visible, } = this.state; /*用户名称 用户头像url*/ let activeIndex = false; @@ -384,7 +367,6 @@ class NewHeader extends Component { } let search_url = settings && settings.common && settings.common.search; - let notice_url = settings && settings.common && settings.common.notice; return (
    @@ -416,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) ); @@ -447,24 +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) ? @@ -477,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 000000000..634a7adc8 --- /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 507262e37..263cd1ee5 100644 --- a/src/forge/Head/header.scss +++ b/src/forge/Head/header.scss @@ -1,7 +1,6 @@ .dropdownFlex{ display:flex; - padding:5px; background:#fff; border-radius: 3px; .ant-menu-vertical > .ant-menu-item{ @@ -9,6 +8,13 @@ height: 35px; line-height: 35px; margin:0px; + &.ant-menu-item-selected{ + background-color: #fff; + a{color: rgba(0, 0, 0, 0.65)!important;} + } + &.ant-menu-item-active{ + a{color: #4cacff!important;} + } } .ant-menu-vertical{ border:none; @@ -18,16 +24,24 @@ 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; - padding:0px; + padding:0px!important; cursor: default; &:hover{ background-color: #fff; @@ -104,4 +118,148 @@ } } } +} +.inviteForm{ + .ant-form-item{ + margin-right: 0px; + } + .ant-form-item-label{ + 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 aa0219aae..c2e369169 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,17 +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, +// }); -const Infos = Loadable({ - loader: () => import("./users/Infos"), - loading: Loading, -}); class Index extends Component { + + componentDidUpdate = () => { + this.props.history.listen(() => { + if (document.body.scrollTop || document.documentElement.scrollTop > 0) { + window.scrollTo(0, 0) + } + }) + } render() { + return (
    @@ -48,30 +55,27 @@ class Index extends Component { )} > ( )} > - ( )} - > + > */} ( )} > + ( - this.props.current_user && this.props.current_user.login ? - - : )} > @@ -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 adda25c54..f50c134a3 100644 --- a/src/forge/Main/CoderDepot.jsx +++ b/src/forge/Main/CoderDepot.jsx @@ -1,8 +1,9 @@ import React , { useEffect , useState } from 'react'; import { WhiteBack , Box , LongWidth , ShortWidth , Gap , AlignCenter , FlexAJ } from '../Component/layout'; -import { Dropdown , Menu , Divider , Spin, Button } from 'antd'; +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'; @@ -19,12 +20,29 @@ import LanguagePower from '../Component/LanguagePower'; 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时不支持在线创建、在线上传、在线修改、在线删除、创建合并请求等功能) */ + const { Paragraph } = Typography; +function turnbar(str){ + if(str && str.length>0 && str.indexOf("/")>-1){ + return str.replaceAll('/','%2F'); + } + return str; +} +function returnbar(str){ + if(str && str.length>0 && str.indexOf("%2F")>-1){ + return str.replaceAll('%2F','/'); + } + return str; +} + function CoderDepot(props){ const [ projectDetail , setProjectDetail ]= useState(undefined); + const [ inviteCode , setInviteCode ] = useState(undefined); const [ treeValue , setTreeValue ] = useState(undefined); const [ treeValuePath , setTreeValuePath ] = useState(undefined); const [ lastCommit,setLastCommit ] = useState(undefined); @@ -46,13 +64,35 @@ function CoderDepot(props){ const [ website , setWebsite ] = useState(undefined); const [ lesson_url , setLessonUrl ] = useState(undefined); const [ readme , setReadme ] = useState(undefined); - const [ defaultBranch , setDefaultBranch ] = useState(undefined) + const [ defaultBranch , setDefaultBranch ] = useState(undefined); + 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; - const branchName = props.match.params.branchName; + let branchName = props.match.params.branchName; + branchName = returnbar(branchName); const details = props.projectDetail; let pathname = props.history.location.pathname; + //distribution:判断此用户是否可以创建发行版 + const distribution = details && details.type != 2 && (details.permission === "Admin" || details.permission === "Owner" || details.permission === "Manager"); + const { bannerList } = props; + + useEffect(()=>{ + if(bannerList && bannerList.length>0){ + let a = bannerList.filter(i=>i.menu_name === "pulls"); + let i = bannerList.filter(i=>i.menu_name === "issues"); + if(a && a.length === 0){ + setPullsFlag(false); + } + if(i && i.length === 0){ + setIssuesFlag(false); + } + } + },[bannerList]) + useEffect(()=>{ if(details){ @@ -61,6 +101,7 @@ function CoderDepot(props){ setWebsite(details.website); setLessonUrl(details.lesson_url); setDefaultBranch(details.default_branch); + setInviteCode(details.invite_code); } },[details]) @@ -75,21 +116,58 @@ function CoderDepot(props){ useEffect(()=>{ if (projectsId && owner && defaultBranch){ - if(pathname.indexOf(`/projects/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${branchName}/`) > -1) { - let url = pathname.split(`/tree/${branchName}/`)[1]; + let b = turnbar(branchName) ; + 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); const url = `/${owner}/${projectsId}/entries.json`; + axios.get(url, { params: { ref: branch } }).then((result) => { @@ -104,7 +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);}) @@ -116,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]) @@ -137,16 +218,20 @@ 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); } setTimeout(function(){setIsSpin(false);},500) }).catch(error=>{setIsSpin(false);}) @@ -154,17 +239,26 @@ function CoderDepot(props){ // 切换分支或者标签 function changeBranch(value){ - let url = `/projects/${owner}/${projectsId}${value && `/tree/${value}`}${treeValue ? `/${treeValue}`:""}`; + let checkvalue = turnbar(value); + let url = `/${owner}/${projectsId}${value && `/tree/${checkvalue}`}${treeValue ? `/${treeValue}`:""}`; props.history.push(url); } // 文件相关的下拉项 - const fileMenu =( - - urlLink(`/projects/${owner}/${projectsId}/${branchName || defaultBranch}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件 - urlLink(`/projects/${owner}/${projectsId}/${branchName || defaultBranch}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件 + function fileMenu(){ + let b = branchName || defaultBranch; + let checkvalue = turnbar(b); + return ( + + + urlLink(`/${owner}/${projectsId}/${checkvalue}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件 + + + urlLink(`/${owner}/${projectsId}/${checkvalue}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件 + - ) + ) + } function getPathUrl(array,index){ if(array && array.length>0 && index){ @@ -179,26 +273,35 @@ function CoderDepot(props){ function returnMain(){ setTreeValue(undefined); let branch = branchName || defaultBranch; - props.history.push(`/projects/${owner}/${projectsId}/tree/${branch}`); + let checkvalue = turnbar(branch); + props.history.push(`/${owner}/${projectsId}/tree/${checkvalue}`); }; // 子目录路径返回链接 function returnUlr(url){ - props.history.push(`/projects/${owner}/${projectsId}/tree${branchName?`/${branchName}`:""}/${url}`); + let enBranch = turnbar(branchName); + props.history.push(`/${owner}/${projectsId}/tree${enBranch?`/${enBranch}`:""}/${url}`); } // 点击跳转到子目录 function goToSubRoot(path,type,filename){ - setType(type); - props.history.push(`/projects/${owner}/${projectsId}${`/tree/${branchName || defaultBranch}`}${path?`/${path}`:""}`); + if(type!=="submodule"){ + let enBranch = branchName || defaultBranch; + let checkvalue = turnbar(enBranch); + setType(type); + props.history.push(`/${owner}/${projectsId}${`/tree/${checkvalue}`}${path?`/${path}`:""}`); + } } function onEdit(readOnly){ setReadOnly(readOnly); + setEditReadme(false); } function ChangeFile(path, readOnly){ //点击直接跳转页面 加载一次路由 - props.history.push(`/projects/${owner}/${projectsId}/tree/${branchName || defaultBranch}/${path}`); + let enBranch = branchName || defaultBranch; + let checkvalue = turnbar(enBranch); + props.history.push(`/${owner}/${projectsId}/tree/${checkvalue}/${path}`); setType("file"); - setReadOnly(readOnly); + setEditReadme(true); }; function changeHide(hide){ @@ -214,17 +317,12 @@ function CoderDepot(props){ } const downloadMenu = ( -
    -
    - -
    - - 下载 ZIP - 下载 TAR.GZ - -
    + ) // 确认修改简介、website、实践课程链接 function okUpdate(d,w,l){ @@ -239,10 +337,14 @@ function CoderDepot(props){ } }) } - let n = fileInfo && fileInfo.name; const mdFlag = n && n.substring(n.length-3,n.length) === ".md"; - + + const { current_user } = props; + 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}/> @@ -261,7 +363,7 @@ function CoderDepot(props){ list = {mainFlag ? dirInfo : undefined} />
    setVisible(true)}> - + 目录
    @@ -274,7 +376,7 @@ function CoderDepot(props){
    -
    +
    { props && props.platform ? : - 分支:{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} + + + + } - - - { type === "dir" && projectDetail.type !== 2 && - - + + { + (baseOperate || baseOper) && +
    + { + baseOperate && + urlLink(`/${owner}/${projectsId}/compare/master...${branchName || defaultBranch}`)} >+ 合并请求 + } + { + baseOper && + urlLink(`/${owner}/${projectsId}/issues/new`)} >+ 易修 + } +
    + } + { fileOperate && + + 文件 } - +
    { - dirInfo || fileInfo ? + (dirInfo && dirInfo.length>0) || fileInfo ?
    { lastCommit &&
    -
    {lastCommit && lastCommit.message}
    +
    +
    +
    { hideBtn && changeHide(hide)}> } - {lastCommit && lastCommit.time_from_now} - { commitCount ? {commitCount}次提交:"" } + {lastCommit.time_from_now} + { + commitCount ? + + {commitCount}次提交 + :"" + }
    }
      - { - treeValuePath && treeValuePath.length > 0 && - - } { dirInfo && dirInfo.length > 0 && dirInfo.map((item,key)=>{ @@ -377,64 +502,80 @@ 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-anquanshezhi color-grey-9 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}

    } + {desc &&

    {desc}

    } { website && -

    - - {website} -

    +
    + + {website} +
    } -

    - - README.md -

    -

    - +

    + + README.md +
    +
    + {projectDetail && projectDetail.size} -

    +
    { projectDetail && projectDetail.license_name && -

    - - {projectDetail.license_name} -

    +
    + + {projectDetail.license_name} +
    }
    + { + inviteCode && +
    + + +
    + } { lesson_url &&
    -

    实践课程

    - {lesson_url} +

    实践课程

    + {lesson_url}
    } {/* 发布 */} { - 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 f374da15c..4f5d86c1a 100644 --- a/src/forge/Main/CoderDepotCatalogue.jsx +++ b/src/forge/Main/CoderDepotCatalogue.jsx @@ -2,20 +2,26 @@ import React from 'react'; import { Link } from 'react-router-dom'; import { truncateCommitId } from '../common/util'; +const typeIco = { + "submodule":"icon-file-submodule font-17", + "file":'icon-wenjian6 font-15 color-blue-file', + "dir":"icon-wenjianjia4 font-15 color-blue_4C" +} + function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){ return(
  • - goToSubRoot(item.path,item.type,item.name)}> - {item.name} + goToSubRoot(item.path,item.type,item.name)} className={item.type === "submodule" && "submoduleStyle"}> + {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 ad4bb1096..89d6a5ca3 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 b04c0dfe0..315f70805 100644 --- a/src/forge/Main/CoderDepotReadme.jsx +++ b/src/forge/Main/CoderDepotReadme.jsx @@ -1,7 +1,9 @@ import React, { useEffect, useState } from 'react'; import RenderHtml from '../../components/render-html'; -import { Dropdown , Menu , Spin } from 'antd'; -import { Link } from 'react-router-dom'; +import { AlignCenter } from '../Component/layout'; +import { Dropdown , Anchor , Spin } from 'antd'; + +import ReadmeCatelogue from './sub/ReadmeCatelogue'; const $ = window.$; function CoderDepotReadme({ operate , history , readme , ChangeFile }){ @@ -22,44 +24,45 @@ function CoderDepotReadme({ operate , history , readme , ChangeFile }){ const anchor = el.id; const level = el.tagName.replace("H", ""); const href = `#${anchor}`; - return { href:`${path}${href}`,text:el.textContent , level:level } + return { href:`${href}`,text:el.textContent , level:level } }); setMenuList(items); },[content]) function menu(){ if(menuList && menuList.length > 0){ - let hash = history.location.hash; return( - - { - menuList.map((item,key)=>{ - return( - -1 ?"active":""}>{item.text} - ) - }) - } - + ) }else{ return } } + return( -
    -
    - - - - README.md - { - operate ? - ChangeFile(readme && readme.path, false)}> - - - :"" - } -
    +
    + +
    + + + + + 目录 + + + + README.md + + + { + operate ? + ChangeFile(readme && readme.path, false)}> + + + :"" + } +
    +
    { content &&
    diff --git a/src/forge/Main/CoderRootCommit.js b/src/forge/Main/CoderRootCommit.js index fc64aa012..b542c3905 100644 --- a/src/forge/Main/CoderRootCommit.js +++ b/src/forge/Main/CoderRootCommit.js @@ -1,21 +1,36 @@ 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){ + return str.replaceAll('%2F','/'); + } + 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 } @@ -43,13 +58,28 @@ 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)=>{ @@ -60,7 +90,7 @@ class CoderRootCommit extends Component{ const url = `/${owner}/${projectsId}/commits.json`; axios.get(url,{ params:{ - sha:branch, + sha:returnbar(branch), page, limit } @@ -78,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({ @@ -93,19 +124,18 @@ 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; const { projectsId , owner , branchName } = this.props.match.params; - let branch = branchName || defaultBranch; + let branch = returnbar(branchName || defaultBranch); return(
    @@ -121,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 deb555a82..bdcfc98a7 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 "./list.css"; +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 ? -
    +
    : @@ -285,6 +323,7 @@ class CoderRootFileDetail extends Component { readOnly={readOnly} editorType="update" currentBranch={currentBranch} + descName={detail && `Update ${detail.name}`} > )}
    diff --git a/src/forge/Main/CoderRootIndex.js b/src/forge/Main/CoderRootIndex.js index ceff9d9f2..7ff25dae1 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,89 +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 6a5205abd..484836213 100644 --- a/src/forge/Main/CoderRootTag.js +++ b/src/forge/Main/CoderRootTag.js @@ -26,7 +26,7 @@ export default (( props, { projectDetail }) => { }, [owner, projectsId]); return ( -
    +
    { @@ -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 e20b4ec9b..06d2fc44b 100644 --- a/src/forge/Main/Detail.js +++ b/src/forge/Main/Detail.js @@ -1,10 +1,13 @@ import React, { Component } from 'react'; import { Spin, Tooltip } from 'antd'; import { Link, Route, Switch } from 'react-router-dom'; -import { Content } from '../Component/layout'; +import { Content, AlignTop } from '../Component/layout'; import DetailBanner from './sub/DetailBanner'; import '../css/index.scss' -import './list.css'; +import './list.scss'; + +import { ImageLayerOfCommentHOC } from "../../modules/page/layers/ImageLayerOfCommentHOC"; + import Loadable from 'react-loadable'; import Loading from '../../Loading'; @@ -67,7 +70,7 @@ const MergeIndexDetail = Loadable({ }) const CreateMerge = Loadable({ - loader: () => import('../Merge/NewMerge'), + loader: () => import('../Merge/CreateMerge'), loading: Loading, }) @@ -103,12 +106,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({ @@ -127,30 +130,42 @@ const Source = Loadable({ const DevIndex = Loadable({ loader: () => import('../DevOps/Index'), loading: Loading, -}) +}); +const Wiki = Loadable({ + loader: () => import('../Wiki/Index'), + loading: Loading, +}); +const WikiEdit = Loadable({ + loader: () => import('../Wiki/EditWiki'), + loading: Loading, +}); /** * 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("/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; @@ -173,14 +188,15 @@ class Detail extends Component { branchs: undefined, branchList: undefined, project: null, - firstSync:false, - secondSync:false, - open_devops:false, + firstSync: false, + secondSync: false, + open_devops: false, + forkSpin: false, // 默认分支 - defaultBranch:undefined, + defaultBranch: undefined, // 非本平台项目 - platform:false + platform: false } } @@ -197,36 +213,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, - firsrtSync: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({ - firsrtSync:false, - secondSync:false + firstSync: false, + secondSync: false }) } } @@ -234,19 +252,23 @@ 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; var cable = actioncable.createConsumer(`wss://${name}/cable`); this.canvasChannel1 = cable.subscriptions.create({ channel: `MirrorProjectChannel`, - id: project && project.identifier + id: project && project.id }, { connected: () => { console.log("###### channel connected! ######"); @@ -254,20 +276,53 @@ 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 + }); cable.subscriptions.consumer.disconnect(); } } }) } + 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, @@ -280,29 +335,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({ @@ -317,15 +372,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', @@ -335,9 +390,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) => { @@ -357,30 +412,40 @@ class Detail extends Component { // fork项目 forkFunc = () => { const { platform } = this.state; - if(!platform)return; + if (!platform) return; + this.setState({ + 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 + }) }).catch(error => { - console.log(error); + this.setState({ + forkSpin: false + }) }) } // 同步镜像 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("镜像同步失败!"); } @@ -389,333 +454,363 @@ class Detail extends Component { }) } - + textFunc = (forked_from_project_id, fork_info) => { + let type = fork_info && fork_info.fork_project_user_type; + return forked_from_project_id && fork_info ? +
      + 复刻自 + {fork_info.fork_project_user_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 } = 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 text = ( - projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ? - - forked from - {projectDetail.fork_info.fork_project_user_name} - / - {projectDetail.fork_info.fork_form_name} - : "" - ); - + const common = { getDetail: this.getDetail, - changeOpenDevops:this.changeOpenDevops, + changeOpenDevops: this.changeOpenDevops, defaultBranch } return (
      -
      -

      - {project && project.author && - - {project.author.name} - - } - / - - {project && project.name} + +

      + +
      + {project && project.author && + {project.author.name} + } + / + {projectDetail && projectDetail.name} +
      + {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.type === 2 ? - - - - : - - - - :"" + 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 ? '取消关注' : '关注'} - - { - 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} - :"" - } - - - } -
      +
      +
      +
      + { + firstSync ? "" : + + { + ((current_user && current_user.admin) || isManager) && (projectDetail && projectDetail.type && projectDetail.type === 2) ? + 同步镜像 : "" + } + + this.focusFunc(watched)}> + + {watched ? '取消关注' : '关注'} + + { + 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} + : "" + } + + + } +
      + { firstSync ? "" : - + }
      { firstSync ? - - - - : - - - {/* 资源 */} - () - } - > - {/* 主页 */} - () - } - > - {/* 工作流 */} - () - } - > - {/* 标签列表 */} - () - } - > - {/* 仓库设置 */} - () - } - > - {/* 任务详情 */} - () - } - > - {/*修改里程碑*/} - () - } - > - {/* 新建里程碑 */} - () - } - > - {/*里程碑详情*/} - () - } - > - {/* 里程碑 */} - () - } - > - {/* 里程碑页面新建任务 */} - () - } - > - {/* 新建任务 */} - () - } - > - {/* 修改详情 */} - () - } - > - {/* 复制详情 */} - () - } - > - {/* 动态 */} - () - } - > - {/* 代码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 000000000..d65f3bc3c --- /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 260ff1e61..ecd5ab9f5 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 d8db5f008..8dad59fba 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 => { @@ -51,34 +82,47 @@ export default ({ match , history }) => { } }, [projectsId , owner, sha]); return ( -
      +
      - {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 64a55ed26..3b1f66dba 100644 --- a/src/forge/Main/Index.js +++ b/src/forge/Main/Index.js @@ -1,15 +1,19 @@ 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'; +import "slick-carousel/slick/slick.css"; +import "slick-carousel/slick/slick-theme.css"; import '../css/index.scss' -import './list.css'; +import './list.scss'; import './Index.scss'; import ListItem from './IndexItem' 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 { @@ -30,6 +34,8 @@ class Index extends Component { categoryList: undefined, recommendList:undefined, + recommendOriList:undefined, + languageList:undefined, languageId:undefined } @@ -47,6 +53,8 @@ class Index extends Component { this.getRecommand(); this.getLanguage(); + + // this.getRecommandOri(); } // 获取语言列表 @@ -72,6 +80,17 @@ class Index extends Component { }).catch(error=>{}) } + getRecommandOri=()=>{ + const url = `/organizations/recommend.json`; + axios.get(url).then(result=>{ + if(result){ + this.setState({ + recommendOriList:result.data.organizations + }) + } + }).catch(error=>{}) + } + // 获取列表 getListData = (page, limit, search, sort, project_type, category_id,languageId) => { const { current_user } = this.props; @@ -210,7 +229,7 @@ class Index extends Component { } getoDetail=(login,identifier)=>{ - this.props.history.push(`/projects/${login}/${identifier}`); + this.props.history.push(`/${login}/${identifier}`); } // 选择语言类别 @@ -236,10 +255,14 @@ class Index extends Component { newItem = ()=>{ return( - - 新建镜像项目 - 新建托管项目 - +
        +
      • + {this.props.history.push('/projects/deposit/new')}}>新建项目 +
      • +
      • + {this.props.history.push('/projects/mirror/new')}}>导入项目 +
      • +
      ) } @@ -256,22 +279,56 @@ class Index extends Component { const { current_user } = this.props; const { projectsList , recommendList , languageList , languageId , - isSpin, total, search, limit, page, typeList, categoryList } = this.state; + isSpin, total, search, limit, page, typeList, categoryList , recommendOriList } = this.state; + + const setting={ + dots: true, + infinite: true, + speed: 500, + slidesToShow: 5, + slidesToScroll: 5, + autoplay:false, + arrows:false, + adaptiveHeight:true + } + const settings={ + dots: true, + infinite: true, + speed: 500, + slidesToShow: 6, + slidesToScroll: 6, + autoplay:false, + arrows:false, + adaptiveHeight:true + } return (

      + {/* { + recommendOriList && recommendOriList.length>0? + + { + recommendOriList.map((i,k)=>{ + return( +
    • {i.name}
    • + ) + }) + } +
      + :"" + } */} { recommendList && recommendList.length>0 && -
      + 5 ? "recommandProjects":"recommandProjects mb20"}> { recommendList.map((item,key)=>{ return( -
      this.getoDetail(item.author && item.author.login,item.identifier)}> +
      this.getoDetail(item.author && item.author.login,item.identifier)}>
      - +

      {item.name}

      {item.author && item.author.name}

      @@ -283,9 +340,8 @@ class Index extends Component { ) }) } -
      + } -
        @@ -336,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 6b6592696..5f3692929 100644 --- a/src/forge/Main/Index.scss +++ b/src/forge/Main/Index.scss @@ -1,57 +1,68 @@ -/* recommandProjects */ -.recommandProjects{ - display: flex; - max-width: 1200px; - margin:20px auto; -} -.recommandProjects >div{ - background-color: #fff; - border-radius: 10px; - width: 220px; - margin-right: 25px; - cursor: pointer; - border: 1px solid #eee; - &:last-child{ - margin-right: 0px; +.recommandOri.slick-slider{ + width: 1300px; + margin:20px auto 40px; + .slick-track{ + margin-left: 0px; + } + .slick-slide{ + li > a{ + + display: flex; + align-items: center; + justify-content: center; + } } } -.recommandProjects > div:hover{ - box-shadow: 0px 2px 20px 0px rgba(0, 0, 0, 0.1); -} -.recommandProjects > div .mainInfo{ - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - min-height: 160px; - border-bottom: 1px solid #eee; - padding:20px; - box-sizing: border-box; - img{ - height: 50px; - width:50px; - border-radius: 50%; - } - .name{ - font-size: 13px; +.iconBtn{ + i{ color: #666; - height: 18px; - line-height: 18px; - margin-top:12px; } - .school{ - margin-top:12px; - color: #333; - font-size: 16px; - height: 22px; - line-height: 22px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - max-width:100%; + span{ + margin-left: 4px; + color: #333!important; + &:last-child{ + font-weight: 500; + } + } + &:hover span,&:hover i{ + color: #466AFF!important; } } -.recommandProjects{ +/* recommandProjects */ +.recommandProjects.slick-slider{ + width: 1230px; + margin:20px auto 40px; + .slick-track{ + margin-left: 0px; + } + .slick-arrow.slick-prev,.slick-arrow.slick-next{ + &:before{ + color: #999; + } + li.slick-active button:before{ + color: #999; + } + } + .slick-dots{ + bottom: -29px; + li button:before{ + color: #909090; + } + } + .slick-slide{ + padding:0px 15px; + box-sizing: border-box; + & > div{ + background-color: #fff; + border-radius: 10px; + width: 100%; + cursor: pointer; + border: 1px solid #eee; + &:hover{ + box-shadow: 0px 2px 20px 0px rgba(0, 0, 0, 0.1); + } + } + } .baseInfo{ padding:18px 15px; display: flex; @@ -72,68 +83,134 @@ text-align: right; } } + .mainInfo{ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 160px; + border-bottom: 1px solid #eee; + padding:20px; + box-sizing: border-box; + img{ + height: 50px; + width:50px; + border-radius: 50%; + } + .name{ + font-size: 13px; + color: #666; + height: 18px; + line-height: 18px; + margin-top:12px; + } + .school{ + margin-top:12px; + color: #333; + font-size: 16px; + height: 22px; + line-height: 22px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + max-width:100%; + } + } } - // coderDepot .Panels{ max-width: 1200px; margin: 0 auto; .panelmenu{ padding-top:30px; - } - .addOptionBtn{ - height: 32px; - line-height: 32px; - display: flex; - border:1px solid #d9d9d9; - border-radius: 4px; - a{ - padding:0px 13px; - color: rgba(0, 0, 0, 0.65); - cursor: pointer; + .depotBtn{ + .mr-5{ + margin-right: -5px; + } + .ant-btn{ + height: 32px; + line-height: 32px; + width: 83px; + text-align: center; + padding:0px ; + font-weight: 500; + font-size: 14px; + } + .ant-btn-default{ + color: #333; + border-color: #d0d0d0; + &:hover{ + background: #F3F4F6; + } + } + .ant-btn-primary{ + color: #fff; + background-color: #466AFF; + border: none; + &:hover{ + background-color: rgba(70,106,255,0.85); + } + } } - & > a:first-child{ - border-right: 1px solid #d9d9d9; + } + .depotBtn,.addOptionBtn{ + display: flex; + a{ + 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{ display: inline-block; - padding:0px 5px; - height: 16px; - line-height: 16px; - background-color: #eee; - color:#999; + width: 24px; + text-align: center; + height: 24px; + line-height: 24px; + background-color:rgba(153, 153, 153, 0.13);; + color:#666; border-radius: 12px; - margin-left: 10px; + margin-left: 6px; font-size: 12px; } .attrPerson{ - padding-top: 15px; + padding-top: 12px; display: flex; flex-wrap: wrap; + padding-bottom: 2px; a{ - margin: 10px 10px 0px 0px; + margin: 0px 17px 10px 0px; img{ border-radius: 50%; - width: 35px; - height: 35px; + 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; } } } @@ -147,16 +224,17 @@ height: 8px; width: 8px; left: 0px; - top:10px + top:8px; } &>span{ padding-left: 15px; position: relative; min-width: 33.5%; + font-size: 12px; + font-weight: 400; + color: #666; span{ - color: #666; &:last-child{ - color: #999; margin-left: 5px; } } @@ -164,58 +242,96 @@ } .listtable{ margin-top: 20px; - border:1px solid #d9d9d9; - border-radius: 4px; .listtablehead{ display: flex; justify-content: space-between; align-items: flex-start; border-bottom: 1px solid #d9d9d9; - padding:7px 20px; + padding:12px 20px 11px; border-radius: 4px 4px 0px 0px; - background-color: #FAFBFC; + border: 1px solid rgba(42, 97, 255, 0.23); + background-color: #FAFCFF; .ellipsistxt{ + &:hover .markdown-body{ + color: #466AFF; + & a{ + color: #466AFF; + } + } + margin-top: 2px; + // cursor: pointer; + #ptxt{ + margin-bottom: 0px; + word-break: break-all; + overflow: unset; + white-space:pre-wrap; /* css3.0 */ + white-space:-moz-pre-wrap; /* Firefox */ + white-space:-pre-wrap; /* Opera 4-6 */ + white-space:-o-pre-wrap; /* Opera 7 */ + word-wrap:break-word; + .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; - margin-top:6px; flex:1; width: 0; color: #666; - &>p{ - word-break:break-all; - } - &.hide{ - height: 18px; + &.hidetxt{ + height: 24px; overflow: hidden; position: relative; padding-right:8px; - } - &.hide::after{ - position: absolute; - right: 0px; - bottom: 0px; - content:"..."; - + // &::after{ + // position: absolute; + // right: 0px; + // bottom: 0px; + // content:"..."; + // } } } .ellipsis{ margin-left: 8px; cursor: pointer; border-radius: 2px; - background-color: #c1c1c1; + height: 16px; + background: rgba(153, 153, 153, 0.2); + border-radius: 2px; padding:0px 4px; height: 14px; line-height: 14px; margin-top: 9px; i{ font-size: 15px!important; - color: #fff; + color: #333; height: 14px; line-height: 14px; } } } .listtablebody{ + border-radius:0px 0px 4px 4px ; + border: 1px solid #D0D0D0; + border-top: none; li.listtablepath{ a{color: #40a9ff;} p{ @@ -223,12 +339,15 @@ } } & > li{ - height: 42px; + height: 38px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #d9d9d9; padding:0px 20px 0px 24px; + &:hover{ + background-color: #F3F4F6; + } & > span:first-child{ width: 30%; overflow: hidden; @@ -255,34 +374,60 @@ .drawerBtn{ position: fixed; left: -13px; - border:1px solid #d9d9d9; - width: 34px; + width: 33px; + background: #FFFFFF; + box-shadow: 0px 0px 8px 3px rgba(0, 0, 0, 0.09); + border: 1px solid #666666; border-radius: 0px 12px 12px 0px; - text-align: right; height: 70px; - line-height: 70px; top:50%; margin-top: -35px; cursor: pointer; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding-left: 7px; &:hover{ - box-shadow: 1px 0px 7px rgba(0,0,0,0.1); + box-shadow: 0px 0px 8px 3px rgba(0, 0, 0, 0.09); + } + span{ + writing-mode: vertical-lr; + color: #333; + width: 25px; + font-size: 14px; } i{ - color: #d9d9d9; + color: #333; + height: 14px; + line-height: 14px; + width: 14px; + margin-left: 2px; + margin-bottom: 3px; } } .downMenu{ - box-shadow: 0px 0px 9px rgba(134, 134, 134,0.4); + width: 329px; background-color: #fff; - .ant-menu-vertical .ant-menu-item:hover{ - background-color: #e6f7ff; + box-shadow: 0px 1px 8px 1px rgba(212, 212, 212, 0.5); + padding-bottom: 14px; + .ant-menu-item{ + height: 50px; + line-height: 50px; + } +} +.fileMenu{ + width: 83px; + li{ + padding:6px 0px!important; + text-align: center; + width: 100%; } } -.menuslist{ - max-height: 200px; - overflow-y: auto; - padding:10px 15px; +.catelogue{ + cursor: pointer; + background: #FAFBFC; border-radius: 4px; .ant-dropdown-menu-item{ border-radius: 8px; @@ -294,7 +439,73 @@ text-overflow: ellipsis; } } - .ant-dropdown-menu-item.active{ - background-color: #e6f7ff; + border: 1px solid #D0D0D0; + font-size: 15px; + font-weight: normal; + margin-right: 12px; + padding:0px 10px; + height: 30px; + line-height: 30px; + color: #666!important; + display: flex; + align-items: center; + &:hover{ + background-color: #F3F4F6; + } + span{ + margin-top: 1px; + } +} +.submoduleStyle{ + cursor: default; + i{ + cursor: default; + } + &:hover{ + color: #05101a; + } +} +.pinfos{ + i,a{color: #666;} + &:hover i,&:hover a{ + color: #2A61FF!important; + } +} +.graph{ + flex:1; + margin:0px 12px; + .ant-typography{ + white-space: pre-wrap; + margin-bottom: 0px; + } +} +.ant-anchor-wrapper{ + 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 9b6a78c1d..0cba9123e 100644 --- a/src/forge/Main/IndexItem.js +++ b/src/forge/Main/IndexItem.js @@ -5,7 +5,7 @@ import { AlignCenter } from '../Component/layout'; import { Link } from 'react-router-dom'; import '../css/index.scss'; import Nodata from '../Nodata'; -import './list.css'; +import './list.scss'; import img_parise from '../Images/parise.png'; class IndexItem extends Component { @@ -18,7 +18,7 @@ class IndexItem extends Component { render() { const { projects } = this.props; return ( -
        +
        { projects && projects.length > 0 ? projects.map((item, key) => { return (
        @@ -28,45 +28,56 @@ class IndexItem extends Component { : - + }
        - + {item.author.name}/{item.name} + { !item.is_public && 私有 } { item.forked_from_project_id ? - + - + : "" } { - item.type && item.type !== 0 ? - item.type === 2 ? - + item.type && item.type === 2 ? + - : - + :"" + } + { + item.type && item.type === 1 ? + - :"" + :"" } - 赞 {item.praises_count} - fork {item.forked_count} + { + item.praises_count && item.praises_count>0 ? + + 赞 {item.praises_count} + :"" + } + { + item.forked_count && item.forked_count>0 ? + + fork {item.forked_count} + :"" + }

        {item.description}

        - {/* {item.visits} */} - {/* {item.category && item.category.id && {item.category.name}} */} {item.last_update_time ? {item.time_ago} : ""} {item.language && item.language.id ? {item.language.name} : ""} diff --git a/src/forge/Main/NullData.js b/src/forge/Main/NullData.js index a550b5bcc..1621d657c 100644 --- a/src/forge/Main/NullData.js +++ b/src/forge/Main/NullData.js @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import "../Branch/branch.css" +import "../Branch/branch.scss" diff --git a/src/forge/Main/img/tree-black.png b/src/forge/Main/img/tree-black.png new file mode 100644 index 000000000..02aa71c3a 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 000000000..56247256c Binary files /dev/null and b/src/forge/Main/img/tree.png differ diff --git a/src/forge/Main/list.css b/src/forge/Main/list.scss similarity index 72% rename from src/forge/Main/list.css rename to src/forge/Main/list.scss index bdf93163f..59589fb62 100644 --- a/src/forge/Main/list.css +++ b/src/forge/Main/list.scss @@ -218,71 +218,92 @@ } /* -----------详情------------ */ .detailHeader-wrapper{ - background-color:#FAFBFC; - /* background: url(../Images/forgeBanner.jpg) no-repeat center; */ - /* background-size:cover; */ + background-color:#FBFCFF; + border-bottom:1px solid #e2e2e2; } .headerMenu-wrapper{ - font-size: 16px; display: flex; flex-direction: row; -} -.headerMenu-wrapper li{ - position: relative; - text-align: center; - height: 40px; - line-height: 28px; - margin-right: 40px; -} -.headerMenu-wrapper li a{ - color: #666; -} -.headerMenu-wrapper li a > img{ - margin-right: 8px; -} -.headerMenu-wrapper li a > span.num{ - height: 28px; - line-height: 29px; - margin-left: 8px; - font-size: 12px; - color: #2878FF; - float: right; -} -.headerMenu-wrapper li.active::after{ - position: absolute; - bottom:0px; - height:2px; - background-color: #5091FF; - content:''; - left: 0px; - width:100%; + cursor: pointer; + li{ + text-align: center; + padding:0px; + margin-right: 40px; + display: flex; + & > a{ + position: relative; + font-size: 14px; + height: 36px; + line-height: 24px; + display: block; + color: #000!important; + &> span.num{ + line-height: 24px; + margin-left: 5px; + font-size: 12px; + float: right; + color: #666!important; + background-color: rgba(153, 153, 153, 0.13);; + border-radius: 50%; + width: 24px; + height: 24px; + } + } + + &.active a::after,&:hover a::after{ + position: absolute; + bottom:0px; + height:2px; + background-color:rgba(153, 153, 153, 0.2); + content:''; + left: 0px; + width:100%; + } + &.active span{ + font-weight: 500; + } + &.active a::after{ + background-color: #466AFF; + } + } } .detail_tag_btn{ - height:26px; - line-height: 26px; + height:32px; + line-height: 32px; border-radius:5px; - border:1px solid #f1f1f1; + border:1px solid #D0D0D0; display: flex; align-items: center; - margin-left: 30px + margin-left: 10px; + padding:0px; + background-color:#FAFBFC; + box-shadow: none; + .detail_tag_btn_name{ + padding:0px 10px; + text-align: center; + height: 30px; + line-height: 30px; + border-radius:5px 0px 0px 5px; + &:hover + { + background-color: #F3F4F6; + } + span{ + color: #333!important; + } + } + .detail_tag_btn_count{ + width: 42px; + text-align: center; + background: #fff; + border-radius: 0px 4px 4px 0px; + height:100%; + border-left: 1px solid #D0D0D0; + } } .ant-tooltip { max-width: fit-content!important; } -.detail_tag_btn_name{ - padding:0px 10px; - color: #666!important; -} -.detail_tag_btn_name img{ - margin-right: 10px; -} -.detail_tag_btn_count{ - padding:0px 10px; - background: #fff; - border-radius: 0px 4px 4px 0px; - font-size: 12px; - height:100%; -} .files-md{ padding:20px; } @@ -333,6 +354,7 @@ .gitAddressClone{ + margin:14px 20px!important; display: flex; height: 40px; align-items: center; @@ -404,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; @@ -496,7 +519,7 @@ } .addFile a{ display: block; - background-color: rgb(76, 172, 255,0.8); + background-color: rgba(76, 172, 255,0.8); color: #fff; cursor: pointer; height: 32px; @@ -511,7 +534,7 @@ border-left: 1px solid rgba(247, 247, 247, 0.3); } .addFile a:active{ - background-color: rgb(76, 172, 255,1); + background-color: rgba(76, 172, 255,1); } @@ -550,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; @@ -564,10 +590,28 @@ border-bottom: 1px solid #d9d9d9; border-radius: 4px 4px 0px 0px; } +.readBox{ + border:none; + &.commonBox .commonBox-info{ + border:1px solid #D0D0D0; + border-top: none; + border-radius: 0px 0px 4px 4px; + padding:20px 38px; + } +} +.commonBox .commonBox-title.boxTitle{ + display: flex; + justify-content: space-between; + height: 55px; + line-height: 55px; + background: #FAFCFF; + border-radius: 4px 4px 0px 0px; + border: 1px solid rgba(42, 97, 255, 0.23); +} .synchronism{ display: block; - height: 26px; - line-height: 26px; + height: 34px; + line-height: 34px; padding:0px 15px; color: #fff!important; background-color: #28BD6C; @@ -576,10 +620,19 @@ .files_info{ cursor: pointer; } -.commonBox .commonBox-info{ - padding:20px 15px; +.commonBox { + .commonBox-info{ + padding:20px 15px; + } +} +.commonBox-title-read{ + vertical-align: middle; + color: #000; + font-size: 14px; + &:hover { + color: #466AFF; + } } -.commonBox-title-read{vertical-align: middle;color: #666;} @media screen and (max-width: 370px){ .p-r-tags,.p-r-btn{ @@ -620,9 +673,7 @@ .item:last-child{ border-bottom:none; } -.gitAddressClone{ - margin: 0 !important; -} + .item_title small{ font-weight: 400; margin-left: 10px; @@ -671,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; + } + } } @@ -725,4 +848,13 @@ a.color-grey-ccc:hover{ text-align: center; display: flex; justify-content: center; +} +.depotNum{ + color: #666!important; + span:last-child{ + color: #333; + } + &:hover span:last-child{ + color: #2A61FF; + } } \ No newline at end of file diff --git a/src/forge/Main/sub/Contribute.jsx b/src/forge/Main/sub/Contribute.jsx index a41cb3ed6..76d56dc89 100644 --- a/src/forge/Main/sub/Contribute.jsx +++ b/src/forge/Main/sub/Contribute.jsx @@ -42,7 +42,7 @@ function Contribute(props){
        -

        贡献者列表

        +

        贡献者列表

        { list && list.length > 0 ?
        @@ -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 fbdf5541c..22a5ce419 100644 --- a/src/forge/Main/sub/DetailBanner.jsx +++ b/src/forge/Main/sub/DetailBanner.jsx @@ -1,113 +1,133 @@ import React, { useEffect, useState } from 'react'; -import { Skeleton } from 'antd'; +import { Skeleton , Tooltip} from 'antd'; import { Link } from 'react-router-dom'; +import { numFormat } from 'educoder'; -function DetailBanner({ list , owner , projectsId , isManager , url , pathname , state , urlFlag , projectDetail , platform ,open_devops }){ +function DetailBanner({ history,list , owner , projectsId , isManager , url , pathname , state , urlFlag , projectDetail , platform ,open_devops }){ const [ menuName , setMenuName ] = useState(undefined); useEffect(()=>{ if(list){ + // 没有资源库banner但是通过连接进资源库页面时 + if(pathname && pathname==="source"){ + let a = list.filter(item=>item.menu_name === "resources"); + if(a && a.length === 0){ + history.push(`/${owner}/${projectsId}`); + } + } setMenuName(list); } },[list]); return( -
        +
        { menuName && projectDetail ?
          { - menuName.map((item,key)=>{ + Array.isArray(menuName)&& menuName.map((item,key)=>{ return( - + { item.menu_name === "home" &&
        • - - + + 主页 - +
        • } { item.menu_name === "code" &&
        • - - + + 代码库 - +
        • } { item.menu_name === "issues" &&
        • - - - 易修 (Issue) - {projectDetail && projectDetail.issues_count ? {projectDetail.issues_count} : ""} - + + + + 易修(Issue) + + {projectDetail && projectDetail.issues_count ? {numFormat(projectDetail.issues_count)} : ""} +
        • } { item.menu_name === "pulls" && projectDetail && parseInt(projectDetail.type) !== 2 && platform ?
        • - - + + 合并请求 - {projectDetail && projectDetail.pull_requests_count ? {projectDetail.pull_requests_count} : ""} + {projectDetail && projectDetail.pull_requests_count ? {numFormat(projectDetail.pull_requests_count)} : ""}
        • :"" } + { + item.menu_name === "wiki" && +
        • + + + Wiki + +
        • + } { item.menu_name === "devops" && platform ?
        • - - 工作流(beta版) + {/* */} + + 工作流(beta版) {projectDetail && projectDetail.ops_count ? {projectDetail.ops_count} : ""}
        • :"" } - { - item.menu_name === "source" && + {/* { + item.menu_name === "resources" &&
        • - - - 资源库 - {projectDetail && projectDetail.source_count ? {projectDetail.source_count} :""} + + + 资源库 + {projectDetail && projectDetail.source_count ? {projectDetail.source_count} :""}
        • - } + } */} { item.menu_name === "versions" &&
        • - - - 里程碑 - {projectDetail && projectDetail.versions_count ? {projectDetail.versions_count} :""} + + + 里程碑 + {projectDetail && projectDetail.versions_count ? {numFormat(projectDetail.versions_count)} :""}
        • } { item.menu_name === "activity" &&
        • - - + + 动态
        • } + { + item.menu_name === "settings" && +
        • + + 0 ? "iconfont icon-cangkushezhiicon color-grey-3 mr5 font-14":"iconfont icon-cangkushezhiicon color-grey-6 font-14 mr5"}> + 仓库设置 + +
        • + }
          ) }) } - { - isManager && platform ? -
        • - - 0 ? "iconfont icon-cangku color-grey-3 mr5 font-14":"iconfont icon-cangku color-grey-6 font-14 mr5"}> - 仓库设置 - -
        • :"" - }
        : diff --git a/src/forge/Main/sub/Invite.jsx b/src/forge/Main/sub/Invite.jsx new file mode 100644 index 000000000..201cee6dd --- /dev/null +++ b/src/forge/Main/sub/Invite.jsx @@ -0,0 +1,17 @@ +import React from 'react'; +import './sub.scss'; +import CopyTool from '../../Component/CopyTool'; + +function Invite({code,className}) { + + return( +
        + 邀请码 +
        + + 可以通过邀请码邀请成员加入项目
        点击复制邀请码。

        } className="ml8 font-16" inputId="devitecode"/> +
        +
        + ) +} +export default Invite; \ No newline at end of file diff --git a/src/forge/Main/sub/ReadmeCatelogue.jsx b/src/forge/Main/sub/ReadmeCatelogue.jsx new file mode 100644 index 000000000..6dab7d792 --- /dev/null +++ b/src/forge/Main/sub/ReadmeCatelogue.jsx @@ -0,0 +1,57 @@ +import React , { useState } from 'react'; +import { Anchor , Input } from 'antd'; +import './sub.scss'; +import { useEffect } from 'react'; + +const { Link } = Anchor; + +function ReadmeCatelogue({ menuList , hash }) { + const [ goHref , setGoHref ] = useState(""); + const [ value , setValue ] = useState(""); + const [ menu , setMenu] = useState(menuList); + + + function onChange(link){ + setGoHref(link); + }; + + function changeValue(e) { + setValue(e.target.value); + if(e.target.value){ + let m = menuList.filter(i=>i.text.toLowerCase().indexOf(e.target.value.toLowerCase())>-1); + setMenu(m); + }else{ + setMenu(menuList); + } + } + return( +
        +
        + }/> +
        + { + menu && menu.length>0? +
        + + { + menu.map((item,key)=>{ + return( +
        + +
        + ) + }) + } +
        +
        + :"" + } + +
        + ) +} +export default ReadmeCatelogue; \ No newline at end of file diff --git a/src/forge/Main/sub/SubMenu.jsx b/src/forge/Main/sub/SubMenu.jsx new file mode 100644 index 000000000..78f37b4de --- /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 2d8fe086b..b0291f347 100644 --- a/src/forge/Main/sub/UpdateDescModal.jsx +++ b/src/forge/Main/sub/UpdateDescModal.jsx @@ -2,13 +2,13 @@ import React , { forwardRef, useEffect } from 'react'; import {Form , Modal , Input } from 'antd'; import "./sub.scss"; const { TextArea } = Input; -function UpdateDescModal({form , visible , onCancel , onOk,desc,website}){ +function UpdateDescModal({form , visible , onCancel , onOk,desc,website,lesson_url}){ const { getFieldDecorator, validateFields , setFieldsValue } = form; useEffect(()=>{ if(desc || website){ setFieldsValue({ - website,desc + website,desc,lesson_url }) } },[desc,website]) @@ -17,7 +17,7 @@ function UpdateDescModal({form , visible , onCancel , onOk,desc,website}){ validateFields((err,values)=>{ if(!err){ onCancel(); - onOk(values.desc,values.website) + onOk(values.desc,values.website,values.lesson_url) } }) } @@ -49,6 +49,13 @@ function UpdateDescModal({form , visible , onCancel , onOk,desc,website}){ )} + + {getFieldDecorator("lesson_url",{ + rules:[] + })( + + )} + ) diff --git a/src/forge/Main/sub/sub.scss b/src/forge/Main/sub/sub.scss index 362b9f4e0..7716f0c50 100644 --- a/src/forge/Main/sub/sub.scss +++ b/src/forge/Main/sub/sub.scss @@ -1,11 +1,13 @@ .boxPanel{ width: 1200px; - margin:0px auto; - padding:20px 0px; + margin:20px auto; + border-radius: 4px; + border:1px solid #eee; min-height: 500px; .contrbuteList{ display: flex; flex-wrap: wrap; + padding:20px; & > div{ width: 20%; } @@ -20,4 +22,70 @@ height: 20px; line-height: 20px; } +} + +.menuslist{ + z-index: 100; + width: 297px; + background: #FFFFFF; + box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5); + border-radius: 4px; + .searchBox{ + padding:15px; + border-bottom: 1px solid #eee; + } + .ant-anchor-wrapper{ + margin-left: 0px; + padding:5px 15px; + max-height: 255px!important; + .items{ + border-radius: 4px; + margin-bottom: 5px; + cursor: pointer; + .ant-anchor-link-title{ + color: #333333!important; + } + &:hover{ + background-color: #F3F4F6; + } + &.active{ + background-color: #2A61FF; + .ant-anchor-link-title{ + color: #fff!important; + } + } + } + .ant-anchor-link{ + padding:0px; + height: 30px; + line-height: 30px; + } + .ant-anchor-ink::before{ + 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 000000000..ff7648513 --- /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 000000000..6adba91e3 --- /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 000000000..2fc574349 --- /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 000000000..f65a1c68f --- /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 000000000..3200d3e8f --- /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 000000000..37cc8c128 --- /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 000000000..8adde9b01 --- /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 000000000..2896899fc --- /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 000000000..7cd5ddb46 --- /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 37c254cc9..93e867ae2 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 000000000..d7a320099 --- /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 40e617c2a..b4cf5b488 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 new file mode 100644 index 000000000..16cc95632 --- /dev/null +++ b/src/forge/Merge/Index.scss @@ -0,0 +1,103 @@ +.i_open{ + color: #28BD6C!important; +} +.i_merged{ + color: #4C9ED3!important; +} +.i_closed{ + color: #FA6400!important; +} +.pr_tags_open{ + border:1px solid #28BD6C; + color: #28BD6C; +} +.pr_tags_merged{ + border:1px solid #4C9ED3; + color: #4C9ED3; +} +.pr_tags_closed{ + border:1px solid #FA6400; + color: #FA6400; +} +.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 a7e2f33e1..11bd3858b 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 0873f5da9..61477c142 100644 --- a/src/forge/Merge/MergeItem.js +++ b/src/forge/Merge/MergeItem.js @@ -5,6 +5,12 @@ import { AlignCenter } from '../Component/layout'; import { getImageUrl } from "educoder"; import "./merge.css"; +function turnbar(str){ + if(str && str.length>0 && str.indexOf("/")>-1){ + return str.replaceAll('/','%2F'); + } + return str; +} class MergeItem extends Component { constructor(props) { super(props); @@ -43,34 +49,36 @@ class MergeItem extends Component { }; render() { - const { issues, project_name, project_author_name } = 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 = () => { if (issues && issues.length > 0) { return issues.map((item, key) => { + let status = item.pull_request_staus; return (

        + {item.name} - - {item.pull_request_staus === "merged" + + {status === "merged" ? "已合并" - : item.pull_request_staus === "closed" + : status === "closed" ? "已拒绝" : "开启的"}

        {item && item.author_name} @@ -97,33 +105,43 @@ class MergeItem extends Component { {item.pr_time} - - - {item.is_original - ? item.fork_project_user - : project_author_name} - :{item.pull_request_head} - - - - - - - - {/* {item.is_fork ? item.pull_request_base : `${item.author_name}:${item.pull_request_base}`} */} - {project_author_name}:{item.pull_request_base} - - + { + item.pull_request_head && + + + {item.is_original + ? item.fork_project_user + : project_author_name} + :{item.pull_request_head} + + + } + { + item.pull_request_base && + + + + } + { + 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} + + + } +

        @@ -138,7 +156,7 @@ class MergeItem extends Component {
      • {item.assign_user_name ? ( {item.assign_user_name} @@ -157,7 +175,7 @@ class MergeItem extends Component { {item.journals_count ? ( {item.journals_count} @@ -165,7 +183,7 @@ class MergeItem extends Component { ) : ( "" )} - {current_user && current_user.login ? ( + {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 000000000..2c9aa4814 --- /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 8f2275d81..d4b42c3b4 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 85333aaf3..6d01e8a37 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,11 +17,16 @@ 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){ + if(str && str.length>0 && str.indexOf("/")>-1){ + return str.replaceAll('/','%2F'); + } + return str; +} class MessageCount extends Component { constructor(props) { super(props); @@ -41,6 +44,7 @@ class MessageCount extends Component { edit_spin: false, pr_status: undefined, pull_request:undefined, + conflict_files:[], copyVisible:false, }; @@ -54,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; @@ -75,7 +84,8 @@ class MessageCount extends Component { data: result.data, SpinFlag: false, pr_status: result.data.pull_request && result.data.pull_request.status, - pull_request:result.data.pull_request + pull_request:result.data.pull_request, + conflict_files:result.data.conflict_files }); } else { this.setState({ SpinFlag: false }); @@ -102,6 +112,8 @@ class MessageCount extends Component { isSpin: false, pr_status: 2, }); + const { getDetail } = this.props; + getDetail && getDetail(); } else { this.setState({ isSpin: false, @@ -138,6 +150,10 @@ class MessageCount extends Component { SpinMerge: false, pr_status: 1, }); + const { getDetail } = this.props; + getDetail && getDetail(); + // 调用子组件的方法刷新评论列表 + this.footRef && this.footRef.refreshComment(); } else { this.setState({ SpinMerge: false }); } @@ -241,6 +257,49 @@ class MessageCount extends Component { ) } + // 点击按钮复制功能 + jsCopy = () => { + const copyEle = document.querySelector('#descContent') // 获取要复制的节点 + const range = document.createRange(); // 创造range + window.getSelection().removeAllRanges(); //清除页面中已有的selection + range.selectNode(copyEle); // 选中需要复制的节点 + window.getSelection().addRange(range); // 执行选中元素 + document.execCommand("Copy"); // 执行copy操作 + } + + mergeabledMes=()=>{ + return( +
        +

        该分支存在冲突,无法自动合并,你可以尝试通过如下命令手动合并

        + this.jsCopy()}> +
        + ) + } + mergeabledDesc=(base,head,conflict_files)=>{ + return( +
        +
          +
        • git fetch origin
        • +
        • git checkout -b {`${base}`} origin/{`${base}`}
        • +
        • git merge {`${head}`}
        • +
        + { + conflict_files && conflict_files.length>0 && +
        +

        如下文件有代码冲突:

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

        {i}

        + }) + } +
        +
        + } +
        + ) + } + render() { const { projectsId, mergeId , owner } = this.props.match.params; @@ -252,7 +311,8 @@ class MessageCount extends Component { ismesrge, SpinFlag, copyVisible, - pull_request + pull_request, + conflict_files } = this.state; const { current_user, projectDetail } = this.props; const menu = ( @@ -280,11 +340,11 @@ class MessageCount extends Component {
        -
        -
        +
        +
        - + {data.issue.subject} @@ -305,10 +365,10 @@ class MessageCount extends Component {
        - {data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}:{data.pull_request.head} + {data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}: {data.pull_request && data.pull_request.head} @@ -320,10 +380,9 @@ class MessageCount extends Component { - {/* {data.pull_request.is_fork ? data.pull_request.base : `${data.pull_request.pull_request_user}:${data.pull_request.base}`} */} {data.issue.project_author_name}:{data.pull_request.base} @@ -331,14 +390,14 @@ class MessageCount extends Component { }
        - + - + {data.issue.author_name} @@ -353,7 +412,7 @@ class MessageCount extends Component { 审查人员: {data.issue.assign_user_name ? ( {data.issue.assign_user_name} @@ -369,7 +428,7 @@ class MessageCount extends Component { - 标签: + 标记: {data.issue.issue_tags && data.issue.issue_tags.length > 0 @@ -386,20 +445,13 @@ class MessageCount extends Component {
        -
        -
        - {/* - this.setCopyVisible(e)}> - 复制 - - 下载为 - */} +
        {operate && ( @@ -416,7 +468,6 @@ class MessageCount extends Component { )}
        -
        { data.issue.description ? @@ -440,35 +491,40 @@ class MessageCount extends Component { type="success" /> )} - {pr_status === 0 && projectDetail && projectDetail.permission !=="Reporter" && ( + {operate && (
        -

        - } - > - {this.state.mergename} - -

        - + } + disabled={!pull_request || (pull_request && !pull_request.mergeable) } + > + {this.state.mergename} + + {pull_request && pull_request.mergeable + ? + : + + }
        -

        @@ -504,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 1ba7960ab..900dea824 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); @@ -42,13 +47,16 @@ class NewMerge extends Component { componentDidUpdate=(preProps)=>{ const { project } = this.props; + const { pull } = this.state; let oldProject = preProps.project; if(project && oldProject && (oldProject.id !== project.id)){ - this.compareProject(this.state.id,"master","master"); + this.compareProject(this.state.id,pull,"master"); } } + // 页面销毁取消监听 componentWillUnmount () { + console.log('----------destoyed---------'); window.removeEventListener('popstate', this.handleBack, false); }; @@ -59,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) @@ -78,7 +89,8 @@ class NewMerge extends Component { this.set_default_pull(result.data.branches); this.set_default_merge(result.data.merge_projects); } - this.compareProject(result.data.id,"master","master"); + const { pull } = this.state; + this.compareProject(result.data.id,pull||"master","master"); this.setState({isSpin: false}) }) .catch((error) => { @@ -103,13 +115,28 @@ 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) { + this.setState({ + isSpin: false, + show_message: false, + }); + } else { + this.setState({ + isSpin: false, + show_message: true, + default_message: result.data.message, + }); + } this.setState({ comparesData:result.data }) } - }).catch(error=>{}) + }).catch(error=>{ + this.setState({isSpin: false}); + }) } } @@ -143,7 +170,7 @@ class NewMerge extends Component { merge:"master" }) } - this.ischeckmerge(); + // this.ischeckmerge(); } } @@ -169,10 +196,10 @@ class NewMerge extends Component { selectBrach = (type, value) => { const { projectsId , owner } = this.props.match.params; this.state[type] = value; - this.ischeckmerge(); + // 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); @@ -194,12 +221,11 @@ 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); }; //判断2分支是否可以合并 - ischeckmerge = () => { this.setState({ isSpin: true }); const { projectsId , owner } = this.props.match.params; @@ -251,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) => { @@ -285,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 8ed8034af..8918db6eb 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 6b50eeb10..d61543b49 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 be1ec97c4..8a0eaedea 100644 --- a/src/forge/Merge/merge.js +++ b/src/forge/Merge/merge.js @@ -4,9 +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; /** @@ -37,17 +39,17 @@ class merge extends Component { // page: 1, search_count: undefined, issue_type: undefined, - status_type: undefined, + status_type: "1", //设置选择高亮 openselect: 1, closeselect: undefined, - issue_tag_ids: "标签", + issue_tag_ids: "标记", fixed_version_ids: "里程碑", assigned_to_ids: "审查人员", paix: "排序", priority_ids: "优先级", select_params: { - status_type: undefined, //开启中和关闭中,默认为开启中的 + status_type: "1", //开启中和关闭中,默认为开启中的 assigned_to_id: undefined, // 指派人 fixed_version_id: undefined, priority_id: undefined, @@ -154,18 +156,14 @@ class merge extends Component { renderMenu = (array, name, id) => { return ( - + this.getOption(e, id, name)}> {name} - {array && - array.length > 0 && - array.map((item, key) => { + {array && array.length > 0 && array.map((item, key) => { return ( - this.getOption(e, id, item.name)} - > + ((!item.permission) || (item.permission && item.permission !== "Reporter")) && + this.getOption(e, id, item.name)}> {item.name} ); @@ -200,29 +198,22 @@ class merge extends Component { }); this.setState({ status_type: type, - issue_tag_ids: "标签", + issue_tag_ids: "标记", fixed_version_ids: "里程碑", assigned_to_ids: "审查人员", paix: "排序", priority_ids: "优先级", }); - this.state.select_params = { - status_type: type, - search: undefined, - page: 1, - limit: 15, - }; + this.state.select_params.status_type = type; + this.state.select_params.page=1; + this.state.select_params.limit=15; + this.getIssueList(); }; - islogin() { + checkOperation() { const { projectsId,owner } = this.props.match.params; - if (this.props.checkIfLogin() === false) { - this.props.showLoginDialog(); - return; - } else { - 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; @@ -253,24 +244,6 @@ class merge extends Component { ); - - const Paginations = ( - - {search_count > limit ? ( -
        - -
        - ) : ( - "" - )} -
        - ); return (
        @@ -282,9 +255,12 @@ class merge extends Component { style={{ width: 300 }} />
        - this.islogin()}> - + 新建合并请求 - + { + data && data.user_admin_or_developer && + this.checkOperation()}> + + 新建合并请求 + + }
        @@ -300,6 +276,7 @@ class merge extends Component { className={status_type === "1" ? "active" : ""} onClick={() => this.openorder("1")} > + {data && data.open_count}
      • @@ -307,6 +284,7 @@ class merge extends Component { className={status_type === "11" ? "active" : ""} onClick={() => this.openorder("11")} > + {data && data.merged_issues_size} @@ -314,6 +292,7 @@ class merge extends Component { className={status_type === "2" ? "active" : ""} onClick={() => this.openorder("2")} > + {data && data.close_count} @@ -342,7 +321,7 @@ class merge extends Component { className="topWrapperSelect" overlay={this.renderMenu( issue_chosen && issue_chosen.issue_tag, - "标签", + "标记", "issue_tag_id" )} trigger={["click"]} @@ -409,7 +388,7 @@ class merge extends Component { {data && data.search_count && data.search_count > 0 ? (
        - - {Paginations} + user_admin_or_developer={data && data.user_admin_or_developer} + >
        ):""} + {search_count > select_params.limit ? ( +
        + +
        + ) : ( + "" + )} { data && data.issues && data.issues.length === 0 ? :""}
        diff --git a/src/forge/Merge/merge_footer.js b/src/forge/Merge/merge_footer.js index 6502827cd..868e736fe 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 1c75a9f9a..e63781391 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 { })( )} @@ -346,19 +346,21 @@ class MergeForm extends Component { )} - - -
        - 必须审查代码 -
        -
        - 合并后删除提交分支 -
        -
        - 合并后关闭提到的任务 -
        -
        -
        + {/* + {getFieldDecorator("checkbox-group")( + +
        + 必须审查代码 +
        +
        + 合并后删除提交分支 +
        +
        + 合并后关闭提到的任务 +
        +
        + )} +
        */}
        diff --git a/src/forge/Merge/no_data.js b/src/forge/Merge/no_data.js index 8ad550abe..d5e4ca89b 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 381d74382..e9aa1f952 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()){ @@ -68,24 +76,28 @@ 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){ let owner = result.data.owners; - if(OIdentifier){ - owner = owner.filter(item=>item.name === OIdentifier); - this.props.form.setFieldsValue({ - user_id:OIdentifier - }) - owner && this.setState({ - owners_id:owner[0].id, - owners_name:owner[0].name - }) - } - this.setOptionsList(owner, 'owners'); this.setState({ OwnerList: owner, }) + if(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 + }) + owner && this.setState({ + owners_id:owner[0].id, + owners_name:owner[0].name + }) + this.setOptionsList(owner, 'owners'); } }).catch(error=>{}) } @@ -138,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) { @@ -158,37 +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) { - if (result.data.id) { - this.setState({ - isSpin: false - }) - this.props.showNotification(`${projectsType && projectsType === "mirror" ? "镜像" : "托管"}项目创建成功!`); - this.props.history.push(`/projects/${owners_name}/${result.data.identifier}`); - } + if (result && result.data.id) { + 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({ @@ -245,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 + }) } } } @@ -283,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

        @@ -332,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')( @@ -505,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 fcb6fa8cf..15aca70b2 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 56eae752d..953f50720 100644 --- a/src/forge/Newfile/Index.js +++ b/src/forge/Newfile/Index.js @@ -65,15 +65,18 @@ class Index extends Component {
        - +
        + +
        diff --git a/src/forge/Newfile/UserSubmitComponent.js b/src/forge/Newfile/UserSubmitComponent.js index 6c921c9fc..aa4bba6e9 100644 --- a/src/forge/Newfile/UserSubmitComponent.js +++ b/src/forge/Newfile/UserSubmitComponent.js @@ -6,6 +6,20 @@ import "./index.css"; import axios from "axios"; const TextArea = Input.TextArea; + + +function turnbar(str){ + if(str && str.length>0 && str.indexOf("/")>-1){ + return str.replaceAll('/','%2F'); + } + return str; +} +function returnbar(str){ + if(str && str.length>0 && str.indexOf("%2F")>-1){ + return str.replaceAll('%2F','/'); + } + return str; +} class UserSubmitComponent extends Component { constructor(props) { super(props); @@ -16,6 +30,24 @@ class UserSubmitComponent extends Component { }; } + componentDidMount=()=>{ + const { descName } = this.props; + if(descName){ + this.props.form.setFieldsValue({ + desc:descName + }) + } + } + + componentDidUpdate=(preProps)=>{ + const { descName } = this.props; + if(preProps && descName && preProps.descName !== descName ){ + this.props.form.setFieldsValue({ + desc:descName + }) + } + } + changeSubmittype = (e) => { this.setState({ submitType: e.target.value, @@ -41,7 +73,7 @@ class UserSubmitComponent extends Component { const url = `/${owner}/${projectsId}/create_file.json`; axios.post(url, { filepath: filename ? filename : path, - branch: branch, + branch: returnbar(branch), new_branch: submitType === "1" ? values.branchname : undefined, content, message: values.desc, @@ -51,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/${values.branchname}`: (branch ? `/tree/${branch}` : "")}`; + let url = `/${owner}/${projectsId}${values.branchname ? `/tree/${turnbar(values.branchname)}`: (branch ? `/tree/${turnbar(branch)}` : "")}`; this.props.history.push(url); } }) @@ -75,12 +107,13 @@ class UserSubmitComponent extends Component { const { projectsId , owner } = this.props.match.params; const { submitType } = this.state; const url = `/${owner}/${projectsId}/update_file.json`; + let b = currentBranch || branch; this.props.form.validateFieldsAndScroll((err, values) => { if (!err) { axios .put(url, { filepath: detail.path, - branch: submitType === "1" ? undefined : (currentBranch || branch), + branch: submitType === "1" ? undefined : returnbar(b), new_branch: submitType === "1" ? values.branchname : undefined, content: content, sha: detail.sha, @@ -89,7 +122,8 @@ class UserSubmitComponent extends Component { .then((result) => { this.setState({ isSpin: false }); if (result.data && result.data.status === 1) { - let url = `/projects/${owner}/${projectsId}${(values.branchname ? `/tree/${values.branchname}` : ((currentBranch || branch) ? `/tree/${currentBranch || branch}`:""))}`; + let b = currentBranch || branch; + let url = `/${owner}/${projectsId}${(values.branchname ? `/tree/${turnbar(values.branchname)}` : (b ? `/tree/${turnbar(b)}`:""))}`; this.props.history.push(url); this.props.showNotification("文件修改成功!"); } @@ -112,10 +146,12 @@ class UserSubmitComponent extends Component { const { current_user, filepath, projectDetail , currentBranch } = this.props; const { editor_type } = this.props; + let b = currentBranch || branch; + return (
        - + - 直接提交至{currentBranch || branch}分支 + 直接提交至{returnbar(b)}分支 @@ -213,7 +249,7 @@ class UserSubmitComponent extends Component {
        diff --git a/src/forge/Nodata.js b/src/forge/Nodata.js index 3147e5601..ccc74ac54 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 new file mode 100644 index 000000000..aeacd67a2 --- /dev/null +++ b/src/forge/Notice/Apply.jsx @@ -0,0 +1,114 @@ +import React, { useEffect , useState } from 'react'; +import Axios from 'axios'; +import { Pagination , Spin , Popconfirm }from 'antd'; +import { Link } from 'react-router-dom'; +import { getImageUrl } from 'educoder'; +import Nodata from '../Nodata'; +import { FlexAJ } from '../Component/layout'; + +const limit = 15; +function Apply(props) { + const username = props.match.params.username; + const [ list , setList ] = useState(undefined); + const [ page , setPage ] = useState(1); + const [ total , setTotal ] = useState(0); + const [ isSpin , setIsSpin ] = useState(true); + + useEffect(()=>{ + if(username){ + setIsSpin(true); + getList(); + } + },[username]) + + function getList() { + const url = `/users/${username}/applied_projects.json`; + Axios.get(url).then(result=>{ + if(result){ + setList(result.data.applied_projects); + setTotal(result.data.total_count); + setIsSpin(false); + } + }).catch(error=>{}) + } + + // 接受 + function acceptDivert(id){ + const url = `/users/${username}/applied_projects/${id}/accept.json`; + Axios.post(url).then(result=>{ + if(result && result.data){ + getList(); + props && props.deleteEvent("apply",1); + } + }).catch(error=>{}) + } + + // 拒绝 + function revertDivert(id){ + const url = `/users/${username}/applied_projects/${id}/refuse.json`; + Axios.post(url).then(result=>{ + if(result && result.data){ + getList(); + props && props.deleteEvent("apply",1); + } + }).catch(error=>{}) + } + return( +
        + +
        + { + list && list.length > 0 ? +
          + { + list.map((i,k)=>{ + return( +
        • + +
          +

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

          + +

          申请以【{i.role === "developer" ?"开发者":i.role === "manager" ? "管理者":"报告者"}】身份加入【{i.project && i.project.name}】项目。是否同意?

          + { + i.status === "common" && + + acceptDivert(i.id)}> + 同意 + + revertDivert(i.id)}> + 拒绝 + + + } + { + i.status === "accepted" && 已接受 + } + { + i.status === "refused" && 已拒绝 + } +
          +
          +
        • + ) + }) + } +
        + : + "" + } + {list && list.length === 0 && } + { + total > limit && +
        + {setPage(p)}}/> +
        + } +
        +
        +
        + ) +} +export default Apply; \ No newline at end of file diff --git a/src/forge/Notice/Index.jsx b/src/forge/Notice/Index.jsx index d9d04d59e..73a2561bd 100644 --- a/src/forge/Notice/Index.jsx +++ b/src/forge/Notice/Index.jsx @@ -6,8 +6,8 @@ import Loadable from "react-loadable"; import Loading from "../../Loading"; import { Route, Switch } from "react-router-dom"; -const Notify = Loadable({ - loader: () => import("./Notify"), +const Apply = Loadable({ + loader: () => import("./Apply"), loading: Loading, }); const UndoEvent = Loadable({ @@ -18,67 +18,87 @@ function Index(props){ const username = props.match.params.username; const pathname = props.history.location.pathname; const user = props.user; - const undo_messages = props.undo_messages; - const [ menu , setMenu ] = useState("notify"); - const [ messages , setMessages ] = useState(0); - const [ transferProjects , setTransferProjects ] = useState(0); + const [ menu , setMenu ] = useState("undo"); + const [ messagesCount , setMessagesCount ] = useState(0); + const [ transferCount , setTransferCount ] = useState(0); + const [ applyCount , setApplyCount ] = useState(0); + + const [ flag , setFlag ] = useState(true); + const { current_user } = props; + + useEffect(()=>{ + if((username && current_user && (current_user.login !== username))){ + props.history.push(`/${username}`); + } + },[current_user,username]) useEffect(()=>{ if(user){ - setTransferProjects(user.undo_transfer_projects); + setTransferCount(user.undo_transfer_projects); + setApplyCount(user.undo_join_projects); + setMessagesCount(user.undo_messages); } - if(undo_messages){ - setMessages(undo_messages); - } - },[user,undo_messages]) + },[user]) useEffect(()=>{ if(pathname && username){ - if(pathname === `/users/${username}/notice`){ - setMenu("notify"); - } - if(pathname === `/users/${username}/notice/undo`){ + if(pathname === `/${username}/notice`){ setMenu("undo"); } + if(pathname === `/${username}/notice/apply`){ + setMenu("apply"); + } } - },[pathname]) - - function fetchUser(){ - props && props.fetchUser(); - } + },[pathname,user]) function changeNum(){ - fetchUser(); + if(flag){ + messagesCount && props.deleteUndoEvent(messagesCount); + setFlag(false); + } + } + + function deleteEvent(type,count) { + let c = count; + if(type==="apply"){ + setApplyCount(applyCount-count); + }else if(type==="undo"){ + setTransferCount(transferCount-count); + }else{ + setMessagesCount(0); + c = messagesCount; + } + (c || c===0) && props.deleteUndoEvent(c); } return (
          -
        • - - 通知 - {messages ? {messages}:""} +
        • + + 接收仓库 + {transferCount ? {transferCount}:""}
        • -
        • - - 接收仓库 - {transferProjects ? {transferProjects}:""} +
        • + + 成员申请 + {applyCount ? {applyCount}:""}
        { - return ; + return ; }} > { - return ; + return ; }} > diff --git a/src/forge/Notice/Index.scss b/src/forge/Notice/Index.scss index a50c34131..b00e18a5a 100644 --- a/src/forge/Notice/Index.scss +++ b/src/forge/Notice/Index.scss @@ -26,7 +26,7 @@ min-width: 23px; text-align: center; background-color: #ffe4b3; - margin-top: 19px; + margin-top: 27px; margin-left: 10px; display: block; } diff --git a/src/forge/Notice/Notify.jsx b/src/forge/Notice/Notify.jsx index 3aad55ae5..313739089 100644 --- a/src/forge/Notice/Notify.jsx +++ b/src/forge/Notice/Notify.jsx @@ -13,6 +13,10 @@ function Notify(props){ const [ total , setTotal ] = useState(0); const [ isSpin , setIsSpin ] = useState(true); + useEffect(()=>{ + props && props.deleteEvent("notify",0); + },[]) + useEffect(()=>{ if(username){ setIsSpin(true); @@ -40,13 +44,27 @@ 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}】

        - case 'successed': - return

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

        + return

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

        + case 'successed': + return

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

        default: - return

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

        + return

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

        + } + }else{ + return "" + } + } + + function renderApplyStatus(status,applied) { + let { project } = applied; + if(status){ + switch(status){ + case 'successed': + return

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

        + default: + return

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

        } }else{ return "" @@ -62,15 +80,16 @@ 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}

          - {renderStatus(i.status,i.applied)} + { 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 68557a9e9..17dcc3216 100644 --- a/src/forge/Notice/UndoEvent.jsx +++ b/src/forge/Notice/UndoEvent.jsx @@ -42,7 +42,7 @@ function UndoEvent(props){ Axios.post(url).then(result=>{ if(result && result.data){ getList(); - props && props.fetchUser(); + props && props.deleteEvent("undo",1); } }).catch(error=>{}) } @@ -53,7 +53,7 @@ function UndoEvent(props){ Axios.post(url).then(result=>{ if(result && result.data){ getList(); - props && props.fetchUser(); + 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 1f61e7369..906de4be7 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 277f5d4ab..4d1b47cfc 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} @@ -249,7 +252,7 @@ class Detail extends Component { 添加于 {data && data.created_at} {data && data.user_permission ? ( - + 复制 @@ -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 0ae88ddf3..48fc286ba 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; @@ -89,8 +90,9 @@ class Milepost extends Component { closeselect: status === "closed" ? current_user.user_id : undefined, openselect: status === "closed" ? undefined : current_user.user_id }) - - this.getList(1, status, 'desc') + this.getList(1, status, 'desc'); + const { getDetail } = this.props; + getDetail && getDetail(); } }).catch(error => { console.log(error); @@ -107,7 +109,9 @@ class Milepost extends Component { } }).then((result) => { if (result) { - this.getList(1, this.state.status, 'desc') + this.getList(1, this.state.status, 'desc'); + const { getDetail } = this.props; + getDetail && getDetail(); } }).catch((error) => { console.log(error); @@ -115,11 +119,12 @@ class Milepost extends Component { } ChangePage = (page) => { + document.body.scrollIntoView(); this.setState({ page }) - - this.getList(page); + const { status } = this.state; + this.getList( page , status ); } // 排序 @@ -150,11 +155,11 @@ class Milepost extends Component { const { data, limit, page, openselect, closeselect, spinings } = this.state; const { projectsId , owner } = this.props.match.params; const menu = ( -

            - 到期日从近到远 - 到期日从远到近 - 完成度从低到高 - 完成度从高到低 + + 到期日从后到先 + 到期日从先到后 + 完成度从低到高 + 完成度从高到低 任务从多到少 任务从少到多 @@ -184,7 +189,7 @@ class Milepost extends Component {
          { data && data.user_admin_or_member ? - 新的里程碑 + {this.props.history.push(`/${owner}/${projectsId}/milestones/new`)}}>新的里程碑 : '' }
          @@ -201,7 +206,7 @@ class Milepost extends Component {
          - {item.name} + {item.name}
          @@ -225,11 +230,11 @@ class Milepost extends Component {
          - 编辑 + 编辑
          @@ -256,7 +261,7 @@ class Milepost extends Component { { data && data.versions_count > limit ?
          - +
          : "" }
          diff --git a/src/forge/Order/MilepostDetail.js b/src/forge/Order/MilepostDetail.js index 7954630dd..0f5d191e0 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: '负责人', @@ -69,6 +70,27 @@ class MilepostDetail extends Component { }) } + deletedetail = (id) => { + const { projectsId , owner } = this.props.match.params; + const url = `/${owner}/${projectsId}/issues/${id}.json`; + axios.delete(url, { + data: { + project_id: projectsId, + id: id, + }, + }) + .then((result) => { + if (result) { + const { page } = this.state; + this.getIssueList(page); + const { getDetail } = this.props; + getDetail && getDetail(); + } + }) + .catch((error) => { + console.log(error); + }); + }; // 获取列表数据 getIssueList = ( page , item , value , update , updateValue , type ) => { const { projectsId, meilid , owner } = this.props.match.params; @@ -92,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 }) } @@ -141,7 +163,7 @@ class MilepostDetail extends Component { renderMenu = (array, name, id) => { return ( - + this.getOption(e, id, name)}>{name} { array && array.length > 0 && array.map((item, key) => { @@ -172,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: '负责人', @@ -217,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">创建易修
          @@ -232,7 +254,7 @@ class MilepostDetail extends Component {
        • - + {this.state.issue_tag_ids}
        • @@ -275,7 +297,15 @@ class MilepostDetail extends Component { : issues && issues.length>0 && issues.map((item,key)=>{ return( - + ) }) } diff --git a/src/forge/Order/Milepostitem.js b/src/forge/Order/Milepostitem.js index 48bf65c11..d79c66fea 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 93fbc1011..3f5a20c59 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 150b95d2a..081788641 100644 --- a/src/forge/Order/OrderItem.js +++ b/src/forge/Order/OrderItem.js @@ -42,17 +42,17 @@ class OrderItem extends Component { }) } render() { - const { item , checkbox , mile } = this.props; + const { item , checkbox , mile , user_admin_or_member } = this.props; const { projectsId , owner } = this.props.match.params; - const { current_user } = this.props - + const { orderid , isdisplay } = this.state; + const { current_user } = this.props; return ( item &&
        {current_user && current_user.login && checkbox}

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

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

      • { item.author_name ? - + {item.author_name} : "--" @@ -77,7 +77,7 @@ class OrderItem extends Component {
      • { item.assign_user_name ? - + {item.assign_user_name} : "--" @@ -89,15 +89,24 @@ class OrderItem extends Component {
      • {item.done_ratio || "--"}
      • - {item.journals_count} + {item.journals_count} { - current_user && current_user.login ? -
        + user_admin_or_member ? +
        - + + +
        - this.deletedetail(item.id)}> + this.deletedetail(item.id)} + >
        diff --git a/src/forge/Order/Tags.js b/src/forge/Order/Tags.js index 174891aa6..eeff8db28 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 9cbb3cd64..0bf4f0f13 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 49a2b8d32..c4f386575 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`); } @@ -180,8 +180,8 @@ class UpdateMilepost extends Component { onTypeChange(e.target.value)} value={type}> - - + + diff --git a/src/forge/Order/newMilepost.js b/src/forge/Order/newMilepost.js index 965e5a6a7..b7d1102dd 100644 --- a/src/forge/Order/newMilepost.js +++ b/src/forge/Order/newMilepost.js @@ -63,7 +63,9 @@ 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(); } }).catch(error => { this.setState({ isSpin: false }) @@ -100,7 +102,7 @@ class NewMilepost extends Component { required: true, message: '请输入标题' }], })( - + )}
        @@ -111,7 +113,7 @@ class NewMilepost extends Component { required: true, message: '请输入描述内容' }], })( -