Compare commits

...

19 Commits

Author SHA1 Message Date
caishi 0d0b164370 Merge branch 'develop' of https://git.trustie.net/jasder/forgeplus-react into develop 2021-08-23 10:15:55 +08:00
caishi ec84ed56b0 reset 2021-08-23 10:15:32 +08:00
caishi 466ed1fe1b Merge branch 'pre_develop' into develop
# Conflicts:
#	public/css/iconfont.css
#	public/css/iconfont.js
#	public/css/iconfont.ttf
#	public/css/iconfont.woff
#	public/css/iconfont.woff2
2021-08-23 10:09:00 +08:00
caishi 9b101403a1 里程碑-切换分页需要带上状态参数 2021-08-23 10:08:04 +08:00
jasder fb872f3a3d change request url 2021-08-20 09:06:57 +08:00
何童崇 19ef012a0e 修改指向路径 2021-08-20 09:01:40 +08:00
jasder b3d62b9cf1 FIX bug 2021-08-19 21:54:56 +08:00
何童崇 d988c4ea5f 兼容页面刷新时的id新增 2021-08-19 21:23:48 +08:00
caishi 313f1edc71 镜像问题websocket传值
镜像问题websocket传值
2021-08-19 17:44:13 +08:00
caishi 8adc662e9b wiki功能分支合并
wiki功能分支合并
2021-08-19 17:31:36 +08:00
何童崇 ff75065a0a 新增wiki模块 2021-08-19 17:21:18 +08:00
何童崇 6e74f88d9e 紧急修复镜像bug 2021-08-19 10:40:44 +08:00
caishi 6beb4c2c8a 修复镜像项目时的展示问题
修复镜像项目时的展示问题
2021-08-18 14:43:28 +08:00
何童崇 e8dadb187b 紧急修复镜像bug 2021-08-18 14:38:11 +08:00
caishi 3a1fd14e7c 代码库-样式 2021-08-13 17:12:56 +08:00
caishi 20f64bdf81 md fullscreen 2021-08-12 17:36:37 +08:00
caishi 2347d04710 同上-细节修改 2021-08-12 15:24:45 +08:00
caishi d13d94e9cf 代码库样式整改 2021-08-12 11:45:56 +08:00
caishi 3294d99516 href 2021-08-09 11:03:49 +08:00
59 changed files with 3266 additions and 690 deletions

54
package-lock.json generated
View File

@ -1273,7 +1273,7 @@
}, },
"babel-cli": { "babel-cli": {
"version": "6.26.0", "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=", "integrity": "sha1-UCq1SHTX24itALiHoGODzgPQAvE=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -1296,7 +1296,7 @@
"dependencies": { "dependencies": {
"chokidar": { "chokidar": {
"version": "1.7.0", "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=", "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -1314,7 +1314,7 @@
}, },
"source-map": { "source-map": {
"version": "0.5.7", "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=", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true "dev": true
} }
@ -1413,7 +1413,7 @@
}, },
"babel-helper-bindify-decorators": { "babel-helper-bindify-decorators": {
"version": "6.24.1", "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=", "integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -1476,7 +1476,7 @@
}, },
"babel-helper-explode-class": { "babel-helper-explode-class": {
"version": "6.24.1", "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=", "integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -1676,7 +1676,7 @@
}, },
"babel-plugin-syntax-async-generators": { "babel-plugin-syntax-async-generators": {
"version": "6.13.0", "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=", "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=",
"dev": true "dev": true
}, },
@ -1687,7 +1687,7 @@
}, },
"babel-plugin-syntax-decorators": { "babel-plugin-syntax-decorators": {
"version": "6.13.0", "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=", "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=",
"dev": true "dev": true
}, },
@ -1723,7 +1723,7 @@
}, },
"babel-plugin-transform-async-generator-functions": { "babel-plugin-transform-async-generator-functions": {
"version": "6.24.1", "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=", "integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -1755,7 +1755,7 @@
}, },
"babel-plugin-transform-decorators": { "babel-plugin-transform-decorators": {
"version": "6.24.1", "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=", "integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -2060,7 +2060,7 @@
}, },
"babel-plugin-transform-runtime": { "babel-plugin-transform-runtime": {
"version": "6.23.0", "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=", "integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=",
"requires": { "requires": {
"babel-runtime": "^6.22.0" "babel-runtime": "^6.22.0"
@ -2077,7 +2077,7 @@
}, },
"babel-polyfill": { "babel-polyfill": {
"version": "6.26.0", "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=", "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
"requires": { "requires": {
"babel-runtime": "^6.26.0", "babel-runtime": "^6.26.0",
@ -2087,7 +2087,7 @@
"dependencies": { "dependencies": {
"regenerator-runtime": { "regenerator-runtime": {
"version": "0.10.5", "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", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
"integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg="
} }
} }
@ -2131,7 +2131,7 @@
}, },
"babel-preset-es2015": { "babel-preset-es2015": {
"version": "6.24.1", "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=", "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -2179,7 +2179,7 @@
}, },
"babel-preset-react": { "babel-preset-react": {
"version": "6.24.1", "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=", "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=",
"requires": { "requires": {
"babel-plugin-syntax-jsx": "^6.3.13", "babel-plugin-syntax-jsx": "^6.3.13",
@ -2212,7 +2212,7 @@
}, },
"babel-preset-stage-2": { "babel-preset-stage-2": {
"version": "6.24.1", "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=", "integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -2224,7 +2224,7 @@
}, },
"babel-preset-stage-3": { "babel-preset-stage-3": {
"version": "6.24.1", "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=", "integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -3507,7 +3507,7 @@
}, },
"code-prettify": { "code-prettify": {
"version": "0.1.0", "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=" "integrity": "sha1-RocMyMGlDQm61TmzOpg9vUqjSx4="
}, },
"codemirror": { "codemirror": {
@ -4885,7 +4885,7 @@
}, },
"dom-closest": { "dom-closest": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npm.taobao.org/dom-closest/download/dom-closest-0.2.0.tgz", "resolved": "https://registry.npmjs.org/dom-closest/-/dom-closest-0.2.0.tgz",
"integrity": "sha1-69n5HRvyLo1vR3h2u80+yQIWwM8=", "integrity": "sha1-69n5HRvyLo1vR3h2u80+yQIWwM8=",
"requires": { "requires": {
"dom-matches": ">=1.0.1" "dom-matches": ">=1.0.1"
@ -4929,7 +4929,7 @@
}, },
"dom-matches": { "dom-matches": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npm.taobao.org/dom-matches/download/dom-matches-2.0.0.tgz", "resolved": "https://registry.npmjs.org/dom-matches/-/dom-matches-2.0.0.tgz",
"integrity": "sha1-0nKLQWqHUzmA6wibhI0lPPI6dYw=" "integrity": "sha1-0nKLQWqHUzmA6wibhI0lPPI6dYw="
}, },
"dom-scroll-into-view": { "dom-scroll-into-view": {
@ -5187,7 +5187,7 @@
}, },
"enquire.js": { "enquire.js": {
"version": "2.1.6", "version": "2.1.6",
"resolved": "https://registry.npm.taobao.org/enquire.js/download/enquire.js-2.1.6.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fenquire.js%2Fdownload%2Fenquire.js-2.1.6.tgz", "resolved": "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz",
"integrity": "sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ=" "integrity": "sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ="
}, },
"entities": { "entities": {
@ -5706,7 +5706,7 @@
}, },
"eventlistener": { "eventlistener": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npm.taobao.org/eventlistener/download/eventlistener-0.0.1.tgz", "resolved": "https://registry.npmjs.org/eventlistener/-/eventlistener-0.0.1.tgz",
"integrity": "sha1-7Suqu4UiJ68rz4iRUscsY8pTLrg=" "integrity": "sha1-7Suqu4UiJ68rz4iRUscsY8pTLrg="
}, },
"events": { "events": {
@ -8040,7 +8040,7 @@
}, },
"hammerjs": { "hammerjs": {
"version": "2.0.8", "version": "2.0.8",
"resolved": "https://registry.npm.taobao.org/hammerjs/download/hammerjs-2.0.8.tgz", "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
"integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=" "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE="
}, },
"handle-thing": { "handle-thing": {
@ -8881,7 +8881,7 @@
}, },
"immutable": { "immutable": {
"version": "3.7.6", "version": "3.7.6",
"resolved": "https://registry.npm.taobao.org/immutable/download/immutable-3.7.6.tgz", "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz",
"integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks="
}, },
"import-fresh": { "import-fresh": {
@ -10486,7 +10486,7 @@
}, },
"lodash.throttle": { "lodash.throttle": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npm.taobao.org/lodash.throttle/download/lodash.throttle-4.1.1.tgz", "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
}, },
"lodash.uniq": { "lodash.uniq": {
@ -11673,7 +11673,7 @@
}, },
"output-file-sync": { "output-file-sync": {
"version": "1.1.2", "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=", "integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -19100,7 +19100,7 @@
}, },
"user-home": { "user-home": {
"version": "1.1.1", "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=", "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=",
"dev": true "dev": true
}, },
@ -19157,7 +19157,7 @@
}, },
"v8flags": { "v8flags": {
"version": "2.1.1", "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=", "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=",
"dev": true, "dev": true,
"requires": { "requires": {

View File

@ -114,14 +114,6 @@ a:visited {
color: #898989; color: #898989;
} }
a:hover {
color: #FF7500;
}
a:hover.fa {
color: #FF7500;
}
input, input,
textarea, textarea,
select { select {

View File

@ -97,10 +97,6 @@ a:visited {
color: #05101a; color: #05101a;
} }
a:hover {
color: #459be5;
}
ol, ol,
ul, ul,
li { li {

View File

@ -1364,7 +1364,7 @@ a:visited {
} }
a:hover { a:hover {
color: #459be5; color: #2A61FF!important;
} }
ol, ol,
@ -1473,7 +1473,7 @@ a.edu-txt-w80,
/*隐藏*/ /*隐藏*/
.none { .none {
display: none display: none!important;
} }
.block { .block {
@ -2471,19 +2471,16 @@ a.hoverLine:hover{
a.color-grey-name:hover, a.color-grey-name:hover,
a.color-dark:hover, a.color-dark:hover,
a.color-grey-6:hover, a.color-grey-6:hover,
a.color-grey-3:hover { a.color-grey-3:hover,a.color-ooo:hover {
color: #4cacff !important; color: #2A61FF !important;
}
a.color-grey-9:hover,
a.color-grey-8:hover,
a.color-grey-c:hover {
color: #111C24 !important;
} }
/*蓝色*/ /*蓝色*/
.color-blue { .color-blue {
color: #4CACFF !important; color: #2A61FF !important;
}
.color-blue-file {
color: #0054CC!important;
} }
/* 绿色 */ /* 绿色 */
.color-green-file{ .color-green-file{
@ -2494,10 +2491,6 @@ a.color-grey-c:hover {
color: #4CACFF !important; color: #4CACFF !important;
} }
a.color-blue:hover,
a.color-blue_4C:hover {
color: #459BE6 !important;
}
/*橙色*/ /*橙色*/
.color-orange { .color-orange {

View File

@ -1,8 +1,8 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 2340181 */ font-family: "iconfont"; /* Project id 2340181 */
src: url('iconfont.woff2?t=1627870211301') format('woff2'), src: url('iconfont.woff2?t=1628841816999') format('woff2'),
url('iconfont.woff?t=1627870211301') format('woff'), url('iconfont.woff?t=1628841816999') format('woff'),
url('iconfont.ttf?t=1627870211301') format('truetype'); url('iconfont.ttf?t=1628841816999') format('truetype');
} }
.iconfont { .iconfont {
@ -13,6 +13,150 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-xinjian2:before {
content: "\e8b0";
}
.icon-xieyiicon:before {
content: "\e870";
}
.icon-neicunicon:before {
content: "\e891";
}
.icon-zishuwenjian_icon:before {
content: "\e8a6";
}
.icon-dianzan_icon:before {
content: "\e8ba";
}
.icon-quxiaoguanzhu:before {
content: "\e8bb";
}
.icon-daimakuicon:before {
content: "\e8a9";
}
.icon-zhuyeicon:before {
content: "\e884";
}
.icon-biaoqianicon:before {
content: "\e882";
}
.icon-a-bianji:before {
content: "\e883";
}
.icon-cangkushezhiicon:before {
content: "\e885";
}
.icon-fuzhiicon:before {
content: "\e886";
}
.icon-lianjieicon:before {
content: "\e887";
}
.icon-hebingqingqiuicon:before {
content: "\e888";
}
.icon-lichengbeiicon:before {
content: "\e889";
}
.icon-gongzuoliuicon:before {
content: "\e88a";
}
.icon-dongtaiicon:before {
content: "\e88b";
}
.icon-morendianzan_icon:before {
content: "\e88e";
}
.icon-muluicon:before {
content: "\e894";
}
.icon-a-shezhi:before {
content: "\e899";
}
.icon-wenjian5:before {
content: "\e89a";
}
.icon-tijiaoicon:before {
content: "\e89e";
}
.icon-morenguanzhu_ICON:before {
content: "\e89f";
}
.icon-wenjianjia3:before {
content: "\e8a2";
}
.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 { .icon-qingqiuicon:before {
content: "\e871"; content: "\e871";
} }
@ -49,10 +193,6 @@
content: "\e898"; content: "\e898";
} }
.icon-xialaanniu_icon:before {
content: "\e89a";
}
.icon-weixuanzhongqingqiuicon:before { .icon-weixuanzhongqingqiuicon:before {
content: "\e89b"; content: "\e89b";
} }
@ -61,10 +201,6 @@
content: "\e8a1"; content: "\e8a1";
} }
.icon-xuanzhongxiangyingicon:before {
content: "\e8a2";
}
.icon-xuanzhongfenzhiicon:before { .icon-xuanzhongfenzhiicon:before {
content: "\e8a3"; content: "\e8a3";
} }
@ -81,18 +217,6 @@
content: "\e8af"; content: "\e8af";
} }
.icon-xinzengmulu_xuantingicon:before {
content: "\e884";
}
.icon-xinzengyemian_morenicon:before {
content: "\e885";
}
.icon-zhankai_morenicon:before {
content: "\e889";
}
.icon-shanchu_tc_icon:before { .icon-shanchu_tc_icon:before {
content: "\e88c"; content: "\e88c";
} }
@ -101,26 +225,14 @@
content: "\e88d"; content: "\e88d";
} }
.icon-xinzengyemian_shubiaodianjiicon:before {
content: "\e88e";
}
.icon-daorumoban_icon:before { .icon-daorumoban_icon:before {
content: "\e86f"; content: "\e86f";
} }
.icon-daochu_xuanfu:before {
content: "\e870";
}
.icon-cuowu:before { .icon-cuowu:before {
content: "\e872"; content: "\e872";
} }
.icon-chenggong1:before {
content: "\e873";
}
.icon-gengduo_icon:before { .icon-gengduo_icon:before {
content: "\e874"; content: "\e874";
} }
@ -137,18 +249,6 @@
content: "\e877"; content: "\e877";
} }
.icon-a-lajitong_icon3x:before {
content: "\e878";
}
.icon-shouqi_morenicon:before {
content: "\e879";
}
.icon-huanying_icon:before {
content: "\e87a";
}
.icon-sousuo_shanchuicon:before { .icon-sousuo_shanchuicon:before {
content: "\e87b"; content: "\e87b";
} }
@ -161,22 +261,10 @@
content: "\e87e"; content: "\e87e";
} }
.icon-wenjianjia_icon:before {
content: "\e87f";
}
.icon-xialaanniu:before { .icon-xialaanniu:before {
content: "\e880"; content: "\e880";
} }
.icon-xinzengmulu_morenicon:before {
content: "\e882";
}
.icon-xinzengmulu_shubiaodianjiicon:before {
content: "\e883";
}
.icon-erciqueren_icon:before { .icon-erciqueren_icon:before {
content: "\e867"; content: "\e867";
} }

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,258 @@
"css_prefix_text": "icon-", "css_prefix_text": "icon-",
"description": "", "description": "",
"glyphs": [ "glyphs": [
{
"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": "23492900",
"name": "点赞_icon",
"font_class": "dianzan_icon",
"unicode": "e8ba",
"unicode_decimal": 59578
},
{
"icon_id": "23492901",
"name": "取消关注",
"font_class": "quxiaoguanzhu",
"unicode": "e8bb",
"unicode_decimal": 59579
},
{
"icon_id": "23473151",
"name": "代码库icon",
"font_class": "daimakuicon",
"unicode": "e8a9",
"unicode_decimal": 59561
},
{
"icon_id": "23473104",
"name": "主页icon",
"font_class": "zhuyeicon",
"unicode": "e884",
"unicode_decimal": 59524
},
{
"icon_id": "23472253",
"name": "标签icon",
"font_class": "biaoqianicon",
"unicode": "e882",
"unicode_decimal": 59522
},
{
"icon_id": "23472254",
"name": "编 辑",
"font_class": "a-bianji",
"unicode": "e883",
"unicode_decimal": 59523
},
{
"icon_id": "23472256",
"name": "仓库设置icon",
"font_class": "cangkushezhiicon",
"unicode": "e885",
"unicode_decimal": 59525
},
{
"icon_id": "23472257",
"name": "复制icon",
"font_class": "fuzhiicon",
"unicode": "e886",
"unicode_decimal": 59526
},
{
"icon_id": "23472258",
"name": "链接icon",
"font_class": "lianjieicon",
"unicode": "e887",
"unicode_decimal": 59527
},
{
"icon_id": "23472259",
"name": "合并请求icon",
"font_class": "hebingqingqiuicon",
"unicode": "e888",
"unicode_decimal": 59528
},
{
"icon_id": "23472260",
"name": "里程碑icon",
"font_class": "lichengbeiicon",
"unicode": "e889",
"unicode_decimal": 59529
},
{
"icon_id": "23472261",
"name": "工作流icon",
"font_class": "gongzuoliuicon",
"unicode": "e88a",
"unicode_decimal": 59530
},
{
"icon_id": "23472262",
"name": "动态icon",
"font_class": "dongtaiicon",
"unicode": "e88b",
"unicode_decimal": 59531
},
{
"icon_id": "23472263",
"name": "默认点赞_icon",
"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": "23472268",
"name": "文件",
"font_class": "wenjian5",
"unicode": "e89a",
"unicode_decimal": 59546
},
{
"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": "23472271",
"name": "文件夹",
"font_class": "wenjianjia3",
"unicode": "e8a2",
"unicode_decimal": 59554
},
{
"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", "icon_id": "23261798",
"name": "请求icon", "name": "请求icon",
@ -68,13 +320,6 @@
"unicode": "e898", "unicode": "e898",
"unicode_decimal": 59544 "unicode_decimal": 59544
}, },
{
"icon_id": "23144154",
"name": "下拉按钮_icon",
"font_class": "xialaanniu_icon",
"unicode": "e89a",
"unicode_decimal": 59546
},
{ {
"icon_id": "23144155", "icon_id": "23144155",
"name": "未选中请求icon", "name": "未选中请求icon",
@ -89,13 +334,6 @@
"unicode": "e8a1", "unicode": "e8a1",
"unicode_decimal": 59553 "unicode_decimal": 59553
}, },
{
"icon_id": "23144159",
"name": "选中响应icon",
"font_class": "xuanzhongxiangyingicon",
"unicode": "e8a2",
"unicode_decimal": 59554
},
{ {
"icon_id": "23144160", "icon_id": "23144160",
"name": "选中分支icon", "name": "选中分支icon",
@ -124,27 +362,6 @@
"unicode": "e8af", "unicode": "e8af",
"unicode_decimal": 59567 "unicode_decimal": 59567
}, },
{
"icon_id": "23046282",
"name": "新增目录_悬停icon",
"font_class": "xinzengmulu_xuantingicon",
"unicode": "e884",
"unicode_decimal": 59524
},
{
"icon_id": "23046283",
"name": "新增页面_默认icon",
"font_class": "xinzengyemian_morenicon",
"unicode": "e885",
"unicode_decimal": 59525
},
{
"icon_id": "23046287",
"name": "展开_默认icon",
"font_class": "zhankai_morenicon",
"unicode": "e889",
"unicode_decimal": 59529
},
{ {
"icon_id": "23046290", "icon_id": "23046290",
"name": "shanchu_tc_icon", "name": "shanchu_tc_icon",
@ -159,13 +376,6 @@
"unicode": "e88d", "unicode": "e88d",
"unicode_decimal": 59533 "unicode_decimal": 59533
}, },
{
"icon_id": "23046311",
"name": "新增页面_鼠标点击icon",
"font_class": "xinzengyemian_shubiaodianjiicon",
"unicode": "e88e",
"unicode_decimal": 59534
},
{ {
"icon_id": "23046244", "icon_id": "23046244",
"name": "导入模版_icon", "name": "导入模版_icon",
@ -173,13 +383,6 @@
"unicode": "e86f", "unicode": "e86f",
"unicode_decimal": 59503 "unicode_decimal": 59503
}, },
{
"icon_id": "23046247",
"name": "导出_悬浮",
"font_class": "daochu_xuanfu",
"unicode": "e870",
"unicode_decimal": 59504
},
{ {
"icon_id": "23046252", "icon_id": "23046252",
"name": "错误", "name": "错误",
@ -187,13 +390,6 @@
"unicode": "e872", "unicode": "e872",
"unicode_decimal": 59506 "unicode_decimal": 59506
}, },
{
"icon_id": "23046254",
"name": "成功",
"font_class": "chenggong1",
"unicode": "e873",
"unicode_decimal": 59507
},
{ {
"icon_id": "23046255", "icon_id": "23046255",
"name": "更多_icon", "name": "更多_icon",
@ -222,27 +418,6 @@
"unicode": "e877", "unicode": "e877",
"unicode_decimal": 59511 "unicode_decimal": 59511
}, },
{
"icon_id": "23046269",
"name": "垃圾桶_icon@3x",
"font_class": "a-lajitong_icon3x",
"unicode": "e878",
"unicode_decimal": 59512
},
{
"icon_id": "23046270",
"name": "收起_默认icon",
"font_class": "shouqi_morenicon",
"unicode": "e879",
"unicode_decimal": 59513
},
{
"icon_id": "23046271",
"name": "欢迎_icon",
"font_class": "huanying_icon",
"unicode": "e87a",
"unicode_decimal": 59514
},
{ {
"icon_id": "23046273", "icon_id": "23046273",
"name": "搜索_删除icon", "name": "搜索_删除icon",
@ -264,13 +439,6 @@
"unicode": "e87e", "unicode": "e87e",
"unicode_decimal": 59518 "unicode_decimal": 59518
}, },
{
"icon_id": "23046277",
"name": "文件夹_icon",
"font_class": "wenjianjia_icon",
"unicode": "e87f",
"unicode_decimal": 59519
},
{ {
"icon_id": "23046278", "icon_id": "23046278",
"name": "下拉按钮", "name": "下拉按钮",
@ -278,20 +446,6 @@
"unicode": "e880", "unicode": "e880",
"unicode_decimal": 59520 "unicode_decimal": 59520
}, },
{
"icon_id": "23046280",
"name": "新增目录_默认icon",
"font_class": "xinzengmulu_morenicon",
"unicode": "e882",
"unicode_decimal": 59522
},
{
"icon_id": "23046281",
"name": "新增目录_鼠标点击icon",
"font_class": "xinzengmulu_shubiaodianjiicon",
"unicode": "e883",
"unicode_decimal": 59523
},
{ {
"icon_id": "22906287", "icon_id": "22906287",
"name": "二次确认_icon", "name": "二次确认_icon",

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -82,10 +82,14 @@ const Search = Loadable({
loader: () => import('./modules/search/'), loader: () => import('./modules/search/'),
loading: Loading, loading: Loading,
}) })
const WikiPreview = Loadable({
loader: () => import('./forge/Wiki/Preview'),
loading: Loading,
})
const ProjectIndex = Loadable({ const ProjectIndex = Loadable({
loader: () => import("./forge/Index"), loader: () => import("./forge/Index"),
loading: Loading, loading: Loading,
}); });
class App extends Component { class App extends Component {
constructor(props) { constructor(props) {
@ -199,9 +203,16 @@ class App extends Component {
<ConfigProvider locale={zhCN}> <ConfigProvider locale={zhCN}>
<MuiThemeProvider theme={theme}> <MuiThemeProvider theme={theme}>
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog> <LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
<SiderBar/> <SiderBar />
<Router> <Router>
<Switch> <Switch>
{/* wiki预览 */}
<Route path="/projects/:owner/:projectsId/wiki/preview/:projectName/:projectId" render={
(props) => {
return (<WikiPreview {...this.props} {...props} {...this.state} />)
}
} />
{/*项目*/} {/*项目*/}
<Route <Route
path={"/projects/:owner/:projectId/devops/:opsId/detail"} path={"/projects/:owner/:projectId/devops/:opsId/detail"}
@ -253,20 +264,21 @@ class App extends Component {
{/* 查询 */} {/* 查询 */}
<Route path="/search" component={Search} /> <Route path="/search" component={Search} />
{/* 个人主页 */} {/* 个人主页 */}
<Route path="/users/:username" <Route path="/users/:username"
render={ render={
(props) => { (props) => {
return (<InfosIndex {...this.props} {...this.state} />) return (<InfosIndex {...this.props} {...this.state} />)
} }
}></Route> }></Route>
<Route exact path="/" <Route exact path="/"
render={ render={
(props) => ( (props) => (
personal && personal.length > 0 ? personal && personal.length > 0 ?
<InfosIndex {...this.props} {...props} /> <InfosIndex {...this.props} {...props} />
: :
<ProjectIndex {...this.props} {...props} /> <ProjectIndex {...this.props} {...props} />
) )
} }
/> />

View File

@ -218,7 +218,7 @@ a:hover {
} }
.color-blue { .color-blue {
color: #4CACFF; color: #2A61FF;
} }
.color-huang { .color-huang {

View File

@ -1,4 +1,5 @@
import moment from "moment"; import moment from "moment";
import { number } from "prop-types";
// 处理整点 半点 // 处理整点 半点
// 取传入时间往后的第一个半点 // 取传入时间往后的第一个半点
@ -97,3 +98,40 @@ export function formatDuring(mss){
} }
return days + "天" + hours + "小时" + minutes + "分"; 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 + "秒前";
}
}

View File

@ -18,6 +18,23 @@ export function getImageUrl(path) {
return `${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) { export function getImage(path) {
// https://www.educoder.net // https://www.educoder.net
// https://testbdweb.trustie.net // https://testbdweb.trustie.net

View File

@ -3,7 +3,7 @@
// export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil'; // export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil';
export { 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 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 , 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 , 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, markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension,
downloadFile, sortDirections, validateLength, mdJSONParse, exportMdtoHtml downloadFile, sortDirections, validateLength, mdJSONParse, exportMdtoHtml
} from './TextUtil' } 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' export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil'

View File

@ -13,7 +13,7 @@ function CloneAddress({http_url , ssh_url , zip_url , tar_url}) {
return ( return (
<div className="downMenu"> <div className="downMenu">
<div style={{padding:"10px 20px 20px 20px",borderBottom:"1px solid #eee"}}> <div style={{borderBottom:"1px solid #eee"}}>
<Menu className="urlMenu" selectedKeys={[key]} mode={"horizontal"}> <Menu className="urlMenu" selectedKeys={[key]} mode={"horizontal"}>
<Menu.Item key="HTTP" onClick={(e)=>{setKey(e.key)}}>HTTP</Menu.Item> <Menu.Item key="HTTP" onClick={(e)=>{setKey(e.key)}}>HTTP</Menu.Item>
<Menu.Item key="SSH" onClick={(e)=>{setKey(e.key)}}>SSH</Menu.Item> <Menu.Item key="SSH" onClick={(e)=>{setKey(e.key)}}>SSH</Menu.Item>

View File

@ -1,116 +1,36 @@
import React , { useState , useEffect } from 'react'; import React , { useState , useEffect } from 'react';
import { Popover , Input , Spin } from 'antd'; import { Popover , Dropdown , Input , Spin } from 'antd';
import './branch.scss'; import './branch.scss';
import { getBranch , getTag } from '../GetData/getData'; import { getBranch , getTag } from '../GetData/getData';
import SelectOverlay from './SelectOverlay';
export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true })=>{ export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true })=>{
const [ showValue , setShowValue ] = useState(branch); 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 [ data , setData ] = useState(undefined);
const [ datas , setDatas ] = useState(undefined);
useEffect(()=>{ useEffect(()=>{
setShowValue(branch); setShowValue(branch);
},[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);
}
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 = ( const menu = (
<div> <SelectOverlay
<div className="padding10 bor-bottom-greyE"> changeBranch={changeBranch}
<Input tagflag={tagflag}
placeholder="请输入分支或标签名称搜索" projectsId={projectsId}
autocomplete="off" className="OptionsInput" value={inputValue} owner={owner}
onChange={changeInputValue} style={{width:"220px"}} branchList={branchList}
/> />
<ul className="navUl">
<li className={nav === 0?"navli active":"navli"} onClick={()=>changeNav(0)}><i className="iconfont icon-fenzhi1 font-14 mr3"></i>分支列表</li>
{ tagflag && <li className={nav === 1?"navli active":"navli"} onClick={()=>changeNav(1)}><i className="iconfont icon-biaoqian3 font-14 mr3"></i>标签列表</li> }
</ul>
</div>
<Spin spinning={isSpin}>
<ul className="OptionsUl" id="ul-btn">
{
datas && datas.length>0 ?
datas.map((item,key)=>{
return(
<li key={key} onClick={()=>chooseitem(item.name)}><a className="task-hide ulALink">{item.name}</a></li>
)
}):
<p className="listTips">暂无{inputValue}{nav === 0 ?"分支":"标签"}~</p>
}
</ul>
</Spin>
</div>
); );
return( return(
<Popover placement='bottomLeft' visible={flag} content={menu} onClick={()=>setFlag(!flag)} overlayClassName="branch-tagBox-list"> <Dropdown placement='bottomLeft' overlay={menu} overlayClassName="branch-tagBox-list" trigger={['click']} >
<div className="branch-tagBox"> <div className="branch-tagBox">
{/* {nav === 0 ?"分支":"标签"} */} {/* {nav === 0 ?"分支":"标签"} */}
<span className="color-grey-9 mr3 ml8"><i className="iconfont icon-fenzhi2 font-18"></i></span> <span className="color-grey-9 mr3 ml8"><i className="iconfont icon-fenzhi2 font-18"></i></span>
<a className="ant-dropdown-link"> <a className="ant-dropdown-link task-hide">
{showValue} {showValue}
</a> </a>
<i className="showtag iconfont icon-xiajiantou font-14 color-grey-9 mr8" /> <i className="showtag iconfont icon-sanjiaoxing-down font-15 color-grey-9 mr5 ml5 mt1" />
</div> </div>
</Popover> </Dropdown>
) )
}) })

View File

@ -0,0 +1,84 @@
import React , { useState , useEffect } from 'react';
import { Input , Spin , Menu } from 'antd';
import { getBranch , getTag } from '../GetData/getData';
function SelectOverlay({ changeBranch , tagflag , branchList , projectsId , owner }) {
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(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);
}
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);
}else{
getTags(projectsId,owner);
}
}
return(
<div className="overlayBranch">
<div className="padding15" style={{paddingBottom:"0px"}}>
<Input
prefix={<i className="iconfont icon-sousuo_icon1 font-14"></i>}
placeholder="请输入分支或标签名称搜索"
autocomplete="off" className="OptionsInput"
value={inputValue}
onChange={changeInputValue}
/>
</div>
<Menu mode="horizontal" className="navUl" selectedKeys={[keys]} onClick={changeNav}>
<Menu.Item key={"branch"}>分支</Menu.Item>
{ tagflag && <Menu.Item key={"tag"}>标签</Menu.Item> }
</Menu>
<Spin spinning={isSpin}>
<ul className="OptionsUl" id="ul-btn">
{
datas && datas.length>0 ?
datas.map((item,key)=>{
return(
<li key={key} onClick={()=>chooseitem(item.name)}><a className="task-hide ulALink">{item.name}</a></li>
)
}):
<p className="listTips">暂无{inputValue}{nav === 0 ?"分支":"标签"}~</p>
}
</ul>
</Spin>
</div>
)
}
export default SelectOverlay;

View File

@ -27,10 +27,11 @@
overflow-y: auto; overflow-y: auto;
} }
.OptionsUl li{ .OptionsUl li{
height: 35px; height: 30px;
line-height: 35px; line-height: 30px;
cursor: pointer; cursor: pointer;
padding:0px 10px; padding:0px 20px;
margin:5px 0px;
} }
.OptionsUl li:hover{ .OptionsUl li:hover{
background-color: #F0F0F0; background-color: #F0F0F0;
@ -45,38 +46,49 @@
width: 100%; width: 100%;
} }
.branch-tagBox{ .branch-tagBox{
border:1px solid #eee; border:1px solid #D0D0D0;
border-radius: 3px; border-radius: 3px;
height: 40px; height: 36px;
display: flex; display: flex;
align-items: center; align-items: center;
cursor: pointer; cursor: pointer;
min-width: 140px; min-width: 104px;
} }
.branch-tagBox-list .ant-popover-arrow{ .branch-tagBox:hover{
display: none; background-color: #F3F4F6;
} }
.branch-tagBox-list.ant-popover.ant-popover-placement-bottom{ .branch-tagBox-list{
padding-top:0px; 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;
}
} }
.branch-tagBox .ant-dropdown-link{ .overlayBranch{
display: block; width: 325px;
flex:1; .navUl{
} margin-top: 8px;
.branch-tagBox-list .ant-popover-inner-content{ height: 30px;
padding:0px; line-height: 30px;
} li{
.navUl{ height: 30px;
display: flex; line-height: 30px;
justify-content: space-between; padding:0px 5px;
align-items: center; margin-left: 20px!important;
margin-top: 5px; }
} }
.navUl li{
cursor: pointer;
}
.navUl li.active{
color:#5091FF;
} }
.listTips{ .listTips{
padding:20px 0px; padding:20px 0px;
@ -86,6 +98,7 @@
.urlMenu{ .urlMenu{
line-height: 30px; line-height: 30px;
margin-bottom: 10px; margin-bottom: 10px;
padding:15px 20px 0px 20px;
border-bottom: none; border-bottom: none;
li.ant-menu-item{ li.ant-menu-item{
height: 30px; height: 30px;

View File

@ -113,7 +113,14 @@ li.ant-menu-item{
z-index: 10000; z-index: 10000;
} }
.laterest{ .laterest{
color: #05690d; 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){ @media screen and (max-width: 1800px){
@ -157,39 +164,88 @@ li.ant-menu-item{
} }
.menuPanels{ .menuPanels{
width: 240px; width: 295px;
height: 180px; .leftline{
position: relative;
color: #666;
height: 16px;
&::before{
position: absolute;
left: -10px;
top:3px;
height: 12px;
width: 1px;
background-color: #666666;
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-primary{
color: #fff;
background-color: #2A61FF;
}
.focusPanelHeadInfo{
padding:14px 16px;
border-bottom: 1px solid #eee;
}
.ant-popover-content,.ant-popover-inner{ .ant-popover-content,.ant-popover-inner{
height: 100%; height: 100%;
width: 100%; width: 100%;
} }
.ant-popover-inner-content{
padding:0px;
}
} }
.halfs{ .halfs{
margin-top: 24px; margin-top: 24px;
padding:24px 0px 0px 0px; padding:24px 0px 0px 0px;
border-top: 1px solid #e8e8e8; border-top: 1px solid #e8e8e8;
.attrPerson{ }
padding-bottom: 24px; .aboutSubTitle{
} display: flex;
align-items: center;
} }
.menuinfos{ .menuinfos{
padding:15px 0px; padding:10px 20px;
&>a{ &>a{
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
border-right: 1px solid #eee;
flex: 1; flex: 1;
& >span:first-child{ & >span:first-child{
font-size: 18px; font-size: 16px;
font-weight: 400; font-weight: 500;
color: #333; color: #333;
line-height: 22px;
} }
& >span:last-child{ & >span:last-child{
color: #666; color: #666;
} font-weight: 400;
&:last-child{ line-height: 20px;
border-right: none; margin-top: 6px;
} }
} }
} }

View File

@ -1,13 +1,13 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { AlignCenter , FlexAJ } from '../Component/layout'; import { AlignCenter , FlexAJ } from '../Component/layout';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Popover , Spin } from 'antd'; import { Popover , Spin , Button } from 'antd';
import { getImageUrl } from 'educoder'; import { getImageUrl } from 'educoder';
import './Component.scss'; import './Component.scss';
import { getUser } from '../GetData/getData'; import { getUser } from '../GetData/getData';
import axios from 'axios'; import axios from 'axios';
function Contributors({contributors,owner,projectsId}){ function Contributors({contributors,owner,projectsId,currentLogin}){
const [ menuList ,setMenuList ]= useState([]); const [ menuList ,setMenuList ]= useState([]);
const [ list , setList ]= useState(undefined); const [ list , setList ]= useState(undefined);
const [ total , setTotal ]= useState(0); const [ total , setTotal ]= useState(0);
@ -50,15 +50,28 @@ function Contributors({contributors,owner,projectsId}){
if(data){ if(data){
let ele = ( let ele = (
<Spin spinning={isSpin}> <Spin spinning={isSpin}>
<FlexAJ> <AlignCenter className="focusPanelHeadInfo">
<AlignCenter> <Link to={`/users/${data.login}`}><img src={getImageUrl(`/${data.image_url}`)} alt="" className="radius" width="38px" height="38px"/></Link>
<Link to={`/users/${data.login}`}><img src={getImageUrl(`/${data.image_url}`)} alt="" className="radius" width="38px" height="38px"/></Link> <div className="flex1 ml10" style={{width:"0"}}>
<Link to={`/users/${data.login}`} className="ml10">{data.name}</Link> <AlignCenter>
</AlignCenter> <Link to={`/users/${data.login}`} className="font-16">{data.name}</Link>
{ {
data.is_watch ? <a className="color-grey-9" onClick={()=>FocusFunc(false,data.login)}>取消关注</a>:<a className="color-blue" onClick={()=>FocusFunc(true,data.login)}>关注</a> data.location &&
} <span className="ml20 font-12 leftline">{data.location}</span>
</FlexAJ> }
</AlignCenter>
{
data.organizations && data.organizations.length > 0 ?
<AlignCenter className="font-12 mt5">
<span>所属组织</span>
<div className="task-hide flex1">
{renderArray(data.organizations)}
</div>
</AlignCenter>
:""
}
</div>
</AlignCenter>
<AlignCenter className="menuinfos"> <AlignCenter className="menuinfos">
<a href={data.projects_url}> <a href={data.projects_url}>
<span>{data.projects_count}</span> <span>{data.projects_count}</span>
@ -73,19 +86,18 @@ function Contributors({contributors,owner,projectsId}){
<span>关注数</span> <span>关注数</span>
</a> </a>
</AlignCenter> </AlignCenter>
{ <div className={"pb20"} style={{display:"flex",justifyContent:'center'}}>
data.organizations && data.organizations.length > 0 ? {
<AlignCenter className="font-12 pt4 pb4"> currentLogin && (currentLogin === data.login)
<span>所属组织</span> ?
<div className="task-hide flex1"> <Button className="currentBtn">当前用户</Button>
{renderArray(data.organizations)} :
</div> data.is_watch ?
</AlignCenter> <Button type={"default"} onClick={()=>FocusFunc(false,data.login)}>已关注</Button>
:"" :
} <Button type={"primary"} onClick={()=>FocusFunc(true,data.login)}>关注TA</Button>
{ }
data.location && <AlignCenter className="font-12 pt4 pb4"><span>所在地址:</span><span className="ml5">{data.location}</span></AlignCenter> </div>
}
</Spin> </Spin>
) )
setMenu(ele); setMenu(ele);
@ -135,10 +147,10 @@ function Contributors({contributors,owner,projectsId}){
return( return(
<div className="halfs"> <div className="halfs">
<FlexAJ> <Link to={`/projects/${owner}/${projectsId}/contribute`} className="font-16 color-ooo aboutSubTitle">
<AlignCenter><span className="font-16 color-grey-6">贡献者</span>{ contributors && contributors.total_count > 0 && <span className="infoCount">{contributors.total_count}</span>}</AlignCenter> <span>贡献者</span>
<Link className="font-12 color-grey-9" to={`/projects/${owner}/${projectsId}/contribute`}>全部</Link> { contributors && contributors.total_count > 0 && <span className="infoCount">{contributors.total_count}</span>}
</FlexAJ> </Link>
<div className="attrPerson" onMouseLeave={()=>setVisibleFunc(false)}> <div className="attrPerson" onMouseLeave={()=>setVisibleFunc(false)}>
{ {
total > 0 ? total > 0 ?

View File

@ -25,7 +25,7 @@ function LanguagePower({languages}){
} }
return( return(
<div> <div>
<p className="font-16 color-grey-6">开发语言</p> <p className="font-16 color-ooo aboutSubTitle">开发语言</p>
<div className="progress"> <div className="progress">
{ {
array && array.map((item,key)=>{ array && array.map((item,key)=>{

View File

@ -6,33 +6,29 @@ function Releases({owner,projectsId,releaseVersions , baseOperate , projectType}
return( return(
<div> <div>
<FlexAJ> <Link to={`/projects/${owner}/${projectsId}/releases`} className="font-16 color-ooo aboutSubTitle">
<AlignCenter><span className="font-16 color-grey-6">发行版</span> <span>发行版</span>
{ releaseVersions && releaseVersions.total_count > 0 && <span className="infoCount">{releaseVersions.total_count}</span>} { releaseVersions && releaseVersions.total_count > 0 && <span className="infoCount">{releaseVersions.total_count}</span>}
</AlignCenter> </Link>
{ (releaseVersions && releaseVersions.total_count > 0) || projectType ===2 ?
<Link className="font-12 color-grey-9" to={`/projects/${owner}/${projectsId}/releases`}>全部</Link>
:
baseOperate && <Link className="font-12 color-blue" to={`/projects/${owner}/${projectsId}/releases/new`}>新建</Link>
}
</FlexAJ>
{ {
releaseVersions && releaseVersions.total_count>0 ? releaseVersions && releaseVersions.total_count>0 ?
releaseVersions.list.map((item,key)=>{ releaseVersions.list.map((item,key)=>{
return( return(
key === 0 &&<AlignTop className="mt10"> key === 0 &&<AlignTop className="mt10">
<i className="iconfont icon-biaoqian3 color-grey-6 font-18 mr10"></i>
<div> <div>
<p className="font-16 color-grey-6"> <p className="font-16">
<Link to={`/projects/${owner}/${projectsId}/releases`}>{item.name}</Link> <Link to={`/projects/${owner}/${projectsId}/releases`} className="color-grey-3">发布{item.name}版本</Link>
<span className="font-12 laterest ml5">最新</span> <span className="laterest">最新</span>
</p> </p>
<p className="color-grey-9 font-13">{item.created_at}</p> <p className="color-grey-3 font-12">{item.created_at}</p>
</div> </div>
</AlignTop> </AlignTop>
) )
}) })
:"" :
<div className="mt8">
您暂未发布任何版本{baseOperate && projectType !==2 && <Link className="color-blue ml20" to={`/projects/${owner}/${projectsId}/releases/new`}>创建新版本</Link>}
</div>
} }
</div> </div>

View File

@ -1,6 +1,6 @@
import React , { useEffect , useState } from 'react'; import React , { useEffect , useState } from 'react';
import { WhiteBack , Box , LongWidth , ShortWidth , Gap , AlignCenter , FlexAJ } from '../Component/layout'; 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 { getImageUrl } from "educoder";
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import CloneAddress from '../Branch/CloneAddress'; import CloneAddress from '../Branch/CloneAddress';
@ -23,7 +23,7 @@ import Invite from './sub/Invite';
/** /**
* projectDetail.type:0是托管项目1是镜像项目2是同步镜像项目(为2时不支持在线创建在线上传在线修改在线删除创建合并请求等功能) * projectDetail.type:0是托管项目1是镜像项目2是同步镜像项目(为2时不支持在线创建在线上传在线修改在线删除创建合并请求等功能)
*/ */
const { Paragraph } = Typography;
function turnbar(str){ function turnbar(str){
if(str && str.length>0 && str.indexOf("/")>-1){ if(str && str.length>0 && str.indexOf("/")>-1){
return str.replaceAll('/','%2F'); return str.replaceAll('/','%2F');
@ -315,7 +315,7 @@ function CoderDepot(props){
list = {mainFlag ? dirInfo : undefined} list = {mainFlag ? dirInfo : undefined}
/> />
<div className="drawerBtn" onClick={()=>setVisible(true)}> <div className="drawerBtn" onClick={()=>setVisible(true)}>
<i className="iconfont icon-youjiantou font-16"></i> <i className="iconfont icon-zuohuaicon font-14"></i>
<span>目录</span> <span>目录</span>
</div> </div>
</React.Fragment> </React.Fragment>
@ -328,7 +328,7 @@ function CoderDepot(props){
<div className="panelmenu"> <div className="panelmenu">
<FlexAJ> <FlexAJ>
<AlignCenter> <AlignCenter>
<div className="mr20"> <div className="mr30">
{ {
props && props.platform ? props && props.platform ?
<SelectBranch <SelectBranch
@ -345,40 +345,37 @@ function CoderDepot(props){
} }
</div> </div>
<AlignCenter className="mr20"> <AlignCenter className="mr20">
<Link to={`/projects/${owner}/${projectsId}/branchs`} className="color-grey-9"> <Link to={`/projects/${owner}/${projectsId}/branchs`} className="depotNum">
<i className="iconfont icon-fenzhi2 font-18 color-grey-9 mr3"></i> <i className="iconfont icon-master_icon font-14 mr3"></i>
<span className="color-grey-6 mr3">{projectDetail && projectDetail.branches && projectDetail.branches.total_count}</span>分支 <span className="mr3">分支</span>
<span>{projectDetail && projectDetail.branches && projectDetail.branches.total_count}</span>
</Link> </Link>
</AlignCenter> </AlignCenter>
<AlignCenter className="mr20"> <AlignCenter className="mr20">
<Link to={`/projects/${owner}/${projectsId}/tag`} className="color-grey-9"> <Link to={`/projects/${owner}/${projectsId}/tag`} className="depotNum">
<i className="iconfont icon-biaoqian3 font-16 color-grey-9 mr3"></i> <i className="iconfont icon-biaoqianicon font-14 mr3"></i>
<span className="color-grey-6 mr3">{projectDetail && projectDetail.tags && projectDetail.tags.total_count}</span>标签 <span className="mr3">标签</span>
<span>{projectDetail && projectDetail.tags && projectDetail.tags.total_count}</span>
</Link> </Link>
</AlignCenter> </AlignCenter>
</AlignCenter> </AlignCenter>
<AlignCenter> <AlignCenter className="depotBtn">
{ {
baseOperate && ((projectDetail.type !== 2 && pullsFlag) || issuesFlag )&& baseOperate && projectDetail.type !== 2 && pullsFlag &&
<div className="mr20 addOptionBtn"> <Button type="default" onClick={()=>urlLink(`/projects/${owner}/${projectsId}/pulls/new`)} className="mr10"><i className="iconfont icon-xinjian2 font-12 mr3"></i> 合并请求</Button>
{ }
projectDetail.type !== 2 && pullsFlag && {
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/pulls/new`)} >+ 合并请求</a> baseOperate && issuesFlag &&
} <Button type="default" onClick={()=>urlLink(`/projects/${owner}/${projectsId}/issues/new`)} className="mr10"><i className="iconfont icon-xinjian2 font-12 mr3"></i> 任务</Button>
{
issuesFlag &&
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/issues/new`)} >+ 任务</a>
}
</div>
} }
{ fileOperate && { fileOperate &&
<Dropdown overlay={fileMenu()} className="mr20" trigger={['click']}> <Dropdown overlay={fileMenu()} className="mr10" trigger={['click']}>
<Button type="default">文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-9"></i></Button> <Button type="default">文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-6 mr-5"></i></Button>
</Dropdown> </Dropdown>
} }
<Dropdown overlay={downloadMenu} placement="bottomRight" trigger={['click']}> <Dropdown overlay={downloadMenu} placement="bottomRight" trigger={['click']}>
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white"></i></Button> <Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white mr-3"></i></Button>
</Dropdown> </Dropdown>
</AlignCenter> </AlignCenter>
</FlexAJ> </FlexAJ>
@ -393,11 +390,14 @@ function CoderDepot(props){
<pre id="ptxt">{lastCommit && lastCommit.message}</pre> <pre id="ptxt">{lastCommit && lastCommit.message}</pre>
</div> </div>
{ hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> } { hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> }
<span className="ml12 color-grey-9 mt3">{lastCommit && lastCommit.time_from_now}</span> <span className="ml20 color-grey-9 mt1">{lastCommit && lastCommit.time_from_now}</span>
{ commitCount ? <Link to={`/projects/${owner}/${projectsId}/commits/branch/${turnbar(branchName || defaultBranch)}`} className="ml12 color-grey-9"> {
<i className="iconfont icon-tijiao mr3 font-17 color-grey-9"></i>{commitCount}次提交 commitCount ?
</Link>:"" } <Link to={`/projects/${owner}/${projectsId}/commits/branch/${turnbar(branchName || defaultBranch)}`} className="ml20 color-grey-9" style={{height:"30px",lineHeight:"30px"}}>
<i className="iconfont icon-tijiaoicon mr3 font-16"></i>{commitCount}次提交
</Link>:""
}
</div> </div>
} }
<ul className="listtablebody"> <ul className="listtablebody">
@ -452,45 +452,47 @@ function CoderDepot(props){
<ShortWidth> <ShortWidth>
<Gap style={{paddingLeft:"30px"}}> <Gap style={{paddingLeft:"30px"}}>
<div className="panelmenu"> <div className="panelmenu">
<FlexAJ className="font-18 color-grey-6 mb20" style={{lineHeight:"28px"}}>简介 <FlexAJ className="font-16 color-ooo mb10" style={{lineHeight:"22px"}}>关于
{projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner") && <i onClick={()=>setOpenModal(true)} className="iconfont icon-anquanshezhi color-grey-9 font-15"></i>} {projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner") &&
<a className="color-grey-6" href="javascript:void(0)"><i onClick={()=>setOpenModal(true)} className="iconfont icon-a-shezhi font-15"></i></a>
}
</FlexAJ> </FlexAJ>
{desc && <p className="font-14 color-grey-9 mb15 task-hide-2" style={{lineHeight:"22px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}}>{desc}</p>} {desc && <p className="font-14 color-grey-3 mb15 task-hide-2" style={{lineHeight:"24px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}}>{desc}</p>}
{ {
website && website &&
<p className="color-grey-6 df"> <div className="color-grey-6 df pinfos mb5">
<i className="iconfont icon-lianjie2 font-15 mr10 color-grey-9"></i> <i className="iconfont icon-lianjie2 font-15 mr10"></i>
<a href={website} className="color-grey-6" target="_blank" style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px",textDecoration:"underline"}}>{website}</a> <a href={website} target="_blank" style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px",textDecoration:"underline"}}>{website}</a>
</p> </div>
} }
<p> <div className="pinfos mb5">
<i className="iconfont icon-wenjian4 font-15 mr10 color-grey-9"></i> <i className="iconfont icon-zishuwenjian_icon font-15 mr10"></i>
<a href="#readme" className="color-grey-6">README.md</a> <a href="#readme">README.md</a>
</p> </div>
<p className="color-grey-6"> <div className="color-grey-6 mb5">
<i className="iconfont icon-dataBase font-15 mr10 color-grey-6"></i> <i className="iconfont icon-neicunicon font-15 mr10"></i>
<span>{projectDetail && projectDetail.size}</span> <span>{projectDetail && projectDetail.size}</span>
</p> </div>
{ {
projectDetail && projectDetail.license_name && projectDetail && projectDetail.license_name &&
<p className="color-grey-6"> <div>
<i className="iconfont icon-tianping font-16 mr10 color-grey-3"></i> <i className="iconfont icon-xieyiicon font-16 mr10 color-grey-6"></i>
<span>{projectDetail.license_name}</span> <span className="color-grey-6">{projectDetail.license_name}</span>
</p> </div>
} }
</div> </div>
{ {
inviteCode && inviteCode &&
<div> <div>
<Divider /> <Divider />
<Invite code={inviteCode} className={"detailsCode"}/> <Invite code={inviteCode}/>
</div> </div>
} }
{ {
lesson_url && lesson_url &&
<div> <div>
<Divider /> <Divider />
<p className="font-16 color-grey-6">实践课程</p> <p className="font-16 color-ooo">实践课程</p>
<a href={lesson_url} target="_blank" className="color-grey-6" style={{textDecoration:"underline",wordBreak:"break-all"}}>{lesson_url}</a> <a href={lesson_url} target="_blank" className="color-grey-6" style={{textDecoration:"underline",wordBreak:"break-all"}}>{lesson_url}</a>
</div> </div>
} }
@ -512,7 +514,12 @@ function CoderDepot(props){
{/* 贡献者 */} {/* 贡献者 */}
{ {
projectDetail && projectDetail.contributors && projectDetail && projectDetail.contributors &&
<Contributors contributors={projectDetail && projectDetail.contributors} owner={owner} projectsId={projectsId} /> <Contributors
contributors={projectDetail && projectDetail.contributors}
owner={owner}
projectsId={projectsId}
currentLogin={current_user && current_user.login}
/>
} }
{/* 语言 */} {/* 语言 */}
{ projectDetail && projectDetail.languages && { projectDetail && projectDetail.languages &&

View File

@ -4,8 +4,8 @@ import { truncateCommitId } from '../common/util';
const typeIco = { const typeIco = {
"submodule":"icon-file-submodule font-17", "submodule":"icon-file-submodule font-17",
"file":'icon-wenjia font-15', "file":'icon-wenjian5 font-15',
"dir":"icon-wenjianjia1 font-15" "dir":"icon-wenjianjia3 font-15"
} }
function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){ function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
@ -13,7 +13,7 @@ function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
<li> <li>
<span> <span>
<a onClick={()=>goToSubRoot(item.path,item.type,item.name)} className={item.type === "submodule" && "submoduleStyle"}> <a onClick={()=>goToSubRoot(item.path,item.type,item.name)} className={item.type === "submodule" && "submoduleStyle"}>
<i className={`iconfont ${typeIco[`${item.type}`]} color-green-file mr5`}></i>{item.name} <i className={`iconfont ${typeIco[`${item.type}`]} color-blue-file mr8`}></i>{item.name}
</a> </a>
</span> </span>
<span title="init project"> <span title="init project">

View File

@ -1,8 +1,9 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import RenderHtml from '../../components/render-html'; import RenderHtml from '../../components/render-html';
import { AlignCenter } from '../Component/layout'; import { AlignCenter } from '../Component/layout';
import { Dropdown , Menu , Spin } from 'antd'; import { Dropdown , Anchor , Spin } from 'antd';
import { Link } from 'react-router-dom';
import ReadmeCatelogue from './sub/ReadmeCatelogue';
const $ = window.$; const $ = window.$;
function CoderDepotReadme({ operate , history , readme , ChangeFile }){ function CoderDepotReadme({ operate , history , readme , ChangeFile }){
@ -23,49 +24,43 @@ function CoderDepotReadme({ operate , history , readme , ChangeFile }){
const anchor = el.id; const anchor = el.id;
const level = el.tagName.replace("H", ""); const level = el.tagName.replace("H", "");
const href = `#${anchor}`; const href = `#${anchor}`;
return { href:`${path}${href}`,text:el.textContent , level:level } return { href:`${href}`,text:el.textContent , level:level }
}); });
setMenuList(items); setMenuList(items);
},[content]) },[content])
function menu(){ function menu(){
if(menuList && menuList.length > 0){ if(menuList && menuList.length > 0){
let hash = history.location.hash;
return( return(
<Menu className="menuslist"> <ReadmeCatelogue menuList={menuList} hash={history.location.hash}/>
{
menuList.map((item,key)=>{
return(
<Menu.Item key={item.id} className={decodeURI(hash).indexOf(item.text)>-1 ?"active":""}><Link to={`${item.href}`} style={{paddingLeft:`${item.level *10}px`}} title={item.text}>{item.text}</Link></Menu.Item>
)
})
}
</Menu>
) )
}else{ }else{
return <Spin /> return <Spin />
} }
} }
return( return(
<div className="commonBox" id="readme"> <div className="commonBox readBox" id="readme">
<div className="commonBox-title boxTitle"> <Anchor offsetTop={70} targetOffset={160}>
<AlignCenter> <div className="commonBox-title boxTitle">
<Dropdown overlay={menu()}> <AlignCenter>
<span className="catelogue"> <Dropdown overlay={menu()} trigger={['hover']} overlayClassName="menuslist">
<i className="iconfont icon-zhangjie1 font-14 mr5"></i> <span className="catelogue">
<span>目录</span> <i className="iconfont icon-muluicon font-12 mr5"></i>
</span> <span>目录</span>
</Dropdown> </span>
<span className="commonBox-title-read">README.md</span> </Dropdown>
</AlignCenter> <span className="commonBox-title-read">README.md</span>
{ </AlignCenter>
operate ? {
<a className="ml20 pull-right" onClick={() =>ChangeFile(readme && readme.path, false)}> operate ?
<i className="iconfont icon-bianji6 font-16 color-blue"></i> <a className="ml20 pull-right" onClick={() =>ChangeFile(readme && readme.path, false)}>
</a> <i className="iconfont icon-a-bianji font-17 color-grey-6"></i>
:"" </a>
} :""
</div> }
</div>
</Anchor>
{ {
content && content &&
<div className="commonBox-info"> <div className="commonBox-info">

View File

@ -4,7 +4,7 @@ import { Dropdown , Menu , Icon , Tooltip , Spin } from 'antd';
import { truncateCommitId } from '../common/util'; import { truncateCommitId } from '../common/util';
import { getBranch } from '../GetData/getData'; import { getBranch } from '../GetData/getData';
import Nodata from '../Nodata'; import Nodata from '../Nodata';
import './list.css'; import './list.scss';
function turnbar(str){ function turnbar(str){
if(str && str.length>0 && str.indexOf("/")>-1){ if(str && str.length>0 && str.indexOf("/")>-1){

View File

@ -1,6 +1,6 @@
import React, { Component } from "react"; import React, { Component } from "react";
import { Popconfirm , Select } from "antd"; import { Popconfirm , Select } from "antd";
import "./list.css"; import "./list.scss";
import axios from "axios"; import axios from "axios";
import Meditor from "../Newfile/m_editor"; import Meditor from "../Newfile/m_editor";
import RenderHtml from "../../components/render-html"; import RenderHtml from "../../components/render-html";

View File

@ -1,10 +1,11 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Spin, Tooltip , Button } from 'antd'; import { Spin, Tooltip, Button } from 'antd';
import { Link, Route, Switch } from 'react-router-dom'; import { Link, Route, Switch } from 'react-router-dom';
import { Content , AlignTop } from '../Component/layout'; import { Content , AlignTop, AlignCenter } from '../Component/layout';
import DetailBanner from './sub/DetailBanner'; import DetailBanner from './sub/DetailBanner';
import { numFormat } from 'educoder';
import '../css/index.scss' import '../css/index.scss'
import './list.css'; import './list.scss';
import Loadable from 'react-loadable'; import Loadable from 'react-loadable';
import Loading from '../../Loading'; import Loading from '../../Loading';
@ -127,7 +128,15 @@ const Source = Loadable({
const DevIndex = Loadable({ const DevIndex = Loadable({
loader: () => import('../DevOps/Index'), loader: () => import('../DevOps/Index'),
loading: Loading, loading: Loading,
}) });
const Wiki = Loadable({
loader: () => import('../Wiki/Index'),
loading: Loading,
});
const WikiEdit = Loadable({
loader: () => import('../Wiki/EditWiki'),
loading: Loading,
});
/** /**
* permissionManager:管理员Reporter报告人员(只有读取权限)Developer开发人员除不能设置仓库信息外 * permissionManager:管理员Reporter报告人员(只有读取权限)Developer开发人员除不能设置仓库信息外
*/ */
@ -151,6 +160,8 @@ function checkPathname(projectsId,owner,pathname){
name="devops" name="devops"
}else if(url.indexOf(`/source`)>-1){ }else if(url.indexOf(`/source`)>-1){
name="source" name="source"
}else if(url.indexOf(`/wiki`)>-1){
name="wiki"
} }
} }
return name; return name;
@ -215,7 +226,7 @@ class Detail extends Component {
if(num){ if(num){
this.setState({ this.setState({
secondSync:true, secondSync:true,
firsrtSync:false firstSync:false
}) })
}else{ }else{
this.setState({ this.setState({
@ -226,7 +237,7 @@ class Detail extends Component {
}else{ }else{
this.getDetail(); this.getDetail();
this.setState({ this.setState({
firsrtSync:false, firstSync:false,
secondSync:false secondSync:false
}) })
} }
@ -247,7 +258,7 @@ class Detail extends Component {
var cable = actioncable.createConsumer(`wss://${name}/cable`); var cable = actioncable.createConsumer(`wss://${name}/cable`);
this.canvasChannel1 = cable.subscriptions.create({ this.canvasChannel1 = cable.subscriptions.create({
channel: `MirrorProjectChannel`, channel: `MirrorProjectChannel`,
id: project && project.identifier id: project && project.id
}, { }, {
connected: () => { connected: () => {
console.log("###### channel connected! ######"); console.log("###### channel connected! ######");
@ -257,6 +268,10 @@ class Detail extends Component {
console.log(`###### ---received data--- ######`); console.log(`###### ---received data--- ######`);
if (data) { if (data) {
this.getDetail(); this.getDetail();
this.setState({
firstSync:false,
secondSync:false
});
cable.subscriptions.consumer.disconnect(); cable.subscriptions.consumer.disconnect();
} }
} }
@ -408,7 +423,7 @@ class Detail extends Component {
<Link to={`/projects/${fork_info.fork_project_user_login}/${fork_info.fork_project_identifier}`} className="color-grey-6 task-hide flex1" style={{maxWidth:"400px"}} title={fork_info.fork_form_name}>{fork_info.fork_form_name}</Link> <Link to={`/projects/${fork_info.fork_project_user_login}/${fork_info.fork_project_identifier}`} className="color-grey-6 task-hide flex1" style={{maxWidth:"400px"}} title={fork_info.fork_form_name}>{fork_info.fork_form_name}</Link>
</div> : "" </div> : ""
} }
render() { render() {
const { projectDetail, watchers_count, praises_count, const { projectDetail, watchers_count, praises_count,
@ -434,91 +449,92 @@ class Detail extends Component {
<div> <div>
<div className="detailHeader-wrapper"> <div className="detailHeader-wrapper">
<div className="normal"> <div className="normal">
<AlignTop style={{padding:"20px 0px 10px",justifyContent:"space-between"}}> <AlignCenter style={{paddingTop:"20px",justifyContent:"space-between"}}>
<div>
<AlignTop> <AlignTop>
<div className="projectallName"> <div className="projectallName">
{project && project.author && {project && project.author &&
<Link to={`${project.author.type ==="Organization" ? "/organize":'/users'}/${project.author.login}`}>{project.author.name}</Link> <Link to={`${project.author.type ==="Organization" ? "/organize":'/users'}/${project.author.login}`} title={project.author.name}>{project.author.name}</Link>
} }
<span className="ml5 mr5">/</span> <span className="ml5 mr5">/</span>
<Link to={`/projects/${owner}/${projectsId}`} className="projectN mt6">{projectDetail && projectDetail.name}</Link> <Link to={`/projects/${owner}/${projectsId}`} className="projectN" title={projectDetail && projectDetail.name}>{projectDetail && projectDetail.name}</Link>
</div> </div>
{ projectDetail && projectDetail.private && <span className="privateTag mt6">私有</span>} { projectDetail && projectDetail.private && <span className="privateTag">私有</span>}
</AlignTop> </AlignTop>
<div className="mt8">
{
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 ?
<span className="color-grey-9">镜像自 <a className="color-grey-6" target="_blank" href={projectDetail.mirror_url}>{projectDetail.mirror_url}</a></span>
:""
}
</div>
</div>
<div> <div>
{ {
firstSync ? "": firstSync ? "":
<span className="df"> <span className="df">
{ {
((current_user && current_user.admin) || isManager) && (projectDetail && projectDetail.type && projectDetail.type === 2) ? ((current_user && current_user.admin) || isManager) && (projectDetail && projectDetail.type && projectDetail.type === 2) ?
<a className="synchronism ml30" onClick={this.synchronismMirror}>同步镜像</a> : "" <a size="middle" className="synchronism ml30" onClick={this.synchronismMirror}>同步镜像</a> : ""
} }
<Button className="detail_tag_btn"> <span className="detail_tag_btn">
<a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={() => this.focusFunc(watched)}> <a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={() => this.focusFunc(watched)}>
<i className={watched ? "iconfont icon-shixing color-orange font-16 mr3":"iconfont icon-kongxing color-grey-9 font-16 mr3"}></i> <i className={watched ? "iconfont icon-quxiaoguanzhu color-blue font-14 mr3":"iconfont icon-morenguanzhu_ICON color-grey-9 font-14 mr3"}></i>
<span>{watched ? '取消关注' : '关注'}</span> <span>{watched ? '取消关注' : '关注'}</span>
</a> </a>
{ {
watchers_count > 0 ? watchers_count > 0 ?
platform ? platform ?
<Link className="detail_tag_btn_count" style={{color:`${watched?"#2878FF":"#666"}`}} to={platform?{ pathname: `/projects/${owner}/${projectsId}/watchers`, state }:""}> <Link className="detail_tag_btn_count" to={platform?{ pathname: `/projects/${owner}/${projectsId}/watchers`, state }:""}>
{watchers_count} {numFormat(watchers_count)}
</Link> </Link>
: :
<span className="detail_tag_btn_count">{watchers_count}</span> <span className="detail_tag_btn_count">{watchers_count}</span>
:"" :""
} }
</Button> </span>
<Button className="detail_tag_btn"> <span className="detail_tag_btn">
<a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={() => this.pariseFunc(praised)}> <a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={() => this.pariseFunc(praised)}>
<i className={praised ? "iconfont icon-weibiaoti105 color-orange font-14 mr3":"iconfont icon-guanzhu color-grey-9 font-14 mr3"}></i> <i className={praised ? "iconfont icon-dianzan_icon color-blue font-14 mr3":"iconfont icon-guanzhu color-grey-9 font-14 mr3"}></i>
<span>{praised ? '取消点赞' : '点赞'}</span> <span>{praised ? '取消点赞' : '点赞'}</span>
</a> </a>
{ {
praises_count > 0 ? praises_count > 0 ?
platform ? platform ?
<Link className="detail_tag_btn_count" style={{color:`${praised?"#2878FF":"#666"}`}} to={{ pathname: `/projects/${owner}/${projectsId}/stargazers`, state }}> <Link className="detail_tag_btn_count" to={{ pathname: `/projects/${owner}/${projectsId}/stargazers`, state }}>
{praises_count} {numFormat(praises_count)}
</Link>: </Link>:
<span className="detail_tag_btn_count">{praises_count}</span> <span className="detail_tag_btn_count">{praises_count}</span>
:"" :""
} }
</Button> </span>
<Button className="detail_tag_btn" loading={forkSpin}> <span className="detail_tag_btn" loading={forkSpin}>
<Tooltip title="复刻是fork的中文名即复制代码仓库" placement="bottom"> <Tooltip title="复刻是fork的中文名即复制代码仓库" placement="bottom">
<a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={this.forkFunc}> <a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={this.forkFunc}>
<i className="iconfont icon-fork color-grey-9 mr3"></i> <i className="iconfont icon-fork color-grey-9 mr3 font-16"></i>
<span>复刻</span>
</a> </a>
</Tooltip> </Tooltip>
{ {
forked_count > 0 ? forked_count > 0 ?
platform ? platform ?
<Link className="detail_tag_btn_count" to={{ pathname: `/projects/${owner}/${projectsId}/fork_users`, state }}> <Link className="detail_tag_btn_count" to={{ pathname: `/projects/${owner}/${projectsId}/fork_users`, state }}>
{forked_count} {numFormat(forked_count)}
</Link> </Link>
: :
<span className="detail_tag_btn_count">{forked_count}</span> <span className="detail_tag_btn_count">{forked_count}</span>
:"" :""
} }
</Button> </span>
</span> </span>
} }
</div> </div>
</AlignTop> </AlignCenter>
<div className="mt6" style={{minHeight:"20px"}}>
{
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 ?
<span className="color-grey-9">镜像自 <a className="color-blue hoverLine" target="_blank" href={projectDetail.mirror_url}>{projectDetail.mirror_url}</a></span>
:""
}
</div>
{ {
firstSync ? "" : firstSync ? "" :
<DetailBanner <DetailBanner
@ -557,6 +573,24 @@ class Detail extends Component {
() => (<DevAbout {...this.props} {...this.state} {...common} />) () => (<DevAbout {...this.props} {...this.state} {...common} />)
} }
></Route> ></Route>
{/* wiki新增文件 */}
<Route path="/projects/:owner/:projectsId/wiki/add"
render={
() => (<WikiEdit {...this.props} {...this.state} {...common} />)
}
></Route>
{/* wiki编辑文件 */}
<Route path="/projects/:owner/:projectsId/wiki/edit/:wikiName"
render={
() => (<WikiEdit {...this.props} {...this.state} {...common} />)
}
></Route>
{/* wiki */}
<Route path="/projects/:owner/:projectsId/wiki"
render={
() => (<Wiki {...this.props} {...this.state} {...common} />)
}
></Route>
{/* 工作流 */} {/* 工作流 */}
<Route path="/projects/:owner/:projectsId/devops" <Route path="/projects/:owner/:projectsId/devops"
render={ render={

View File

@ -6,7 +6,7 @@ import { getImageUrl } from 'educoder';
import "slick-carousel/slick/slick.css"; import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css"; import "slick-carousel/slick/slick-theme.css";
import '../css/index.scss' import '../css/index.scss'
import './list.css'; import './list.scss';
import './Index.scss'; import './Index.scss';
import ListItem from './IndexItem' import ListItem from './IndexItem'
import axios from 'axios'; import axios from 'axios';

View File

@ -108,6 +108,31 @@
margin: 0 auto; margin: 0 auto;
.panelmenu{ .panelmenu{
padding-top:30px; padding-top:30px;
.depotBtn{
.mr-5{
margin-right: -5px;
}
.ant-btn{
height: 36px;
line-height: 34px;
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: #2A61FF;
}
}
} }
.addOptionBtn{ .addOptionBtn{
height: 32px; height: 32px;
@ -129,25 +154,27 @@
} }
.infoCount{ .infoCount{
display: inline-block; display: inline-block;
padding:0px 5px; width: 24px;
height: 16px; text-align: center;
line-height: 16px; height: 24px;
background-color: #eee; line-height: 24px;
color:#999; background-color:rgba(153, 153, 153, 0.13);;
color:#666;
border-radius: 12px; border-radius: 12px;
margin-left: 10px; margin-left: 6px;
font-size: 12px; font-size: 12px;
} }
.attrPerson{ .attrPerson{
padding-top: 15px; padding-top: 12px;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
padding-bottom: 2px;
a{ a{
margin: 10px 10px 0px 0px; margin: 0px 17px 0px 0px;
img{ img{
border-radius: 50%; border-radius: 50%;
width: 35px; width: 40px;
height: 35px; height: 40px;
} }
&:nth-child(6){ &:nth-child(6){
margin-right: 0px; margin-right: 0px;
@ -184,10 +211,11 @@
padding-left: 15px; padding-left: 15px;
position: relative; position: relative;
min-width: 33.5%; min-width: 33.5%;
font-size: 12px;
font-weight: 400;
color: #666;
span{ span{
color: #666;
&:last-child{ &:last-child{
color: #999;
margin-left: 5px; margin-left: 5px;
} }
} }
@ -195,16 +223,15 @@
} }
.listtable{ .listtable{
margin-top: 20px; margin-top: 20px;
border:1px solid #d9d9d9;
border-radius: 4px;
.listtablehead{ .listtablehead{
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: flex-start; align-items: flex-start;
border-bottom: 1px solid #d9d9d9; border-bottom: 1px solid #d9d9d9;
padding:7px 20px; padding:13px 20px;
border-radius: 4px 4px 0px 0px; border-radius: 4px 4px 0px 0px;
background-color: #FAFBFC; border: 1px solid rgba(42, 97, 255, 0.23);
background-color: #FAFCFF;
.ellipsistxt{ .ellipsistxt{
margin-top: 6px; margin-top: 6px;
#ptxt{ #ptxt{
@ -227,32 +254,37 @@
overflow: hidden; overflow: hidden;
position: relative; position: relative;
padding-right:8px; padding-right:8px;
&::after{ // &::after{
position: absolute; // position: absolute;
right: 0px; // right: 0px;
bottom: 0px; // bottom: 0px;
content:"..."; // content:"...";
} // }
} }
} }
.ellipsis{ .ellipsis{
margin-left: 8px; margin-left: 8px;
cursor: pointer; cursor: pointer;
border-radius: 2px; border-radius: 2px;
background-color: #c1c1c1; height: 16px;
background: rgba(153, 153, 153, 0.2);
border-radius: 2px;
padding:0px 4px; padding:0px 4px;
height: 14px; height: 14px;
line-height: 14px; line-height: 14px;
margin-top: 9px; margin-top: 9px;
i{ i{
font-size: 15px!important; font-size: 15px!important;
color: #fff; color: #333;
height: 14px; height: 14px;
line-height: 14px; line-height: 14px;
} }
} }
} }
.listtablebody{ .listtablebody{
border-radius:0px 0px 4px 4px ;
border: 1px solid #D0D0D0;
border-top: none;
li.listtablepath{ li.listtablepath{
a{color: #40a9ff;} a{color: #40a9ff;}
p{ p{
@ -260,12 +292,15 @@
} }
} }
& > li{ & > li{
height: 42px; height: 44px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
border-bottom: 1px solid #d9d9d9; border-bottom: 1px solid #d9d9d9;
padding:0px 20px 0px 24px; padding:0px 20px 0px 24px;
&:hover{
background-color: #F3F4F6;
}
& > span:first-child{ & > span:first-child{
width: 30%; width: 30%;
overflow: hidden; overflow: hidden;
@ -292,8 +327,10 @@
.drawerBtn{ .drawerBtn{
position: fixed; position: fixed;
left: -13px; left: -13px;
border:1px solid rgb(207,205,223); width: 33px;
width: 34px; background: #FFFFFF;
box-shadow: 0px 0px 8px 3px rgba(0, 0, 0, 0.09);
border: 1px solid #666666;
border-radius: 0px 12px 12px 0px; border-radius: 0px 12px 12px 0px;
height: 70px; height: 70px;
top:50%; top:50%;
@ -301,63 +338,55 @@
cursor: pointer; cursor: pointer;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-end; align-items: center;
justify-content: center; justify-content: center;
padding-left: 7px;
&:hover{ &: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{ span{
writing-mode: vertical-lr; writing-mode: vertical-lr;
color: #202429; color: #333;
width: 25px; width: 25px;
font-size: 14px;
} }
i{ i{
color: #24292e; color: #333;
height: 18px; height: 14px;
line-height: 18px; line-height: 14px;
width: 18px; width: 14px;
margin-left: 2px;
margin-bottom: 3px;
} }
} }
.downMenu{ .downMenu{
width: 330px; width: 329px;
box-shadow: 0px 0px 9px rgba(134, 134, 134,0.4);
background-color: #fff; background-color: #fff;
.ant-menu-vertical .ant-menu-item:hover{ box-shadow: 0px 1px 8px 1px rgba(212, 212, 212, 0.5);
background-color: #e6f7ff; padding-bottom: 14px;
.ant-menu-item{
height: 50px;
line-height: 50px;
} }
} }
.menuslist{
max-height: 200px;
overflow-y: auto;
padding:10px 15px;
border-radius: 4px;
.ant-dropdown-menu-item{
border-radius: 8px;
text-align: left!important;
a{
width: 350px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.ant-dropdown-menu-item.active{
background-color: #e6f7ff;
}
}
.catelogue{ .catelogue{
border:1px solid rgb(211, 211, 211); cursor: pointer;
background: #FAFBFC;
border-radius: 4px;
border: 1px solid #D0D0D0;
font-size: 15px; font-size: 15px;
font-weight: normal; font-weight: normal;
border-radius: 5px; margin-right: 12px;
margin-right: 10px;
padding:0px 10px; padding:0px 10px;
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
color: #666!important; color: #666!important;
display: flex; display: flex;
align-items: center; align-items: center;
&:hover{
background-color: #F3F4F6;
}
span{ span{
margin-top: 1px; margin-top: 1px;
} }
@ -370,4 +399,24 @@
&:hover{ &:hover{
color: #05101a; color: #05101a;
} }
}
.pinfos{
i,a{color: #666;}
&:hover i,&:hover a{
color: #2A61FF;
}
}
.graph{
flex:1;
margin:0px 12px;
.ant-typography{
white-space: pre-wrap;
margin-bottom: 0px;
}
}
.ant-anchor-wrapper{
padding-left: 2px;
.ant-anchor-ink::before{
background-color: #fff;
}
} }

View File

@ -5,7 +5,7 @@ import { AlignCenter } from '../Component/layout';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import '../css/index.scss'; import '../css/index.scss';
import Nodata from '../Nodata'; import Nodata from '../Nodata';
import './list.css'; import './list.scss';
import img_parise from '../Images/parise.png'; import img_parise from '../Images/parise.png';
class IndexItem extends Component { class IndexItem extends Component {

View File

@ -218,74 +218,92 @@
} }
/* -----------详情------------ */ /* -----------详情------------ */
.detailHeader-wrapper{ .detailHeader-wrapper{
background-color:#FAFBFC; background-color:#FBFCFF;
/* background: url(../Images/forgeBanner.jpg) no-repeat center; */ border-bottom:1px solid #e2e2e2;
/* background-size:cover; */
} }
.headerMenu-wrapper{ .headerMenu-wrapper{
font-size: 16px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
} cursor: pointer;
.headerMenu-wrapper li{ li{
position: relative; font-size: 14px;
text-align: center; position: relative;
height: 40px; text-align: center;
line-height: 28px; height: 40px;
margin-right: 40px; line-height: 28px;
} padding:0px 20px;
.headerMenu-wrapper li a{ & > a{
color: #666; color: #666;
} &> img{
.headerMenu-wrapper li a > img{ margin-right: 8px;
margin-right: 8px; }
} &> span.num{
.headerMenu-wrapper li a > span.num{ line-height: 24px;
height: 28px; margin-left: 5px;
line-height: 29px; margin-top: 2px;
margin-left: 8px; font-size: 12px;
font-size: 12px; float: right;
color: #2878FF; color: #666!important;
float: right; background-color: rgba(153, 153, 153, 0.13);;
} border-radius: 50%;
.headerMenu-wrapper li.active::after{ width: 24px;
position: absolute; height: 24px;
bottom:0px; }
height:2px; }
background-color: #5091FF; &.active a,&.active a i{
content:''; color: #2A61FF!important;
left: 0px; }
width:100%; &.active::after,&:hover::after{
position: absolute;
bottom:0px;
height:2px;
background-color: #2A61FF;
content:'';
left: 0px;
width:100%;
}
&:hover::after{
background-color: rgba(153, 153, 153, 0.2);;
}
}
} }
.detail_tag_btn{ .detail_tag_btn{
height:26px; height:34px;
line-height: 26px; line-height: 32px;
border-radius:5px; border-radius:5px;
border:1px solid #f1f1f1; border:1px solid #D0D0D0;
display: flex; display: flex;
align-items: center; align-items: center;
margin-left: 30px; margin-left: 10px;
padding:0px; padding:0px;
background-color: transparent; background-color:#FAFBFC;
box-shadow: none; box-shadow: none;
&:hover{
background-color: #F3F4F6;
}
.detail_tag_btn_name{
padding:0px 18px;
min-width: 82px;
text-align: center;
&:hover>span{
color: #333!important;
}
img{
margin-right: 10px;
}
}
.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 { .ant-tooltip {
max-width: fit-content!important; 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{ .files-md{
padding:20px; padding:20px;
} }
@ -336,6 +354,7 @@
.gitAddressClone{ .gitAddressClone{
margin:0px 20px 14px 20px!important;
display: flex; display: flex;
height: 40px; height: 40px;
align-items: center; align-items: center;
@ -499,7 +518,7 @@
} }
.addFile a{ .addFile a{
display: block; display: block;
background-color: rgb(76, 172, 255,0.8); background-color: rgba(76, 172, 255,0.8);
color: #fff; color: #fff;
cursor: pointer; cursor: pointer;
height: 32px; height: 32px;
@ -514,7 +533,7 @@
border-left: 1px solid rgba(247, 247, 247, 0.3); border-left: 1px solid rgba(247, 247, 247, 0.3);
} }
.addFile a:active{ .addFile a:active{
background-color: rgb(76, 172, 255,1); background-color: rgba(76, 172, 255,1);
} }
@ -567,14 +586,28 @@
border-bottom: 1px solid #d9d9d9; border-bottom: 1px solid #d9d9d9;
border-radius: 4px 4px 0px 0px; 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{ .commonBox .commonBox-title.boxTitle{
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
height: 65px;
line-height: 65px;
background: #FAFCFF;
border-radius: 4px 4px 0px 0px;
border: 1px solid rgba(42, 97, 255, 0.23);
} }
.synchronism{ .synchronism{
display: block; display: block;
height: 26px; height: 34px;
line-height: 26px; line-height: 34px;
padding:0px 15px; padding:0px 15px;
color: #fff!important; color: #fff!important;
background-color: #28BD6C; background-color: #28BD6C;
@ -583,10 +616,16 @@
.files_info{ .files_info{
cursor: pointer; cursor: pointer;
} }
.commonBox .commonBox-info{ .commonBox {
padding:20px 15px; .commonBox-info{
padding:20px 15px;
}
}
.commonBox-title-read{
vertical-align: middle;
color: #666;
font-size: 14px;
} }
.commonBox-title-read{vertical-align: middle;color: #666;}
@media screen and (max-width: 370px){ @media screen and (max-width: 370px){
.p-r-tags,.p-r-btn{ .p-r-tags,.p-r-btn{
@ -627,9 +666,7 @@
.item:last-child{ .item:last-child{
border-bottom:none; border-bottom:none;
} }
.gitAddressClone{
margin: 0 !important;
}
.item_title small{ .item_title small{
font-weight: 400; font-weight: 400;
margin-left: 10px; margin-left: 10px;
@ -732,4 +769,13 @@ a.color-grey-ccc:hover{
text-align: center; text-align: center;
display: flex; display: flex;
justify-content: center; justify-content: center;
}
.depotNum{
color: #666!important;
span:last-child{
color: #333;
}
&:hover span:last-child{
color: #2A61FF;
}
} }

View File

@ -1,6 +1,7 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Skeleton , Tooltip} from 'antd'; import { Skeleton , Tooltip} from 'antd';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { numFormat } from 'educoder';
function DetailBanner({ history,list , owner , projectsId , isManager , url , pathname , state , urlFlag , projectDetail , platform ,open_devops }){ function DetailBanner({ history,list , owner , projectsId , isManager , url , pathname , state , urlFlag , projectDetail , platform ,open_devops }){
const [ menuName , setMenuName ] = useState(undefined); const [ menuName , setMenuName ] = useState(undefined);
@ -17,19 +18,19 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
} }
},[list]); },[list]);
return( return(
<div className="f-wrap-between mt15"> <div className="f-wrap-between mt25">
{ {
menuName && projectDetail ? menuName && projectDetail ?
<ul className="headerMenu-wrapper"> <ul className="headerMenu-wrapper">
{ {
menuName.map((item,key)=>{ Array.isArray(menuName)&& menuName.map((item,key)=>{
return( return(
<React.Fragment> <React.Fragment key={item.menu_name}>
{ {
item.menu_name === "home" && item.menu_name === "home" &&
<li className={pathname==="about" ? "active" : ""}> <li className={pathname==="about" ? "active" : ""}>
<Link to={{ pathname: `/projects/${owner}/${projectsId}/about`, state }}> <Link to={{ pathname: `/projects/${owner}/${projectsId}/about`, state }}>
<i className={(pathname==="" || urlFlag) ? "iconfont icon-zhuye1 color-grey-3 mr5 font-14":"iconfont icon-zhuye1 color-grey-6 font-14 mr5"}></i> <i className={(pathname==="" || urlFlag) ? "iconfont icon-zhuyeicon color-grey-3 mr5 font-14":"iconfont icon-zhuyeicon color-grey-6 font-14 mr5"}></i>
<span>主页</span> <span>主页</span>
</Link> </Link>
</li> </li>
@ -38,7 +39,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
item.menu_name === "code" && item.menu_name === "code" &&
<li className={(pathname==="" || urlFlag) ? "active" : ""}> <li className={(pathname==="" || urlFlag) ? "active" : ""}>
<Link to={{ pathname: `/projects/${owner}/${projectsId}`, state }}> <Link to={{ pathname: `/projects/${owner}/${projectsId}`, state }}>
<i className={(pathname==="" || urlFlag) ? "iconfont icon-daimaku color-grey-3 mr5 font-14":"iconfont icon-daimaku color-grey-6 font-14 mr5"}></i> <i className={(pathname==="" || urlFlag) ? "iconfont icon-daimakuicon color-grey-3 mr5 font-14":"iconfont icon-daimakuicon color-grey-6 font-14 mr5"}></i>
<span>代码库</span> <span>代码库</span>
</Link> </Link>
</li> </li>
@ -48,9 +49,9 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
<li className={pathname==="issues" ? "active" : ""}> <li className={pathname==="issues" ? "active" : ""}>
<Tooltip title="易修是Issue的中文名即问题列表" placement="bottom"> <Tooltip title="易修是Issue的中文名即问题列表" placement="bottom">
<Link to={{ pathname: `/projects/${owner}/${projectsId}/issues`, state }}> <Link to={{ pathname: `/projects/${owner}/${projectsId}/issues`, state }}>
<i className={pathname==="issues" ? "iconfont icon-renwu color-grey-3 mr5 font-14":"iconfont icon-renwu color-grey-6 font-14 mr5"}></i> <i className={pathname==="issues" ? "iconfont icon-yixiuicon color-grey-3 mr5 font-14":"iconfont icon-yixiuicon color-grey-6 font-14 mr5"}></i>
<span>易修</span> <span>易修</span>
{projectDetail && projectDetail.issues_count ? <span className="num">{projectDetail.issues_count}</span> : ""} {projectDetail && projectDetail.issues_count ? <span className="num">{numFormat(projectDetail.issues_count)}</span> : ""}
</Link> </Link>
</Tooltip> </Tooltip>
</li> </li>
@ -59,18 +60,27 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
item.menu_name === "pulls" && projectDetail && parseInt(projectDetail.type) !== 2 && platform ? item.menu_name === "pulls" && projectDetail && parseInt(projectDetail.type) !== 2 && platform ?
<li className={pathname==="pulls" ? "active" : ""}> <li className={pathname==="pulls" ? "active" : ""}>
<Link to={{ pathname: `/projects/${owner}/${projectsId}/pulls`, state }}> <Link to={{ pathname: `/projects/${owner}/${projectsId}/pulls`, state }}>
<i className={pathname==="pulls" ? "iconfont icon-hebingqingqiu1 color-grey-3 mr5 font-14":"iconfont icon-hebingqingqiu1 color-grey-6 font-14 mr5"}></i> <i className={pathname==="pulls" ? "iconfont icon-hebingqingqiuicon color-grey-3 mr5 font-14":"iconfont icon-hebingqingqiuicon color-grey-6 font-14 mr5"}></i>
<span>合并请求</span> <span>合并请求</span>
{projectDetail && projectDetail.pull_requests_count ? <span className="num">{projectDetail.pull_requests_count}</span> : ""} {projectDetail && projectDetail.pull_requests_count ? <span className="num">{numFormat(projectDetail.pull_requests_count)}</span> : ""}
</Link> </Link>
</li>:"" </li>:""
} }
{
item.menu_name === "wiki" &&
<li className={pathname === "wiki" ? "active" : ""}>
<Link to={{ pathname: `/projects/${owner}/${projectsId}/wiki`, state }}>
<i className={pathname==="wiki" ? "iconfont icon-wiki_icon color-grey-3 mr5 font-14":"iconfont icon-wiki_icon color-grey-6 font-14 mr5"}></i>
<span>Wiki</span>
</Link>
</li>
}
{ {
item.menu_name === "devops" && platform ? item.menu_name === "devops" && platform ?
<li className={pathname==="devops" ? "active" : ""}> <li className={pathname==="devops" ? "active" : ""}>
<Link to={{ pathname: `/projects/${owner}/${projectsId}/devops${open_devops ? `/dispose`:""}`, state }}> <Link to={{ pathname: `/projects/${owner}/${projectsId}/devops${open_devops ? `/dispose`:""}`, state }}>
<i className="iconfont icon-gongzuoliu font-13 mr8"></i>工作流(beta版) <i className="iconfont icon-gongzuoliuicon font-13 mr8"></i>工作流(beta版)
{projectDetail && projectDetail.ops_count ? <span>{projectDetail.ops_count}</span> : ""} {projectDetail && projectDetail.ops_count ? <span>{numFormat(projectDetail.ops_count)}</span> : ""}
</Link> </Link>
</li> </li>
:"" :""
@ -81,7 +91,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
<Link to={{ pathname: `/projects/${owner}/${projectsId}/source`, state }}> <Link to={{ pathname: `/projects/${owner}/${projectsId}/source`, state }}>
<i className={pathname==="source" ? "iconfont icon-ziyuanpaihanghetuijian color-grey-3 mr5 font-14":"iconfont icon-ziyuanpaihanghetuijian color-grey-6 font-14 mr5"}></i> <i className={pathname==="source" ? "iconfont icon-ziyuanpaihanghetuijian color-grey-3 mr5 font-14":"iconfont icon-ziyuanpaihanghetuijian color-grey-6 font-14 mr5"}></i>
<span>资源库</span> <span>资源库</span>
{projectDetail && projectDetail.source_count ? <span className="num">{projectDetail.source_count}</span> :""} {projectDetail && projectDetail.source_count ? <span className="num">{numFormat(projectDetail.source_count)}</span> :""}
</Link> </Link>
</li> </li>
} }
@ -89,9 +99,9 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
item.menu_name === "versions" && item.menu_name === "versions" &&
<li className={pathname==="milestones" ? "active" : ""}> <li className={pathname==="milestones" ? "active" : ""}>
<Link to={{ pathname: `/projects/${owner}/${projectsId}/milestones`, state }}> <Link to={{ pathname: `/projects/${owner}/${projectsId}/milestones`, state }}>
<i className={pathname==="milestones" ? "iconfont icon-lichengbei color-grey-3 mr5 font-14":"iconfont icon-lichengbei color-grey-6 font-14 mr5"}></i> <i className={pathname==="milestones" ? "iconfont icon-lichengbeiicon color-grey-3 mr5 font-14":"iconfont icon-lichengbeiicon color-grey-6 font-14 mr5"}></i>
<span>里程碑</span> <span>里程碑</span>
{projectDetail && projectDetail.versions_count ? <span className="num">{projectDetail.versions_count}</span> :""} {projectDetail && projectDetail.versions_count ? <span className="num">{numFormat(projectDetail.versions_count)}</span> :""}
</Link> </Link>
</li> </li>
} }
@ -99,7 +109,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
item.menu_name === "activity" && item.menu_name === "activity" &&
<li className={pathname==="activity" ? "active" : ""}> <li className={pathname==="activity" ? "active" : ""}>
<Link to={{ pathname: `/projects/${owner}/${projectsId}/activity`, state }}> <Link to={{ pathname: `/projects/${owner}/${projectsId}/activity`, state }}>
<i className={pathname==="activity" ? "iconfont icon-tongzhi color-grey-3 mr5 font-14":"iconfont icon-tongzhi color-grey-6 font-14 mr5"}></i> <i className={pathname==="activity" ? "iconfont icon-dongtaiicon color-grey-3 mr5 font-14":"iconfont icon-dongtaiicon color-grey-6 font-14 mr5"}></i>
<span>动态</span> <span>动态</span>
</Link> </Link>
</li> </li>
@ -108,7 +118,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
item.menu_name === "setting" && item.menu_name === "setting" &&
<li className={pathname === "setting" ? "active" : ""}> <li className={pathname === "setting" ? "active" : ""}>
<Link to={`/projects/${owner}/${projectsId}/setting`}> <Link to={`/projects/${owner}/${projectsId}/setting`}>
<i className={url && url.indexOf("/setting") > 0 ? "iconfont icon-cangku color-grey-3 mr5 font-14":"iconfont icon-cangku color-grey-6 font-14 mr5"}></i> <i className={url && url.indexOf("/setting") > 0 ? "iconfont icon-cangkushezhiicon color-grey-3 mr5 font-14":"iconfont icon-cangkushezhiicon color-grey-6 font-14 mr5"}></i>
<span>仓库设置</span> <span>仓库设置</span>
</Link> </Link>
</li> </li>

View File

@ -15,7 +15,7 @@ function Invite({code,className}) {
} }
return( return(
<div className={className}> <div className={className}>
<span className="font-16 color-grey-6">邀请码</span> <span className="font-16 color-ooo">邀请码</span>
<div> <div>
<span id="devitecode">{code}</span> <span id="devitecode">{code}</span>
<Tooltip title={<p className="edu-txt-center">可以通过邀请码邀请成员加入项目<br/>点击复制邀请码</p>} placement={"bottom"}> <Tooltip title={<p className="edu-txt-center">可以通过邀请码邀请成员加入项目<br/>点击复制邀请码</p>} placement={"bottom"}>

View File

@ -0,0 +1,57 @@
import React , { useState , useEffect } from 'react';
import { Anchor , Input } from 'antd';
import './sub.scss';
import { Base64 } from 'js-base64';
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.indexOf(e.target.value)>-1);
setMenu(m);
}else{
setMenu(menuList);
}
}
return(
<div>
<div className="searchBox">
<Input
placeholder={"请输入关键字"}
value={value}
onChange={changeValue}
prefix={<i className="iconfont icon-sousuo_icon1 font-14"></i>}/>
</div>
{
menu && menu.length>0?
<div className="anchorBox">
<Anchor affix={false} onChange={onChange}>
{
menu.map((item,key)=>{
return(
<div style={{paddingLeft:`${item.level *10}px`}} className={goHref===item.href?"items active":"items"}>
<Link href={`#${item.text}`} title={item.text} />
</div>
)
})
}
</Anchor>
</div>
:""
}
</div>
)
}
export default ReadmeCatelogue;

View File

@ -24,7 +24,44 @@
} }
} }
.detailsCode{ .menuslist{
display: flex; z-index: 100;
justify-content: space-between; 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;
}
}
} }

View File

@ -118,11 +118,12 @@ class Milepost extends Component {
} }
ChangePage = (page) => { ChangePage = (page) => {
document.body.scrollIntoView();
this.setState({ this.setState({
page page
}) })
const { status } = this.state;
this.getList(page); this.getList( page , status );
} }
// 排序 // 排序
@ -259,7 +260,7 @@ class Milepost extends Component {
{ {
data && data.versions_count > limit ? data && data.versions_count > limit ?
<div className="mt30 mb50 edu-txt-center"> <div className="mt30 mb50 edu-txt-center">
<Pagination simple defaultCurrent={page} total={data && data.versions_count} pageSize={limit} onChange={this.ChangePage}></Pagination> <Pagination simple current={page} total={data && data.versions_count} pageSize={limit} onChange={this.ChangePage}></Pagination>
</div> : "" </div> : ""
} }
</div> </div>

View File

@ -80,7 +80,7 @@ export default Form.create()(
[], [],
<Input type="password" /> <Input type="password" />
)} )}
<p className="font-12 mt10 pb15" style={{borderBottom:"1px solid #eee"}}>推送创建删除分支事件白名单支持匹配符如果为空或者 *所有分支的事件均被触发<br/>语法参见 <Link to="github.com/gobwas/glob" className="color-blue" target="_blank">github.com/gobwas/glob</Link> 示例 Master, ${'{master,release*}'}</p> <p className="font-12 mt10 pb15" style={{borderBottom:"1px solid #eee"}}>推送创建删除分支事件白名单支持匹配符如果为空或者 *所有分支的事件均被触发<br/>语法参见 <a href="http://github.com/gobwas/glob" className="color-blue" target="_blank">github.com/gobwas/glob</a> 示例 Master, ${'{master,release*}'}</p>
{helper( {helper(
"", "",
"active", "active",

View File

@ -14,6 +14,7 @@ const menu = [
{name:"代码库",index:"code"}, {name:"代码库",index:"code"},
{name:"易修 (Issue)",index:"issues"}, {name:"易修 (Issue)",index:"issues"},
{name:"合并请求",index:"pulls"}, {name:"合并请求",index:"pulls"},
{name:"Wiki",index:"wiki"},
{name:"工作流(beta版)",index:"devops"}, {name:"工作流(beta版)",index:"devops"},
{name:"资源库",index:"resources"}, {name:"资源库",index:"resources"},
{name:"里程碑",index:"versions"}, {name:"里程碑",index:"versions"},

View File

@ -302,7 +302,7 @@ function New({ form , match , showNotification , history }) {
<Form.Item <Form.Item
label="分支过滤" label="分支过滤"
className="topLine" className="topLine"
help={<span>推送创建删除分支事件的分支白名单使用 glob 模式匹配指定若为空或 *则将报告所有分支的事件语法文档见<a href="github.com/gobwas/glob" target="_blank" className="hoverLine color-blue">github.com/gobwas/glob</a>示例master,{'{'}master,release*{'}'}</span>} help={<span>推送创建删除分支事件的分支白名单使用 glob 模式匹配指定若为空或 *则将报告所有分支的事件语法文档见<a href="http://github.com/gobwas/glob" target="_blank" className="hoverLine color-blue">github.com/gobwas/glob</a>示例master,{'{'}master,release*{'}'}</span>}
colon={false} colon={false}
style={{marginTop:'15px'}} style={{marginTop:'15px'}}
> >

View File

@ -1,5 +1,5 @@
import React, { forwardRef , useCallback , useEffect, useState } from 'react'; import React, { forwardRef , useCallback , useEffect, useState } from 'react';
import { Form , Input , Radio ,Checkbox , Divider , Button } from 'antd'; import { Form , Input , Radio ,Checkbox , Divider , Button , InputNumber } from 'antd';
import { WhiteBack , FlexAJ } from '../../Component/layout'; import { WhiteBack , FlexAJ } from '../../Component/layout';
import Title from '../../Component/Title'; import Title from '../../Component/Title';
import styled from 'styled-components'; import styled from 'styled-components';
@ -31,7 +31,8 @@ export default Form.create()(
useEffect(()=>{ useEffect(()=>{
if(organizeDetail){ if(organizeDetail){
setFieldsValue({ setFieldsValue({
...organizeDetail ...organizeDetail,
max_repo_creation:organizeDetail.max_repo_creation===-1 ? "":organizeDetail.max_repo_creation
}) })
setImage(organizeDetail.avatar_url); setImage(organizeDetail.avatar_url);
setDescNum(organizeDetail.description ? organizeDetail.description.length : 0); setDescNum(organizeDetail.description ? organizeDetail.description.length : 0);
@ -39,10 +40,10 @@ export default Form.create()(
},[organizeDetail]) },[organizeDetail])
const helper = useCallback( const helper = useCallback(
(label, name, rules, widget , isRequired , flag ) => ( (label, name, rules, widget , isRequired , flag , help ) => (
<div> <div>
<span className={isRequired?"required":""}>{label}</span> <span className={isRequired?"required":""}>{label}</span>
<Form.Item> <Form.Item help={help}>
{getFieldDecorator(name, { rules, validateFirst: true , valuePropName:flag ? "checked":"value" })(widget)} {getFieldDecorator(name, { rules, validateFirst: true , valuePropName:flag ? "checked":"value" })(widget)}
</Form.Item> </Form.Item>
</div> </div>
@ -175,7 +176,8 @@ export default Form.create()(
'最大仓库数:', '最大仓库数:',
"max_repo_creation", "max_repo_creation",
[], [],
<Input value="-1" style={{width:"350px"}}/> <InputNumber value="-1" style={{width:"350px"}}/>,false,false,
"当输入栏为空时,默认数量无限制"
)} )}
<p>选择头像:</p> <p>选择头像:</p>
<UploadImage url={getImageUrl(`/${image}`)} getImage={getImage}/> <UploadImage url={getImageUrl(`/${image}`)} getImage={getImage}/>

223
src/forge/Wiki/EditWiki.jsx Normal file
View File

@ -0,0 +1,223 @@
import React, { useEffect, useCallback, useState } from 'react';
import { Button, Checkbox, Form, Icon, Radio, Input, message } from 'antd';
import MDEditor from "../../modules/tpm/challengesnew/tpm-md-editor";
import DelModal from './components/ModalFun';
import { weekModal, monthModal } from './components/config';
import { getWiki, wikiPages, addWiki, updateWiki } from './api';
import './Index.scss';
export default Form.create()(({ form, history, showNotification, projectDetail, match, project }) => {
// const permission = projectDetail && projectDetail.permission !== "Reporter";
const permission = projectDetail && projectDetail.permission && projectDetail.permission !== "Reporter";
const { getFieldDecorator, validateFields, setFieldsValue } = form;
const [fileArrInit, setFileArrInit] = useState(null);
let projectsId = match.params.projectsId;
let owner = match.params.owner;
let wikiName = history.location.pathname.split('/').pop();
if (wikiName === 'add') {
wikiName = '';
}
const [content, setContent] = useState(undefined);
const [modal, setModal] = useState(false);
const [modalType, setModalType] = useState();
useEffect(() => {
wikiName && project && getWiki({
owner,
repo: projectsId,
pagename: wikiName,
projectId: project.id
}).then(res => {
if (res && res.data) {
setContent(res.data.md_content);
setFieldsValue({
name: res.data.name,
content: res.data.md_content,
});
}
});
}, [owner, wikiName]);
// wiki
useEffect(() => {
project && wikiPages({
owner: owner,
repo: projectsId,
projectId: project.id
}).then(res => {
if (res && res.message === "200" && Array.isArray(res.data)) {
setFileArrInit(res.data);
} else {
setFileArrInit([]);
}
});
}, [project]);
const helper = useCallback(
(label, name, rules, widget, initialValue, rightComponent) => (
<Form.Item label={label} className="mb0">
{getFieldDecorator(name, { rules, initialValue, validateFirst: true, })(widget)}
{rightComponent}
</Form.Item>
), []);
function onContentChange(value) {
setContent(value);
setFieldsValue({
content: value
});
};
// wiki
function saveFile() {
validateFields((err, values) => {
if (!err) {
let regEn = /[\[\]`\/:*?''<>|%-+_]/g;
if (regEn.test(values.name)) {
message.error('文件名不能有特殊字符');
return;
}
if (wikiName) {
updateWiki({
owner,
repo: projectsId,
projectId: project.id,
pagename: wikiName,
...values,
commit_message: '',
}).then(res => dealRes(res));
} else {
if (Array.isArray(fileArrInit)) {
for (const item of fileArrInit) {
if (item.name === values.name) {
message.error('不能与已有文件标题相同');
return false;
}
}
}
addWiki({
owner,
repo: projectsId,
projectId: project.id,
pagename: values.name,
...values,
commit_message: '',
}).then(res => dealRes(res));
}
}
})
}
function dealRes(res) {
if (res && res.message === "200") {
showNotification("操作成功");
goBack();
} else if (res && res.message === "500") {
message.error('请检查格式是否正确或文件名是否重复');
} else {
showNotification(res.message || "操作失败");
}
}
function goBack() {
history.push(`/projects/${owner}/${projectsId}/wiki`);
}
function changeModal(e) {
setModal(e.target.checked);
if (!e.target.checked) {
setModalType();
}
}
function changeModalType(e) {
let value = e.target.value;
if (!content) {
setModalContent(value);
return;
}
DelModal({
title: '添加模版',
contentTitle: `您确定要添加“${value}”模板吗`,
content: `此操作会将“${value}”模板替换编辑栏内所有内容,请确认以防文件的丢失`,
okText: '确认添加',
onOk: () => {
setModalType(value);
setModal(true);
setModalContent(value);
}
});
}
function setModalContent(value) {
if (value === '周报') {
setContent(weekModal);
setFieldsValue({
content: weekModal
});
} else if (value === '月报') {
setContent(monthModal);
setFieldsValue({
content: monthModal
});
}
}
return (
<div className="wiki-main">
<div className="wiki-head">
<span className="head-title"><span className="back-wiki" onClick={goBack}>Wiki</span> <Icon type="right" /> 编辑页面</span>
</div>
<div >
<h4 className="mt20 mb0">标题</h4>
{helper(
"",
"name",
[
{ required: true, message: "请输入标题" },
// { pattern: /[^`\[\]\/:*?''<>|%-+_]/g, message: '' }
],
<Input
placeholder={"请输入标题"}
className="contact-input"
maxLength={50}
/>
)}
<Form.Item className="mb0">
<MDEditor
placeholder={"请输入wiki内容"}
height={500}
mdID={"order-new-description"}
initValue={content}
onChange={onContentChange}
className="mt20"
></MDEditor>
{getFieldDecorator('content', {
rules: [{ required: true, message: "请输入wiki内容" }],
validateFirst: true
})(<Input style={{ display: 'none' }} />)}
</Form.Item>
<Checkbox checked={modal} onChange={changeModal}>添加模版</Checkbox>
<Radio.Group onChange={changeModalType} value={modalType}>
<Radio value='周报'>周报</Radio>
<Radio value='月报'>月报</Radio>
</Radio.Group>
</div>
{permission && <Button className="mt25" type="primary" onClick={saveFile}>保存</Button>}
</div>
)
})

298
src/forge/Wiki/Index.jsx Normal file
View File

@ -0,0 +1,298 @@
import React, { useEffect, useCallback, useState } from 'react';
import { Button, Dropdown, Icon, Input, Menu, Tooltip, Select, Upload, message, Spin } from 'antd';
import { getImageUrl, timeAgo } from 'educoder';
import cookie from 'react-cookies';
// import Loading from "../../Loading";
import DelModal from './components/ModalFun';
import Welcome from './Welcome';
import { wikiPages, getWiki, deleteWiki } from './api';
import { httpUrl, TokenKey } from './fetch';
import './Index.scss';
import { isArray } from 'lodash';
const Search = Input.Search;
const InputGroup = Input.Group;
const { Option } = Select;
export default (props) => {
const { match, current_user, history, showNotification, project, projectDetail } = props;
// const permission = projectDetail && projectDetail.permission !== "Reporter";
const permission = projectDetail && projectDetail.permission && projectDetail.permission !== "Reporter";
let projectsId = match.params.projectsId;
let owner = match.params.owner;
console.log(project);
const [fileArrInit, setFileArrInit] = useState(null);
const [checkItem, setCheckItem] = useState({});
const [itemDetail, setItemDetail] = useState({});
const [fileArr, setFileArr] = useState([]);
const [reload, setReload] = useState();
const [urlType, setUrlType] = useState('HTTPS');
// wiki
useEffect(() => {
project && wikiPages({
owner: owner,
repo: projectsId,
projectId: project.id
}).then(res => {
if (res && res.message === "200" && isArray(res.data)) {
setFileArr(res.data);
setFileArrInit(res.data);
if (res.data.length) {
setCheckItem(res.data[0]);
};
} else {
setFileArr([]);
setFileArrInit([]);
}
});
}, [project, reload])
// wiki
useEffect(() => {
project && checkItem.name && getWiki({
owner: owner,
repo: projectsId,
pagename: checkItem.name,
projectId: project.id
}).then(res => {
if (res && res.message === "200") {
setItemDetail(res.data);
} else {
showNotification("加载失败")
}
});
}, [project, checkItem]);
function changeSearchValue(e) {
let value = e.target.value;
let newFileArr = [];
for (const item of fileArrInit) {
if (item.name.indexOf(value) > -1) {
newFileArr.push(item);
}
}
setFileArr(newFileArr);
}
// wiki
function deleteFileModal(e, item) {
e.stopPropagation();
DelModal({
title: '删除页面',
contentTitle: `您确定要删除“${item.name}”此页面吗?`,
content: '此操作将删除该页面,请进行确认以防文件的丢失。',
onOk: () => {
deleteWiki({
owner: owner,
repo: projectsId,
pagename: item.name,
projectId: project.id
}).then(res => {
if (res && res.message === "200") {
message.success('删除成功');
setReload(Math.random());
} else {
message.error('删除失败');
}
});
}
});
}
function goUser(login) {
window.location.href = `/users/${login}`;
}
//
const copyUrl = useCallback(() => {
let wikiUrl = document.getElementById("wikiUrl");
wikiUrl.select();
if (document.execCommand('copy')) {
document.execCommand('copy');
}
message.success('复制成功');
wikiUrl.blur();
}, [])
function addFile() {
history.push(`/projects/${owner}/${projectsId}/wiki/add`);
}
function goEdit() {
history.push(`/projects/${owner}/${projectsId}/wiki/edit/${encodeURI(checkItem.name)}`);
}
function preview() {
window.open(`/projects/${owner}/${projectsId}/wiki/preview/${encodeURI(project.name)}/${project.id}`);
}
// MarkdownHtmlPdf
const menu = (
<Menu >
<Menu.Item key="1" onClick={() => { downloadWiki('markdown') }}>
Markdown
</Menu.Item>
<Menu.Item key="2" onClick={() => { downloadWiki('html') }}>
HTML
</Menu.Item>
<Menu.Item key="3" onClick={() => { downloadWiki('pdf') }}>
PDF
</Menu.Item>
</Menu>
);
function downloadWiki(type) {
window.open(`${httpUrl}/api/wikiExport/wikiExport-wrapper?repoName=${projectsId}&owner=${owner}&type=${type}&projectName=${project.name}&projectId=${project.id}`);
}
function beforeUpload(file) {
if (!['md', 'txt'].includes(file.name.split('.').pop())) {
message.error('只能上传md、txt文件');
return false;
}
let regEn = /[\[\]`\/:*?''<>|%-+_]/g;
if (regEn.test(file.name)) {
message.error('文件名不能有特殊字符');
return;
}
for (const item of fileArrInit) {
if (item.name === file.name) {
message.error('不能上传与已有文件相同文件名的文件');
return false;
}
}
const isLt100M = file.size / 1024 / 1024 < 100;
if (!isLt100M) {
showNotification(`文件大小必须小于${100}MB!`);
}
return isLt100M;
}
const uploadProps = {
name: 'multipartFile',
withCredentials: true,
action: `${httpUrl}/api/wikiExport/uploadWiki/${owner}/${projectsId}/${project && project.id}`, //?token=${sessionStorage.taskToken}
showUploadList: false,
headers: {
Authorization: cookie.load(TokenKey) || sessionStorage.taskToken,
},
beforeUpload: beforeUpload,
onChange(info) {
if (info.file.status === 'uploading') {
console.log(info.file, info.fileList);
}
if (info.file.status === 'done') {
if (info.file.response.message === '200') {
message.success(`${info.file.name} 上传成功`);
setReload(Math.random());
} else if (info.file.response.message === '500') {
let data = JSON.parse(info.file.response.data);
message.error(data && data.message ? data.message : '文件上传失败');
} else {
message.error('文件上传失败');
}
} else if (info.file.status === 'error') {
message.error(`${info.file.name} 上传失败`);
}
},
};
return (
< Spin spinning={!fileArrInit} className="opacitySpin">
{fileArrInit && fileArrInit.length ?
<div className="wiki-main">
<div className="wiki-head">
<span className="head-title">
{
permission ?
<Button type="default" onClick={addFile}><Icon type="plus" />新增页面</Button>
: "Wiki文档"
}
</span>
<div>
{
permission &&
<Upload {...uploadProps}>
<Tooltip placement="top" title={'支持导入txt、markdown格式文件'}>
<Button type="default" className="ml10"><Icon type="plus" />导入模板</Button>
</Tooltip>
</Upload>
}
<Dropdown overlay={menu}>
<Button type="default" className="ml10">导出<Icon type="caret-down" /></Button>
</Dropdown>
<Button type="default" className="ml10" onClick={preview}>预览</Button>
</div>
</div>
<div className="wiki-body">
<div className="wiki-nav-parent">
<div className="wiki-nav">
<Search
// allowClear
placeholder="输入关键字搜索文件"
className="wiki-search"
onChange={changeSearchValue}
/>
{
fileArr.map(item => {
return <div className="wiki-nav-title-parent">
<div className={`wiki-nav-title ${item.name === checkItem.name ? 'active' : ''}`} key={item.name} onClick={() => { setCheckItem(item) }}>
<div className="nav-title-left">
<i className="iconfont icon-wenjianjia2 mr3"></i>
<span className="nav-title-left-text">{item.name}</span>
</div>
{permission && <i className="iconfont icon-shanchuicon1 delete-title-icon color-grey-6" onClick={(e) => { deleteFileModal(e, item) }}></i>}
</div>
</div>
})
}
</div>
{checkItem.wiki_clone_link && <InputGroup className="copy-url" compact>
<Select dropdownClassName="wiki-url-type" defaultValue="HTTPS" onChange={(v) => { setUrlType(v) }}>
<Option value="HTTPS">HTTPS</Option>
<Option value="SSH">SSH</Option>
</Select>
<Input id="wikiUrl" value={urlType === 'HTTPS' ? checkItem.wiki_clone_link.https : checkItem.wiki_clone_link.ssh} />
<Tooltip placement="bottom" title={'复制'}>
<i className="iconfont icon-fuzhiicon copy-svg" onClick={copyUrl}></i>
</Tooltip>
</InputGroup>}
</div>
<div className="wiki-content">
<div className="wiki-content-head">
<div className="wiki-content-head-left">
<h3 className="wiki-detail-title">{checkItem.name}</h3>
<span className="user-box mr10" onClick={() => { goUser(current_user.login) }}>
{itemDetail.image_url && <img alt="头像" className="head-log-small" src={getImageUrl(`/${itemDetail.image_url}`)} />}
<span >{checkItem.commit ? checkItem.commit.author.name : ''}</span>
</span>
<span className="time-ago">上次修改于{checkItem.commit && timeAgo(checkItem.commit.author.when)}</span>
</div>
{permission && <Button type="primary" onClick={goEdit}>编辑</Button>}
</div>
<div className="wiki-content-detail editor-content-panel markdown-body" dangerouslySetInnerHTML={{ __html: itemDetail && itemDetail.simple_content }} ></div>
</div>
</div>
</div >
:
<Welcome {...props} reloadList={setReload} />
}
</Spin>
)
}

381
src/forge/Wiki/Index.scss Normal file
View File

@ -0,0 +1,381 @@
$wikiColor: #466aff;
$primaryBtnHover: #6482ff;
body {
width: 100% !important;
}
.ant-spin-nested-loading > div > .ant-spin.opacitySpin{
max-height: 100vh;
background: rgba(255,255,255,1);
}
.wiki-main {
width: 1200px;
min-height: 400px;
margin: 20px auto;
.ant-btn-primary {
background-color: $wikiColor;
border-color: $wikiColor;
&:hover,
&:focus,
&:active {
background-color: $primaryBtnHover;
}
}
.ant-btn-default:hover,
.ant-btn-default:active,
.ant-btn-default:focus {
background: #f3f4f6;
color: #333;
border-color: #d0d0d0;
}
.wiki-head {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
height: 64px;
background: #fafcff;
box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.13);
border-radius: 4px;
border-bottom-left-radius: 0;
.ant-btn .anticon {
margin: 0 -3px 0 0;
}
}
.head-title {
font-size: 20px;
color: #05101a;
line-height: 30px;
font-weight: 500;
.anticon-right {
color: #666;
font-size: 0.9rem;
}
}
.back-wiki {
color: $wikiColor;
cursor: pointer;
&:hover {
color: $primaryBtnHover;
}
}
.head-log-middle {
width: 3rem;
height: 3rem;
margin-right: 0.35rem;
border-radius: 50%;
}
.head-log-small {
width: 1.25rem;
height: 1.25rem;
margin-right: 0.35rem;
border-radius: 50%;
}
.user-box {
font-size: 12px;
font-family: "PingFangSC-Medium";
color: $wikiColor;
cursor: pointer;
&:hover {
color: $primaryBtnHover;
}
.head-log-small {
position: relative;
top: -2px;
}
}
.time-ago {
font-size: 12px;
color: #333;
letter-spacing: 0;
line-height: 17px;
font-weight: 400;
font-family: "PingFangSC-Regular";
}
.has-error .ant-form-explain,
.has-error .ant-form-split {
position: absolute;
}
.wiki-nav {
max-height: 60vh;
.wiki-search {
padding: 0 14px;
.ant-input {
padding-left: 30px;
}
.ant-input-suffix {
left: 26px;
right: auto;
}
&:hover .ant-input,
&:focus .ant-input {
border-color: $wikiColor !important;
}
}
}
.wiki-nav-parent {
width: 260px;
flex: none;
}
.ant-form-item-children .ant-input:hover {
border-color: $wikiColor !important;
}
.ant-checkbox-checked .ant-checkbox-inner {
background-color: $wikiColor;
border-color: $wikiColor;
}
.ant-radio-checked .ant-radio-inner,
.ant-radio-checked::after {
border-color: $wikiColor;
}
.ant-radio-inner::after {
background-color: $wikiColor;
}
.ant-radio-group {
display: block;
margin: 10px 0 0 30px;
}
.ant-radio-wrapper:hover .ant-radio,
.ant-radio:hover .ant-radio-inner,
.ant-radio-input:focus + .ant-radio-inner {
border-color: $wikiColor;
}
}
#wikiUrl:focus {
border-right: 1px solid #d9d9d9 !important;
}
.wiki-body {
display: flex;
}
.wiki-content {
flex: auto;
width: 75%;
}
.wiki-content-detail {
padding: 0 20px;
word-break: break-all;
}
.ant-input-group.ant-input-group-compact.copy-url {
display: flex;
margin-top: 20px;
.ant-select-selection__rendered {
margin: 0 14px 0 5px;
width: 3rem;
font-size: 12px;
}
.ant-select-arrow {
right: 4px;
}
.ant-input {
font-size: 12px;
font-family: "PingFangSC-Regular";
color: #666;
letter-spacing: 0;
font-weight: 400;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-break: break-all;
}
.copy-svg {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 5px;
background: #fff;
font-size: 1rem !important;
border: 1px solid #d9d9d9;
border-left: 0;
color: $wikiColor;
cursor: pointer;
}
}
.wiki-url-type {
.ant-select-dropdown-menu-item {
font-size: 12px;
}
}
.wiki-nav {
min-height: 300px;
padding: 20px 0;
background: #ffffff;
border: 1px solid rgba(153, 153, 153, 0.22);
overflow-y: scroll;
flex: none;
color: #333;
}
.wiki-nav-title {
display: flex;
justify-content: space-between;
align-items: center;
height: 50px;
padding: 0 10px 0 10px;
font-size: 14px;
letter-spacing: 0;
font-weight: 400;
font-family: "PingFangSC-Regular";
border-bottom: 1px solid #eee;
line-height: 16px;
cursor: pointer;
.delete-title-icon {
display: none;
}
&:hover {
background-color: #fbfbfb;
.delete-title-icon {
display: inline-block;
}
}
}
.wiki-nav-title-parent {
padding: 0 14px;
&:hover {
background: #fbfbfb;
}
}
.wiki-nav-title.active {
color: $wikiColor;
}
.wiki-content-head {
margin: 20px 0 20px 20px;
padding: 0 20px 20px 0;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #eee;
}
.wiki-content-head-left {
width: 90%;
}
.nav-title-left {
display: inline-flex;
max-width: 90%;
svg {
margin-right: 0.5rem;
flex: none;
}
.nav-title-left-text {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.wiki-detail-title {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
// 预览页面样式文件
.wiki-preview {
overflow-y: scroll;
height: 100%;
.wiki-body {
width: 90%;
}
.ant-btn-primary {
background-color: $wikiColor;
border-color: $wikiColor;
&:hover,
&:focus,
&:active {
background-color: $primaryBtnHover;
}
}
.preview-head {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 12rem 0 2rem;
width: 100%;
height: 80px;
background: rgb(39, 47, 76);
color: #fff;
}
.preview-head-left {
display: inline-flex;
align-items: center;
font-size: 24px;
cursor: pointer;
.icon-wendangyulan_icon {
font-size: 24px !important;
font-weight: 700;
}
}
.preview-head-right {
display: flex;
.copy-url {
margin-top: 0;
}
.copy-desc {
width: 6rem;
padding-top: 1px;
}
}
.wiki-nav-title {
padding: 0 10px 0 40px;
}
.wiki-nav-title.active {
background-color: #f3f4f6;
}
.wiki-content-head {
padding: 10px 20px 10px 20px;
}
.wiki-nav {
padding: 20px 0;
width: 20vw;
border-bottom: 0;
height: 80vh;
}
.wiki-content-detail {
padding: 0 40px;
img {
max-width: 100%;
}
}
.ant-btn:hover {
background: #f3f4f6;
color: #333;
border-color: #d0d0d0;
}
}

157
src/forge/Wiki/Preview.jsx Normal file
View File

@ -0,0 +1,157 @@
import React, { useEffect, useCallback, useState } from 'react';
import { Input, Button, Tooltip, Select, Dropdown, Icon, Menu, message } from 'antd';
import { wikiPages, getWiki, } from './api';
import { httpUrl } from './fetch';
import './Index.scss';
const InputGroup = Input.Group;
const { Option } = Select;
export default (props) => {
const { match, history, showNotification, project, projectDetail } = props;
const permission = projectDetail && projectDetail.permission && projectDetail.permission !== "Reporter";
let projectsId = match.params.projectsId;
let owner = match.params.owner;
let projectName = match.params.projectName;
let projectId = match.params.projectId;
console.log('projectName:');
console.log(projectName);
const [checkItem, setCheckItem] = useState({});
const [itemDetail, setItemDetail] = useState({});
const [fileArr, setFileArr] = useState([]);
const [urlType, setUrlType] = useState('HTTPS');
useEffect(() => {
projectsId && wikiPages({
owner: owner,
repo: projectsId,
projectId: projectId,
}).then(res => {
if (res && res.message === "200") {
setFileArr(res.data);
if (res.data.length) {
setCheckItem(res.data[0]);
};
} else {
showNotification("加载失败")
}
});
}, [project])
useEffect(() => {
projectsId && checkItem.name && getWiki({
owner: owner,
repo: projectsId,
pagename: checkItem.name,
projectId: projectId,
}).then(res => {
if (res && res.message === "200") {
setItemDetail(res.data);
} else {
showNotification("加载失败")
}
});
}, [project, checkItem]);
const copyUrl = useCallback(() => {
let wikiUrl = document.getElementById("wikiUrl");
wikiUrl.select();
if (document.execCommand('copy')) {
document.execCommand('copy');
}
message.success('复制成功');
wikiUrl.blur();
}, []);
function goEdit() {
history.push(`/projects/${owner}/${projectsId}/wiki/edit/${checkItem.name}`);
}
function goBack() {
history.push(`/projects/${owner}/${projectsId}/wiki`);
}
// MarkdownHtmlPdf
const menu = (
<Menu >
<Menu.Item key="1" onClick={() => { downloadWiki('markdown') }}>
Markdown
</Menu.Item>
<Menu.Item key="2" onClick={() => { downloadWiki('html') }}>
HTML
</Menu.Item>
<Menu.Item key="3" onClick={() => { downloadWiki('pdf') }}>
PDF
</Menu.Item>
</Menu>
);
function downloadWiki(type) {
window.open(`${httpUrl}/api/wikiExport/wikiExport-wrapper?repoName=${projectsId}&owner=${owner}&type=${type}&projectName=${projectName}&projectId=${projectId}`);
}
return (
<div className="wiki-preview">
<div className="preview-head">
<div className="preview-head-left" onClick={goBack}>
<i className="iconfont icon-wendangyulan_icon mr3"></i>
<span className="ml10">{projectName}</span>
</div>
<div className="preview-head-right">
<span className="copy-desc">克隆地址</span>
{
checkItem.wiki_clone_link && <InputGroup className="copy-url" compact>
<Select dropdownClassName="wiki-url-type" defaultValue="HTTPS" onChange={(v) => { console.log(v); setUrlType(v) }}>
<Option value="HTTPS">HTTPS</Option>
<Option value="SSH">SSH</Option>
</Select>
<Input id="wikiUrl" value={urlType === 'HTTPS' ? checkItem.wiki_clone_link.https : checkItem.wiki_clone_link.ssh} />
<Tooltip placement="bottom" title={'复制'}>
<i className="iconfont icon-fuzhiicon copy-svg" onClick={copyUrl}></i>
</Tooltip>
</InputGroup>
}
<Dropdown overlay={menu}>
<Button className="ml10">导出<Icon type="caret-down" /></Button>
</Dropdown>
</div>
</div>
<div className="wiki-body">
<div className="wiki-nav">
{
fileArr.map(item => {
return <div className={`${item.name === checkItem.name ? 'active' : ''} wiki-nav-title`} key={item.name} onClick={() => { setCheckItem(item) }}>
<span className="nav-title-left" >
<i className="iconfont icon-wenjianjia2 mr3"></i>
<span className="nav-title-left-text">{item.name}</span>
</span>
</div>
})
}
</div>
<div className="wiki-content">
<div className="wiki-content-head">
<h3>{checkItem.name}</h3>
{permission && <Button type="primary" onClick={goEdit}>编辑</Button>}
</div>
<div className="wiki-content-detail editor-content-panel markdown-body" dangerouslySetInnerHTML={{ __html: itemDetail && itemDetail.simple_content }} ></div>
</div>
</div>
</div>
)
}

View File

@ -0,0 +1,50 @@
import React from 'react';
import { Button } from 'antd';
// import { addWiki } from '../api';
import './index.scss';
export default ({ project, isManager, history, showNotification, match, reloadList }) => {
let projectsId = match.params.projectsId;
let owner = match.params.owner;
// function addFile() {
// addWiki({
// owner,
// repo: projectsId,
// pagename: 'Home',
// name: 'Home',
// content: 'Welcome to the wiki!',
// commit_message: '',
// }).then(res => {
// if (res.message === "200") {
// reloadList(Math.random());
// showNotification("");
// } else {
// showNotification("");
// }
// });
// }
function addFile() {
history.push(`/projects/${owner}/${projectsId}/wiki/add`);
}
return (
<div className="welcome-main">
<i className="iconfont icon-huanying_icon" ></i>
<p className="welcome-title">欢迎使用&nbsp;
<span className="wiki-title">
{project && project.name}
</span>
&nbsp;Wiki</p>
<p className="welcome-content">Wiki主要是您项目的产品设计文档描述注释等等</p>
<div className="wiki-line"></div>
{
isManager ? <Button type="primary" onClick={addFile}>创建Wiki文档</Button>
: <p className="welcome-des">该项目暂时没有创建Wiki</p>
}
</div>
)
}

View File

@ -0,0 +1,55 @@
.welcome-main {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
width: 1200px;
min-height: 400px;
padding: 20px;
margin: 20px auto;
background: rgba(250, 252, 255, 1);
font-family: "PingFangSC-Medium";
border-radius: 4px;
border: 1px solid rgba(42, 97, 255, 0.23);
.icon-huanying_icon {
font-size: 48px !important;
font-weight: 700;
}
.welcome-title {
display: inline-flex;
align-items: center;
margin: 10px 0;
font-size: 26px;
color: #333333;
font-weight: 500;
}
.wiki-title {
display: inline-block;
max-width: 20em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.welcome-content {
font-size: 14px;
color: #333333;
font-weight: 400;
}
.wiki-line {
margin: 50px 0 40px;
width: 400px;
height: 1px;
background: #eeeeee;
}
.welcome-des {
font-size: 16px;
color: #333333;
font-weight: 500;
}
}

48
src/forge/Wiki/api.js Normal file
View File

@ -0,0 +1,48 @@
import fetch from './fetch';
// import { notification } from 'antd';
// 获取wiki列表
export function wikiPages(params) {
return fetch({
url: '/api/wiki/wikiPages',
method: 'get',
params
});
}
// 获取单个wiki
export function getWiki(params) {
return fetch({
url: '/api/wiki/getWiki',
method: 'get',
params
});
}
//新增wiki
export function addWiki(data) {
return fetch({
url: '/api/wiki/createWiki',
method: 'post',
data: data
});
}
//更新wiki
export function updateWiki(data) {
return fetch({
url: '/api/wiki/updateWiki',
method: 'PUT',
data: data
});
}
//删除wiki
export function deleteWiki(data) {
return fetch({
url: '/api/wiki/deleteWiki',
method: 'DELETE',
data,
});
}

View File

@ -0,0 +1,244 @@
import * as React from 'react';
import classNames from 'classnames';
import { Icon, Tree } from 'antd';
import omit from 'omit.js';
import debounce from 'lodash/debounce';
import { conductExpandParent, convertTreeToEntities } from 'rc-tree/lib/util';
import { polyfill } from 'react-lifecycles-compat';
import { ConfigConsumer } from '../../../../../node_modules/antd/lib/config-provider';
import {
calcRangeKeys,
getFullKeyList,
convertDirectoryKeysToNodes,
getFullKeyListByTreeData,
} from '../../../../../node_modules/antd/lib/tree/util';
import { FolderSvg, FolderExpandSvg, FileSvg } from '../../Svg';
import './index.scss';
function getIcon(props) {
// console.log(props);
// console.log(props.expanded);
const { isLeaf, expanded ,selected} = props;
if (isLeaf) {
return <FileSvg color={selected ? "#2A61FF" : "#666"}/>;
}
return expanded ? <FolderExpandSvg color={"#666"}/> : <FolderSvg color={"#666"} />
// return <FolderSvg color={expanded ? "#2A61FF" : "#666"} />
}
class DirectoryTree extends React.Component {
static defaultProps = {
showIcon: true,
expandAction: 'click',
};
static getDerivedStateFromProps(nextProps) {
const newState = {};
if ('expandedKeys' in nextProps) {
newState.expandedKeys = nextProps.expandedKeys;
}
if ('selectedKeys' in nextProps) {
newState.selectedKeys = nextProps.selectedKeys;
}
return newState;
}
// state: DirectoryTreeState;
// tree: Tree;
// onDebounceExpand: (event: React.MouseEvent<HTMLElement>, node: AntTreeNode) => void;
// Shift click usage
// lastSelectedKey?: string;
// cachedSelectedKeys?: string[];
constructor(props) {
super(props);
const {
defaultExpandAll,
defaultExpandParent,
expandedKeys,
defaultExpandedKeys,
children,
} = props;
const { keyEntities } = convertTreeToEntities(children);
// Selected keys
this.state = {
selectedKeys: props.selectedKeys || props.defaultSelectedKeys || [],
};
// Expanded keys
if (defaultExpandAll) {
if (props.treeData) {
this.state.expandedKeys = getFullKeyListByTreeData(props.treeData);
} else {
this.state.expandedKeys = getFullKeyList(props.children);
}
} else if (defaultExpandParent) {
this.state.expandedKeys = conductExpandParent(
expandedKeys || defaultExpandedKeys,
keyEntities,
);
} else {
this.state.expandedKeys = expandedKeys || defaultExpandedKeys;
}
this.onDebounceExpand = debounce(this.expandFolderNode, 200, {
leading: true,
});
}
onExpand = (expandedKeys, info) => {
const { onExpand } = this.props;
this.setUncontrolledState({ expandedKeys });
// Call origin function
if (onExpand) {
return onExpand(expandedKeys, info);
}
return undefined;
};
onClick = (event, node) => {
const { onClick, expandAction } = this.props;
// Expand the tree
if (expandAction === 'click') {
this.onDebounceExpand(event, node);
}
if (onClick) {
onClick(event, node);
}
};
onDoubleClick = (event, node) => {
const { onDoubleClick, expandAction } = this.props;
// Expand the tree
if (expandAction === 'doubleClick') {
this.onDebounceExpand(event, node);
}
if (onDoubleClick) {
onDoubleClick(event, node);
}
};
onSelect = (keys, event) => {
const { onSelect, multiple, children } = this.props;
const { expandedKeys = [] } = this.state;
const { node, nativeEvent } = event;
const { eventKey = '' } = node.props;
const newState = {};
// We need wrap this event since some value is not same
const newEvent = {
...event,
selected: true, // Directory selected always true
};
// Windows / Mac single pick
const ctrlPick = nativeEvent.ctrlKey || nativeEvent.metaKey;
const shiftPick = nativeEvent.shiftKey;
// Generate new selected keys
let newSelectedKeys;
if (multiple && ctrlPick) {
// Control click
newSelectedKeys = keys;
this.lastSelectedKey = eventKey;
this.cachedSelectedKeys = newSelectedKeys;
newEvent.selectedNodes = convertDirectoryKeysToNodes(children, newSelectedKeys);
} else if (multiple && shiftPick) {
// Shift click
newSelectedKeys = Array.from(
new Set([
...(this.cachedSelectedKeys || []),
...calcRangeKeys(children, expandedKeys, eventKey, this.lastSelectedKey),
]),
);
newEvent.selectedNodes = convertDirectoryKeysToNodes(children, newSelectedKeys);
} else {
// Single click
newSelectedKeys = [eventKey];
this.lastSelectedKey = eventKey;
this.cachedSelectedKeys = newSelectedKeys;
newEvent.selectedNodes = [event.node];
}
newState.selectedKeys = newSelectedKeys;
if (onSelect) {
onSelect(newSelectedKeys, newEvent);
}
this.setUncontrolledState(newState);
};
setTreeRef = (node) => {
this.tree = node;
};
expandFolderNode = (event, node) => {
const { isLeaf } = node.props;
if (isLeaf || event.shiftKey || event.metaKey || event.ctrlKey) {
return;
}
// Get internal rc-tree
const internalTree = this.tree.tree;
// Call internal rc-tree expand function
// https://github.com/ant-design/ant-design/issues/12567
internalTree.onNodeExpand(event, node);
};
setUncontrolledState = (state) => {
const newState = omit(state, Object.keys(this.props));
if (Object.keys(newState).length) {
this.setState(newState);
}
};
renderDirectoryTree = ({ getPrefixCls }) => {
const { prefixCls: customizePrefixCls, className, ...props } = this.props;
const { expandedKeys, selectedKeys } = this.state;
const prefixCls = getPrefixCls('tree', customizePrefixCls);
const connectClassName = classNames(`${prefixCls}-directory`, className);
return (
<Tree
icon={getIcon}
ref={this.setTreeRef}
{...props}
prefixCls={prefixCls}
className={connectClassName}
expandedKeys={expandedKeys}
selectedKeys={selectedKeys}
onSelect={this.onSelect}
onClick={this.onClick}
onDoubleClick={this.onDoubleClick}
onExpand={this.onExpand}
/>
);
};
render() {
return <ConfigConsumer>{this.renderDirectoryTree}</ConfigConsumer>;
}
}
polyfill(DirectoryTree);
export default DirectoryTree;

View File

@ -0,0 +1,61 @@
.hide-file-icon.ant-tree.ant-tree-directory {
li span.ant-tree-switcher {
display: none !important;
}
// li[role="treeitem"]:hover > span.ant-tree-switcher,
// li.ant-tree-treenode-selected > span.ant-tree-switcher {
// z-index: 1000;
// display: inline-block !important;
// }
.ant-tree-node-content-wrapper{
display: inline-flex;
width: 100%;
}
.tree-title-icon{
display: none;
}
.ant-tree-node-content-wrapper:hover .tree-title-icon{
transition: all 0.3s;
display: inline-block;
}
&.ant-tree.ant-tree-directory
> li.ant-tree-treenode-selected
> span.ant-tree-node-content-wrapper::before,
&.ant-tree.ant-tree-directory
.ant-tree-child-tree
> li.ant-tree-treenode-selected
> span.ant-tree-node-content-wrapper::before {
background: #fff;
margin-top: -3px;
}
&.ant-tree.ant-tree-directory > li span.ant-tree-node-content-wrapper::before,
&.ant-tree.ant-tree-directory
.ant-tree-child-tree
> li
span.ant-tree-node-content-wrapper::before {
margin-top: -3px;
}
> li span.ant-tree-node-content-wrapper.ant-tree-node-selected,
.ant-tree-child-tree
> li
span.ant-tree-node-content-wrapper.ant-tree-node-selected {
color: #2a61ff;
}
.ant-tree-title{
display: inline-flex;
justify-content:space-between;
flex: auto;
}
}

View File

@ -0,0 +1,44 @@
import React, { useState } from 'react';
import * as ReactDOM from 'react-dom';
import LoginDialog from '../../../../modules/login/LoginDialog';
import './index.scss';
// 使
export default function DelModal(props) {
const div = document.createElement('div');
document.body.appendChild(div);
function destroy() {
const unmountResult = ReactDOM.unmountComponentAtNode(div);
if (unmountResult && div.parentNode) {
div.parentNode.removeChild(div);
}
}
function render() {
/**
* Sync render blocks React event. Let's make this async.
*/
setTimeout(() => {
ReactDOM.render(
<MyLoginDialog afterClose={destroy} />
,
div,
);
});
}
render();
}
function MyLoginDialog({afterClose}) {
const [isRender, setIsRender] = useState(true);
return (
<LoginDialog
isRender={isRender}
Modifyloginvalue={() => {setIsRender(false);afterClose()}}
/>
)
}

View File

@ -0,0 +1,56 @@
.delete-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;
}
.delete-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;
}
.delete-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;
}
}
}

View File

@ -0,0 +1,149 @@
import React, { useState } from 'react';
import * as ReactDOM from 'react-dom';
import { Modal, Button } from 'antd';
import './index.scss';
// 使
export default function DelModal(props) {
renderModal({ ...props, type: 'delete' })
}
export function confirmModal(props) {
renderModal({ ...props, type: 'confirm' })
}
function renderModal(props) {
const type = props.type;
const div = document.createElement('div');
document.body.appendChild(div);
function destroy() {
const unmountResult = ReactDOM.unmountComponentAtNode(div);
if (unmountResult && div.parentNode) {
div.parentNode.removeChild(div);
}
}
function modalType(type) {
if (type === 'delete') {
return <DeleteModal title="删除页面" contentTitle="确定要删除吗?" afterClose={destroy} {...props} />
} else if (type === 'confirm') {
return <ConfirmModal title="选择" afterClose={destroy} {...props} />
} else {
return <ConfirmModal title="选择" afterClose={destroy} {...props} />
}
}
function render() {
/**
* Sync render blocks React event. Let's make this async.
*/
setTimeout(() => {
ReactDOM.render(
modalType(type),
div,
);
});
}
render();
}
//
function DeleteModal({
onCancel,
onOk,
title,
contentTitle,
content,
afterClose,
okText,
cancelText,
}) {
const [visible, setVisible] = useState(true);
function onCancelModal() {
setVisible(false);
onCancel && onCancel()
}
function onSuccess() {
setVisible(false);
onOk && onOk();
}
return (
<Modal
visible={visible}
onCancel={onCancelModal}
afterClose={afterClose}
title={title}
className="myself-modal"
centered
footer={[
<Button key="back" onClick={onCancelModal}>
{cancelText||'取消'}
</Button>,
<Button className="foot-submit" key="submit" onClick={onSuccess}>
{okText||'确认删除'}
</Button>,
]}
>
<div>
<p className="delete-title">
<i className="red-circle iconfont icon-shanchu_tc_icon mr3"></i>
{contentTitle}</p>
<p className="delete-descibe">{content}</p>
</div>
</Modal>
)
}
//
function ConfirmModal({
onCancel,
onOk,
title,
contentTitle,
content,
okText,
cancelText,
afterClose,
}) {
const [visible, setVisible] = useState(true);
function onCancelModal() {
setVisible(false);
onCancel && onCancel()
}
function onSuccess() {
setVisible(false);
onOk && onOk();
}
return (
<Modal
visible={visible}
onCancel={onCancelModal}
afterClose={afterClose}
title={title}
className="myself-modal"
centered
footer={[
<Button key="back" onClick={onCancelModal}>
{cancelText||'取消'}
</Button>,
<Button className="foot-submit" key="submit" onClick={onSuccess}>
{okText||'确认'}
</Button>,
]}
>
<div>
{contentTitle && <p className="delete-title">{contentTitle}</p>}
<p className="delete-descibe">{content}</p>
</div>
</Modal>
)
}

View File

@ -0,0 +1,56 @@
.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;
}
.delete-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;
}
.delete-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;
}
}
}

View File

@ -0,0 +1,29 @@
import { httpUrl } from '../fetch';
export const editorConfig = {
placeholder: '请输入',
uploadImgServer: httpUrl + '/busiAttachments/upload',
uploadFileName: 'file',
uploadImgHeaders: {
'X-Requested-With': 'XMLHttpRequest'
},
excludeMenus: [
'list',
'todo',
'emoticon',
'video'
],
uploadImgHooks: {
// 图片上传并返回了结果,想要自己把图片插入到编辑器中
customInsert: function (insertImgFn, result) {
// insertImgFn 可把图片插入到编辑器,传入图片 src ,执行函数即可
if (result && result.data && result.data.id) {
insertImgFn(`${httpUrl}/busiAttachments/view/${result.data.id}`);
}
}
},
}
export const weekModal="| 工作项目 | 本周工作计划 | 本周完成情况 |下周计划 | 待协同事项 |\n| ------------ | ------------ | ------------ | ------------ | ------------ |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n\n 备注:";
export const monthModal="|工作项目 | 工作内容 | 项目进度情况 | 问题列表及解决方案| 下月工作计划 | 遗留未解决的问题 |\n| ------------ | ------------ | ------------ | ------------ | ------------ | ------------ |\n| | | | | | |\n| | | | | | |\n| | | | | | |\n| | | | | | |\n\n 月度总结:";

106
src/forge/Wiki/fetch.js Normal file
View File

@ -0,0 +1,106 @@
import { notification ,message} from 'antd';
import axios from 'axios';
import cookie from 'react-cookies';
import Login from './components/Login';
let actionUrl = '';
if (window.location.href.indexOf('localhost') > -1) {
// actionUrl = 'http://117.50.100.12:8008';
// actionUrl = 'http://192.168.31.74:8081';
actionUrl = "https://test-search.trustie.net";
} else if(window.location.href.indexOf('testforgeplus')>-1){
actionUrl = "https://test-search.trustie.net";
// actionUrl = 'https://testforgeplus.trustie.net';
axios.defaults.withCredentials = true;
}else if (window.location.href.indexOf('forgeplus') > -1) {
actionUrl = "https://wiki-api.trustie.net";
axios.defaults.withCredentials = true;
}
export const httpUrl = actionUrl;
export const TokenKey = 'autologin_trustie';
// 创建axios实例
const service = axios.create({
baseURL: httpUrl,
timeout: 10000, // 请求超时时间
});
// request拦截器
service.interceptors.request.use(config => {
if (cookie.load(TokenKey)) {
console.log(cookie.load(TokenKey));
config.headers['Authorization'] = cookie.load(TokenKey); // 让每个请求携带自定义token 请根据实际情况自行修改
}
if (window.location.port === "3007") {
// 模拟token为登录用户
const taskToken = sessionStorage.taskToken;
if (config.url.indexOf('?') === -1) {
config.url = `${config.url}?token=${taskToken}`;
} else {
config.url = `${config.url}&token=${taskToken}`;
}
}
return config;
}, error => {
// Do something with request error
console.log(error); // for debug
// Promise.reject(error);
});
// respone拦截器
service.interceptors.response.use(
response => {
const res = response||{};
if (res.status === 400) {
message.error(res.data.message || '操作失败');
return Promise.reject('error');
}
if (res.status === 401) {
message.error(res.data.message || '登录信息已过期');
return Promise.reject('error');
}
if (res.status === 403) {
message.error(res.data.message || '无权限!');
return Promise.reject('error');
}
if (res.status === 40001) {
notification.open({
message: "提示",
description: '账户或密码错误!',
});
return Promise.reject('error');
}
if (response.status !== 200 && res.status !== 200) {
notification.open({
message: "提示",
description: res.message,
});
} else {
return response.data;
}
},
error => {
console.log(error);
let res = error.response||{};
if (res.status === 400) {
message.error(res.data.message || '操作失败');
return Promise.reject('error');
}
if (res.status === 401) {
message.error(res.data.message || '登录信息已过期');
Login();
return Promise.reject('error');
}
if (res.status === 403) {
message.error(res.data.message || '无权限!');
return Promise.reject('error');
}
notification.open({
message: "提示",
description: error.message,
});
return Promise.reject(error);
}
);
export default service;

View File

@ -11,7 +11,10 @@ ul,ol,dl{
font-size: 22px; font-size: 22px;
font-weight: normal; font-weight: normal;
line-height: 30px; line-height: 30px;
max-width: 850px; max-width: 690px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
.projectN{ .projectN{
word-break: break-all; word-break: break-all;
} }

View File

@ -134,6 +134,7 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
}, },
toolbarIconsClass: { toolbarIconsClass: {
"line-break": "fa-minus", "line-break": "fa-minus",
"fullScreen":"iconfont icon-fangdaicon font-14"
}, },
toolbarCustomIcons: { toolbarCustomIcons: {
"inline-latex": "<a title='行内公式' class='latex' ><i name='inline-latex' class='fa iconfont icon-hangneigongshi font-14'></i></a>", "inline-latex": "<a title='行内公式' class='latex' ><i name='inline-latex' class='fa iconfont icon-hangneigongshi font-14'></i></a>",
@ -150,6 +151,10 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
} }
cm.replaceSelection(NULL_CH) cm.replaceSelection(NULL_CH)
}, },
"fullScreen":function(cm,icon,cursor,selection){
icon.addClass("none");
console.log(cm,icon)
},
"inline-latex": function (cm, icon, cursor, selection) { "inline-latex": function (cm, icon, cursor, selection) {
cm.replaceSelection("$$" + selection + "$$"); cm.replaceSelection("$$" + selection + "$$");
cm.setCursor(cursor.line, cursor.ch + 2); cm.setCursor(cursor.line, cursor.ch + 2);
@ -164,7 +169,8 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
lang: { lang: {
toolbar: { toolbar: {
"latex": "多行公式", "latex": "多行公式",
"line-break": "换行" "line-break": "换行",
"fullScreen":"开启全屏"
} }
}, },
onload: function () { onload: function () {
@ -229,7 +235,7 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
if (resizeBarEl.current) { if (resizeBarEl.current) {
let el = resizeBarEl.current let el = resizeBarEl.current
let dragging = false let dragging = false
let startY = 0 let startY = 0
function onMouseDown(e) { function onMouseDown(e) {
dragging = true dragging = true
startY = e.pageY startY = e.pageY