Compare commits

..

83 Commits

Author SHA1 Message Date
caishi 85bd0ffb62 merge develop 2021-05-08 17:22:18 +08:00
caishi 0f59544d10 编辑合并请求-url地址错误 2021-05-08 14:35:32 +08:00
caishi 57c8f256fa detail+同步镜像type=2的才不需要合并请求 2021-05-07 17:40:44 +08:00
caishi 0470da643f 导航-字体颜色 2021-05-07 16:33:32 +08:00
caishi 878ff76b00 merge 2021-05-07 16:29:32 +08:00
caishi d6e7666607 统一项目简介、项目概览 2021-05-07 16:27:33 +08:00
caishi 138db0b0cb merge 2021-05-06 17:24:24 +08:00
caishi ba81f51e76 设置所有标签的marginbottom为0 2021-05-06 17:23:15 +08:00
caishi 3ca1ce6c1b merge 2021-05-06 17:23:10 +08:00
caishi d4550d44e9 04-28休假期修改issue --需合并至其它分支(合并请求相关) 2021-04-28 20:24:14 +08:00
caishi 0138eb2f1e 头部不设置默认logo 2021-04-28 13:50:14 +08:00
caishi e1aef30b9d 组织团队-无数据显示错误 2021-04-27 09:46:49 +08:00
caishi 277ba72f91 代码库编辑文件-切换到其它目录后要重新将编辑状态改为显示状态 2021-04-25 17:51:43 +08:00
caishi 6a58a468f9 样式覆盖 2021-04-23 18:04:23 +08:00
caishi 14486724fa +上 关注后不需要提示 2021-04-23 16:14:32 +08:00
caishi 3201b7265b +上 贡献者悬浮框里增加的跳转链接不要新开页 2021-04-23 16:14:22 +08:00
caishi f774ce974d 贡献者-悬浮内容增加跳转链接 2021-04-23 16:14:06 +08:00
caishi fdca717eeb imageUrl + / 2021-04-23 16:13:55 +08:00
caishi 4b304ead34 个人中心关注-关注或者取消关注未更新状态 2021-04-23 16:13:45 +08:00
caishi 67d914ddb6 贡献者-悬浮卡片-测试版1 2021-04-23 16:13:35 +08:00
caishi e6020c3e13 发布评论者头像路径错误 2021-04-23 16:13:18 +08:00
caishi af2feeb34f 新建组织-组织账号正则 2021-04-23 16:12:58 +08:00
caishi 40918bf1d7 merge develop 2021-04-23 16:12:35 +08:00
caishi 8a5a7a0647 md文件要用Markdown渲染 2021-04-20 15:36:40 +08:00
caishi 93ba9c6a98 合并请求-提出申请者头像显示问题 2021-04-20 11:18:24 +08:00
caishi 12322f8785 合并--组织团队设置、团队项目列表的跳转login和显示的name 2021-04-20 11:03:41 +08:00
caishi 8c1bebcfdc 切换左侧目录,选择不同的文件时,文件详情没有更新 2021-04-20 10:31:19 +08:00
caishi 04bdbd7c30 all-默认头像(首字母加背景颜色) 2021-04-20 09:46:19 +08:00
caishi f57ee7fd99 个人主页头像url 2021-04-20 09:46:07 +08:00
caishi 1e0f522f4a 上线后的getImageURL也不用在前面加/ + 一些小样式修改 2021-04-20 09:45:56 +08:00
caishi 798d919447 imageurl接口统一返回带iamges的字段 2021-04-20 09:44:58 +08:00
caishi 1f6a4bda6c readme-文件增加一个目录下拉icon 2021-04-20 09:42:47 +08:00
caishi 0d546f4789 资源库数量显示错误 2021-04-20 09:40:57 +08:00
caishi 44996b5dea 组织团队-新增一个团队标识 2021-04-20 09:40:45 +08:00
caishi 134d79faa3 新建团队板块无边框 2021-04-20 09:40:32 +08:00
caishi 2677efec83 合并冲突 2021-04-20 09:40:13 +08:00
caishi 7482d1184c 资源库不需要按引用次数排序 2021-04-20 09:39:09 +08:00
caishi 58fb71b324 组织-项目-切换协作者管理和团队管理时会重复调用增加成员接口 2021-04-13 17:14:32 +08:00
caishi 5517b28062 去掉右侧悬浮手册按钮 2021-04-09 14:00:57 +08:00
caishi 0bd7f7d900 项目详情右侧增加实践课程链接的显示 2021-04-08 15:38:41 +08:00
caishi 9cfe2c186e entries接口传的branch值为undefined 2021-04-07 18:47:26 +08:00
caishi e4c54622b8 账号同步框提示文字错误 2021-04-07 15:00:09 +08:00
caishi 21902543f4 新增组织账号,组织名称增加新的check条件 2021-04-06 18:40:59 +08:00
caishi e541e91a06 仓库设置页面增加资源库配置项 2021-04-06 17:35:13 +08:00
caishi b6dc01b0be 资源库模块测试版第一次上线 2021-04-06 17:17:40 +08:00
caishi f0858e7ecc 列表的type字段为头像跳转到个人中心或者组织的判断依据 2021-04-06 11:45:37 +08:00
caishi f9f79e0365 资源库部分接口调试 2021-04-06 11:37:17 +08:00
caishi 8903363695 合并请求分页 2021-04-02 18:57:10 +08:00
caishi b9a8becec3 合并资源库 2021-04-02 17:32:20 +08:00
caishi 2fcd2fd066 冲突 2021-04-02 14:10:32 +08:00
caishi 898ad15343 构建列表 2021-04-02 12:01:37 +08:00
caishi 1cf7655e63 tips(易修、复刻) 2021-04-02 10:00:48 +08:00
caishi 2383710c54 通知、消息的地址,trustie改为educoder 2021-04-01 15:46:51 +08:00
caishi 3b3d6dc8b1 工作流author 2021-03-31 17:13:10 +08:00
caishi c74c40b73e 冲突 2021-03-31 14:06:13 +08:00
caishi c5bbcd9c1d color 2021-03-31 11:40:19 +08:00
caishi 74deb640a9 合并 2021-03-31 11:37:05 +08:00
caishi 534da2115a 头部 active 2021-03-30 13:49:38 +08:00
caishi f2ef3183ea toubu 2021-03-30 13:46:52 +08:00
caishi 1182a45cdc Merge branch 'develop' into develop_educoder 2021-03-30 11:51:06 +08:00
caishi 29f37b9760 代码冲突 2021-03-26 10:04:01 +08:00
caishi f5fa45e1ce 新建项目 2021-03-25 22:05:27 +08:00
caishi 97bf4a5a46 readme 2021-03-25 14:41:08 +08:00
caishi 5e4d3a92a1 header 2021-03-24 14:14:00 +08:00
caishi 29f25a585d Merge branch 'develop_new' into develop_educoder
# Conflicts:
#	src/forge/Head/Header.js
#	src/modules/tpm/TPMIndex.css
#	src/modules/tpm/TPMIndexHOC.js
2021-03-24 14:11:12 +08:00
caishi 6bd57d8877 style 2021-03-23 17:57:51 +08:00
caishi e7aa871b53 condition 2021-03-23 17:42:57 +08:00
caishi 9c22457249 delete 2021-03-23 17:00:09 +08:00
caishi 68b1296652 Merge branch 'develop_new' into develop_educoder
# Conflicts:
#	src/modules/tpm/NewHeader.js
2021-03-23 16:13:36 +08:00
caishi 0f7c8a4b5d style 2021-03-22 16:54:41 +08:00
caishi 98289b05aa 未登录不弹框 2021-03-22 14:19:50 +08:00
caishi 83086e7d61 导航栏和底部 2021-03-22 13:51:02 +08:00
caishi 76c88a659a Merge branch 'develop_new' into develop_educoder 2021-03-22 11:24:23 +08:00
caishi ae8ece2695 Merge branch 'develop_new' into develop_educoder 2021-03-22 09:45:46 +08:00
caishi 93994cb785 Merge branch 'develop_new' into develop_educoder 2021-03-19 17:22:14 +08:00
caishi 917958c880 Merge branch 'develop_new' into develop_educoder 2021-03-19 16:31:51 +08:00
caishi 65b906f49f update 2021-03-19 16:31:46 +08:00
caishi 90be5ad793 Merge branch 'develop_new' into develop_educoder 2021-03-19 15:54:10 +08:00
caishi eeaefc5810 隐藏操作手册 2021-03-19 15:48:00 +08:00
caishi 284bf67f82 educoder和forge用户的密码是否一致 2021-03-19 13:44:02 +08:00
caishi fbdde52651 弹框修改接口 2021-03-19 11:52:04 +08:00
caishi 64dcdce51b Merge branch 'develop_new' into develop_educoder 2021-03-19 11:35:20 +08:00
caishi 741a461f7e 邮箱绑定 2021-03-19 09:33:22 +08:00
349 changed files with 12656 additions and 23701 deletions

1190
.idea/workspace.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +0,0 @@
{
}

124
LICENSE
View File

@ -1,124 +0,0 @@
木兰宽松许可证, 第2版
2020年1月 http://license.coscl.org.cn/MulanPSL2
您对“软件”的复制、使用、修改及分发受木兰宽松许可证第2版“本许可证”的如下条款的约束
0. 定义
“软件” 是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
“贡献” 是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
“贡献者” 是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
“法人实体” 是指提交贡献的机构及其“关联实体”。
“关联实体” 是指对“本许可证”下的行为方而言控制、受控制或与其共同受控制的机构此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
1. 授予版权许可
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。
2. 授予专利许可
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。
3. 无商标许可
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可但您为满足第4条规定的声明义务而必须使用除外。
4. 分发限制
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
5. 免责声明与责任限制
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。
6. 语言
“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。
条款结束
如何将木兰宽松许可证第2版应用到您的软件
如果您希望将木兰宽松许可证第2版应用到您的新软件为了方便接收者查阅建议您完成如下三步
1 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
2 请您在软件包的一级目录下创建以“LICENSE”为名的文件将整个许可证文本放入该文件中
3 请将如下声明文本放入每个源文件的头部注释中。
Copyright (c) [Year] [name of copyright holder]
[Software Name] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
Mulan Permissive Software LicenseVersion 2
Mulan Permissive Software LicenseVersion 2 (Mulan PSL v2)
January 2020 http://license.coscl.org.cn/MulanPSL2
Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions:
0. Definition
Software means the program and related documents which are licensed under this License and comprise all Contribution(s).
Contribution means the copyrightable work licensed by a particular Contributor under this License.
Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License.
Legal Entity means the entity making a Contribution and all its Affiliates.
Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, control means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity.
1. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not.
2. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.
3. No Trademark License
No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in section 4.
4. Distribution Restriction
You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software.
5. Disclaimer of Warranty and Limitation of Liability
THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW ITS CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
6. Language
THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL.
END OF THE TERMS AND CONDITIONS
How to Apply the Mulan Permissive Software LicenseVersion 2 (Mulan PSL v2) to Your Software
To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps:
Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner;
Create a file named "LICENSE" which contains the whole context of this License in the first directory of your software package;
Attach the statement to the appropriate annotated syntax at the beginning of each source file.
Copyright (c) [Year] [name of copyright holder]
[Software Name] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.

View File

@ -19,8 +19,7 @@ const getClientEnvironment = require("./env");
let publicPath = "/react/build/";
const publicUrl = publicPath.slice(0, -1);
// const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false";
const shouldUseSourceMap = process.env.NODE_ENV !== "production";
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false";
const env = getClientEnvironment(publicPath);
// This is the production configuration.
@ -55,8 +54,7 @@ module.exports = {
},
bail: true,
mode: "production",
// devtool: false, //测试版
devtool: shouldUseSourceMap?'source-map':false,
devtool: false, //测试版
entry: [require.resolve("./polyfills"), paths.appIndexJs],
output: {
path: paths.appBuild,

9786
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "forge",
"version": "3.0.0",
"version": "0.1.0",
"private": true,
"dependencies": {
"@monaco-editor/react": "^2.3.0",
@ -14,7 +14,6 @@
"babel-jest": "20.0.3",
"babel-loader": "7.1.2",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-polyfill": "^6.26.0",
"babel-preset-react-app": "^3.1.1",
"babel-runtime": "6.26.0",
"bizcharts": "^3.5.8",
@ -22,17 +21,15 @@
"case-sensitive-paths-webpack-plugin": "2.1.1",
"chalk": "1.1.3",
"classnames": "^2.2.5",
"clipboard": "^2.0.8",
"clipboard": "^2.0.6",
"code-prettify": "^0.1.0",
"codemirror": "^5.53.0",
"connected-react-router": "4.4.1",
"cross-env": "^7.0.3",
"css-loader": "^3.5.2",
"dompurify": "^2.0.15",
"dotenv": "4.0.0",
"dotenv-expand": "4.2.0",
"echarts": "^4.9.0",
"echarts-wordcloud": "^2.0.0",
"echarts": "^4.7.0",
"editor.md": "^1.5.0",
"eslint": "4.10.0",
"eslint-config-react-app": "^2.1.0",
@ -49,7 +46,6 @@
"install": "^0.12.2",
"jest": "20.0.4",
"js-base64": "^2.5.2",
"js2wordcloud": "^1.1.12",
"katex": "^0.11.1",
"lodash": "^4.17.15",
"loglevel": "^1.6.8",
@ -66,7 +62,7 @@
"postcss-loader": "2.0.8",
"promise": "8.0.1",
"prop-types": "^15.6.1",
"qrcode.react": "^1.0.1",
"qrcode.react": "^1.0.0",
"qs": "^6.9.3",
"quill": "^1.3.7",
"quill-delta-to-html": "^0.11.0",
@ -96,7 +92,6 @@
"react-resizable": "^1.10.1",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"react-slick": "^0.28.1",
"react-split-pane": "^0.1.91",
"react-url-query": "^1.5.0",
"react-zmage": "^0.8.5-beta.31",
@ -104,11 +99,9 @@
"redux-thunk": "2.3.0",
"rsuite": "^4.3.4",
"sass-loader": "7.3.1",
"save-dev": "0.0.1-security",
"scroll-into-view": "^1.14.2",
"showdown": "^1.9.1",
"showdown-katex": "^0.8.0",
"slick-carousel": "^1.8.1",
"store": "^2.0.12",
"style-loader": "0.19.0",
"styled-components": "^4.4.1",
@ -118,14 +111,12 @@
"webpack-dev-server": "^3.10.3",
"webpack-manifest-plugin": "^2.2.0",
"whatwg-fetch": "2.0.3",
"wrap-md-editor": "^0.2.20",
"xterm": "4.8.1",
"xterm-addon-fit": "0.4.0"
"wrap-md-editor": "^0.2.20"
},
"scripts": {
"start": "node --max_old_space_size=15360 scripts/start.js",
"build": "cross-env NODE_ENV=production node --max_old_space_size=15360 scripts/build.js",
"test-build": "cross-env NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js",
"build": "NODE_ENV=production node --max_old_space_size=15360 scripts/build.js",
"test-build": "NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js",
"pre-build": "NODE_ENV=preBuild node --max_old_space_size=15360 scripts/build.js",
"gen_stats": "NODE_ENV=production webpack --profile --config=./config/webpack.config.prod.js --json > stats.json",
"ana": "webpack-bundle-analyzer ./stats.json",
@ -187,7 +178,7 @@
"eslintConfig": {
"extends": "react-app"
},
"proxy": "http://localhost:3001",
"proxy": "http://localhost:3000",
"port": "3007",
"devDependencies": {
"@babel/runtime": "7.0.0-beta.51",
@ -195,7 +186,6 @@
"babel-core": "^6.26.0",
"babel-plugin-import": "^1.13.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
@ -206,7 +196,6 @@
"node-sass": "^4.12.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"purgecss": "^2.1.2",
"react-json-view": "^1.21.3",
"reqwest": "^2.0.5",
"resize-observer-polyfill": "^1.5.1",
"terser-webpack-plugin": "^2.3.5",

View File

@ -38,6 +38,29 @@
box-sizing: border-box;
}
.head-nav ul#header-nav li {
float: left;
height: 60px;
line-height: 60px;
margin-right: 30px;
cursor: pointer;
position: relative;
font-size: 16px
}
.head-nav ul#header-nav li.active:after {
content: '';
position: absolute;
left: 0px;
top: auto;
bottom: 10px;
right: auto;
height: 2px;
width: 14px;
background-color: #459be5;
}
.nav-img {
position: absolute;
top: 2px;
@ -269,10 +292,6 @@ em.vertical-line {
overflow: hidden;
}
/*底部*/
.newFooter {
max-height: 110px;
}
.newFooter {
position: absolute;

View File

@ -25,9 +25,6 @@ html {
min-width: 1200px
}
.newFooter {
max-height: 110px;
}
.newFooter {
position: absolute;
@ -114,6 +111,14 @@ a:visited {
color: #898989;
}
a:hover {
color: #FF7500;
}
a:hover.fa {
color: #FF7500;
}
input,
textarea,
select {

View File

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

View File

@ -1,4 +1,3 @@
@charset "utf-8";
/* 头部 */
.header {
width: 100%;
@ -1272,7 +1271,7 @@ html body {
font-size: 14px;
line-height: 2.0;
background: #fafafa;
font-family: "Microsoft YaHei", "SimSun";
font-family: "微软雅黑", "宋体";
color: #05101a;
height: 100%;
position: relative;
@ -1365,6 +1364,10 @@ a:visited {
color: #05101a;
}
a:hover {
color: #459be5;
}
ol,
ul,
li {
@ -1471,7 +1474,7 @@ a.edu-txt-w80,
/*隐藏*/
.none {
display: none!important;
display: none
}
.block {
@ -1520,15 +1523,7 @@ a.edu-txt-w80,
.font-16 {
font-size: 16px !important;
}
.weight400{
font-weight: 400;
}
.weight500{
font-weight: 500;
}
.weight{
font-weight: bold;
}
.font-17 {
font-size: 17px !important;
}
@ -1548,9 +1543,6 @@ a.edu-txt-w80,
.font-25 {
font-size: 25px !important;
}
.font-26 {
font-size: 26px !important;
}
.font-24 {
font-size: 24px !important;
@ -1572,9 +1564,6 @@ a.edu-txt-w80,
font-size: 36px !important;
}
.font-40 {
font-size: 40px !important;
}
.font-50 {
font-size: 50px !important;
}
@ -1760,20 +1749,12 @@ a.decoration {
margin-bottom: 10px;
}
.mb12 {
margin-bottom: 12px;
}
.mb13 {
margin-bottom: 13px;
}
.mb14 {
margin-bottom: 14px;
}
.mb15 {
margin-bottom: 15px!important;
margin-bottom: 15px;
}
.mb16 {
@ -2444,23 +2425,13 @@ input::-ms-clear {
.color-grey-c {
color: #ccc !important;
}
a.hoverLine:hover{
text-decoration: underline;
}
.color-grey-cd {
color: #cdcdcd !important;
}
.color-grey-d {
color: #ddd;
}
.color-grey-9 {
color: #999 !important;
}
a:hover{
color: #466AFF !important;
color: #999999 !important;
}
.color-grey-98 {
@ -2495,23 +2466,33 @@ a:hover{
a.color-grey-name:hover,
a.color-dark:hover,
a.color-grey-6:hover,
a.color-grey-3:hover,a.color-ooo:hover {
color: #2A61FF !important;
a.color-grey-3:hover {
color: #4cacff !important;
}
a.color-grey-9:hover,
a.color-grey-8:hover,
a.color-grey-c:hover {
color: #111C24 !important;
}
/*蓝色*/
.color-blue {
color: #2A61FF !important;
}
.color-blue-file {
color: #4598FA!important;
color: #4CACFF !important;
}
/* 绿色 */
.color-green-file{
color: #28BD6C;
}
/*主*/
.color-blue_4C {
color: #4CACFF !important;
}
a.color-blue:hover,
a.color-blue_4C:hover {
color: #459BE6 !important;
}
/*橙色*/
.color-orange {
@ -3429,7 +3410,7 @@ a.user_bluebg_btn {
}
.cdefault {
cursor: default!important;
cursor: default
}
@ -3604,6 +3585,42 @@ a.user_bluebg_btn {
margin-right: 5px;
}
/*-------------------个人主页:右侧提示区域--------------------------*/
.-task-sidebar {
position: fixed;
width: 40px;
height: 180px;
right: 0;
bottom: 80px;
z-index: 10;
}
.-task-sidebar div {
height: 40px;
line-height: 40px;
box-sizing: border-box;
width: 40px;
background: #4CACFF;
color: #fff;
font-size: 20px;
text-align: center;
margin-bottom: 5px;
border-radius: 4px;
}
.-task-sidebar div i {
color: #fff;
}
.-task-sidebar div i:hover {
color: #fff !important;
}
.gotop {
background-color: rgba(208, 207, 207, 0.5) !important;
padding: 0px !important;
}
/***** loading ******/
/*****载入中******/
@ -3928,21 +3945,11 @@ html>body #ajax-indicator {
max-height: 340px;
}/*头部导航条样式---2018-03-19--by-cs*/
.privateTag{
display: block;
padding:0px 6px;
border-radius: 12px;
border:1px solid #2FC25B;
height: 18px;
line-height: 18px;
font-size: 12px;
margin-left: 10px;
color: #2FC25B;
}
.head-nav {
text-align: center;
height: 70px;
box-sizing: border-box;
min-width: 780px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@ -3964,14 +3971,14 @@ html>body #ajax-indicator {
cursor: pointer;
position: relative;
font-size: 16px;
padding-right:40px;
padding:0px 20px;
}
.head-nav ul#header-nav li a {
display: block;
height: 100%;
width: 100%;
color: #333;
color: #fff;
font-size: 16px;
}
@ -6705,10 +6712,4 @@ p{
right: 0px;
top:4px;
color: #999;
}
.ant-input, .ant-input .ant-input-suffix{
background-color: #fff!important;
}
.has-error .ant-input{
background-color: #FEF1F0!important;
}

File diff suppressed because one or more lines are too long

BIN
public/css/iconfont.eot Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -5,916 +5,6 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "24656750",
"name": "文件",
"font_class": "wenjian7",
"unicode": "e8e0",
"unicode_decimal": 59616
},
{
"icon_id": "630094",
"name": "向右箭头",
"font_class": "xiangyoujiantou",
"unicode": "e8de",
"unicode_decimal": 59614
},
{
"icon_id": "630095",
"name": "向左箭头",
"font_class": "xiangzuojiantou",
"unicode": "e8df",
"unicode_decimal": 59615
},
{
"icon_id": "24600282",
"name": "浏览icon@2x",
"font_class": "a-liulanicon2x",
"unicode": "e8dd",
"unicode_decimal": 59613
},
{
"icon_id": "24567893",
"name": "文件icon",
"font_class": "wenjianicon",
"unicode": "e8dc",
"unicode_decimal": 59612
},
{
"icon_id": "24527422",
"name": "圆圈@2x",
"font_class": "a-yuanquan2x",
"unicode": "e8db",
"unicode_decimal": 59611
},
{
"icon_id": "24378423",
"name": "项目标签",
"font_class": "xiangmubiaoqian",
"unicode": "e8da",
"unicode_decimal": 59610
},
{
"icon_id": "24368060",
"name": "icon",
"font_class": "icon",
"unicode": "e8ce",
"unicode_decimal": 59598
},
{
"icon_id": "24368061",
"name": "tar",
"font_class": "tar",
"unicode": "e8cf",
"unicode_decimal": 59599
},
{
"icon_id": "24289113",
"name": "复制 (2)",
"font_class": "a-fuzhi2",
"unicode": "e8d0",
"unicode_decimal": 59600
},
{
"icon_id": "24289114",
"name": "附件",
"font_class": "fujian1",
"unicode": "e8d1",
"unicode_decimal": 59601
},
{
"icon_id": "24289115",
"name": "编 辑",
"font_class": "a-bianji1",
"unicode": "e8d2",
"unicode_decimal": 59602
},
{
"icon_id": "24289116",
"name": "版本icon",
"font_class": "banbenicon",
"unicode": "e8d3",
"unicode_decimal": 59603
},
{
"icon_id": "24289117",
"name": "删除icon",
"font_class": "shanchuicon2",
"unicode": "e8d4",
"unicode_decimal": 59604
},
{
"icon_id": "24289118",
"name": "垃圾桶_icon@3x",
"font_class": "a-lajitong_icon3x",
"unicode": "e8d5",
"unicode_decimal": 59605
},
{
"icon_id": "24289119",
"name": "下拉按钮",
"font_class": "xialaanniu2",
"unicode": "e8d6",
"unicode_decimal": 59606
},
{
"icon_id": "24289120",
"name": "下载-icon",
"font_class": "xiazai-icon",
"unicode": "e8d7",
"unicode_decimal": 59607
},
{
"icon_id": "24289121",
"name": "master_icon",
"font_class": "master_icon1",
"unicode": "e8d8",
"unicode_decimal": 59608
},
{
"icon_id": "24289122",
"name": "上传icon",
"font_class": "shangchuanicon",
"unicode": "e8d9",
"unicode_decimal": 59609
},
{
"icon_id": "24059956",
"name": "个人资料",
"font_class": "gerenziliao1",
"unicode": "e8c7",
"unicode_decimal": 59591
},
{
"icon_id": "24059409",
"name": "里程碑icon",
"font_class": "lichengbeiicon",
"unicode": "e885",
"unicode_decimal": 59525
},
{
"icon_id": "24059410",
"name": "仓库设置icon",
"font_class": "cangkushezhiicon",
"unicode": "e889",
"unicode_decimal": 59529
},
{
"icon_id": "24059411",
"name": "动态icon",
"font_class": "dongtaiicon",
"unicode": "e88a",
"unicode_decimal": 59530
},
{
"icon_id": "24059412",
"name": "工作流icon",
"font_class": "gongzuoliuicon",
"unicode": "e88b",
"unicode_decimal": 59531
},
{
"icon_id": "24059413",
"name": "易修icon",
"font_class": "yixiuicon1",
"unicode": "e89b",
"unicode_decimal": 59547
},
{
"icon_id": "24059414",
"name": "wiki icon",
"font_class": "a-wikiicon1",
"unicode": "e8c6",
"unicode_decimal": 59590
},
{
"icon_id": "24047186",
"name": "代码库icon",
"font_class": "daimakuicon1",
"unicode": "e8c5",
"unicode_decimal": 59589
},
{
"icon_id": "24047189",
"name": "我的通知",
"font_class": "wodetongzhi",
"unicode": "e8c8",
"unicode_decimal": 59592
},
{
"icon_id": "24047190",
"name": "通知管理",
"font_class": "tongzhiguanli",
"unicode": "e8c9",
"unicode_decimal": 59593
},
{
"icon_id": "24047191",
"name": "选中",
"font_class": "xuanzhong3",
"unicode": "e8ca",
"unicode_decimal": 59594
},
{
"icon_id": "24047192",
"name": "系统通知icon",
"font_class": "xitongtongzhiicon",
"unicode": "e8cb",
"unicode_decimal": 59595
},
{
"icon_id": "24047193",
"name": "消息",
"font_class": "xiaoxi2",
"unicode": "e8cc",
"unicode_decimal": 59596
},
{
"icon_id": "24047194",
"name": "ssh密钥",
"font_class": "sshmiyue",
"unicode": "e8cd",
"unicode_decimal": 59597
},
{
"icon_id": "24014152",
"name": "个人资料",
"font_class": "gerenziliao",
"unicode": "e8c4",
"unicode_decimal": 59588
},
{
"icon_id": "23655968",
"name": "新手指引",
"font_class": "xinshouzhiyin",
"unicode": "e8e4",
"unicode_decimal": 59620
},
{
"icon_id": "23655969",
"name": "新建项目",
"font_class": "xinjianxiangmu",
"unicode": "e8e6",
"unicode_decimal": 59622
},
{
"icon_id": "23658111",
"name": "加入课堂",
"font_class": "jiaruketang1",
"unicode": "e8e9",
"unicode_decimal": 59625
},
{
"icon_id": "23791639",
"name": "项目公告",
"font_class": "xiangmugonggao",
"unicode": "e8c2",
"unicode_decimal": 59586
},
{
"icon_id": "23791640",
"name": "成果",
"font_class": "chengguo",
"unicode": "e8c3",
"unicode_decimal": 59587
},
{
"icon_id": "23791410",
"name": "成交公告",
"font_class": "chengjiaogonggao",
"unicode": "e8c0",
"unicode_decimal": 59584
},
{
"icon_id": "23791411",
"name": "技术资产",
"font_class": "jishuzichan",
"unicode": "e8c1",
"unicode_decimal": 59585
},
{
"icon_id": "23790928",
"name": "废标公告",
"font_class": "feibiaogonggao",
"unicode": "e8bc",
"unicode_decimal": 59580
},
{
"icon_id": "23790929",
"name": "中标公告",
"font_class": "zhongbiaogonggao",
"unicode": "e8bd",
"unicode_decimal": 59581
},
{
"icon_id": "23790930",
"name": "更正公告",
"font_class": "gengzhenggonggao",
"unicode": "e8be",
"unicode_decimal": 59582
},
{
"icon_id": "23790931",
"name": "招标公告",
"font_class": "zhaobiaogonggao",
"unicode": "e8bf",
"unicode_decimal": 59583
},
{
"icon_id": "23732532",
"name": "文件",
"font_class": "wenjian6",
"unicode": "e8ba",
"unicode_decimal": 59578
},
{
"icon_id": "23732533",
"name": "文件夹",
"font_class": "wenjianjia4",
"unicode": "e8bb",
"unicode_decimal": 59579
},
{
"icon_id": "23642443",
"name": "取消关注",
"font_class": "quxiaoguanzhu",
"unicode": "e89a",
"unicode_decimal": 59546
},
{
"icon_id": "23642444",
"name": "点赞_icon",
"font_class": "dianzan_icon",
"unicode": "e8a2",
"unicode_decimal": 59554
},
{
"icon_id": "23639530",
"name": "文件",
"font_class": "wenjian5",
"unicode": "e896",
"unicode_decimal": 59542
},
{
"icon_id": "23639533",
"name": "文件夹",
"font_class": "wenjianjia3",
"unicode": "e8a9",
"unicode_decimal": 59561
},
{
"icon_id": "23639440",
"name": "复制icon",
"font_class": "fuzhiicon",
"unicode": "e886",
"unicode_decimal": 59526
},
{
"icon_id": "23639422",
"name": "主页-fill",
"font_class": "zhuye-fill",
"unicode": "e876",
"unicode_decimal": 59510
},
{
"icon_id": "23639423",
"name": "代码库icon",
"font_class": "daimakuicon",
"unicode": "e884",
"unicode_decimal": 59524
},
{
"icon_id": "23572260",
"name": "新建",
"font_class": "xinjian2",
"unicode": "e8b0",
"unicode_decimal": 59568
},
{
"icon_id": "23567674",
"name": "协议icon",
"font_class": "xieyiicon",
"unicode": "e870",
"unicode_decimal": 59504
},
{
"icon_id": "23567675",
"name": "内存icon",
"font_class": "neicunicon",
"unicode": "e891",
"unicode_decimal": 59537
},
{
"icon_id": "23567676",
"name": "自述文件_icon",
"font_class": "zishuwenjian_icon",
"unicode": "e8a6",
"unicode_decimal": 59558
},
{
"icon_id": "23472253",
"name": "标签icon",
"font_class": "biaoqianicon",
"unicode": "e882",
"unicode_decimal": 59522
},
{
"icon_id": "23472254",
"name": "编 辑",
"font_class": "a-bianji",
"unicode": "e883",
"unicode_decimal": 59523
},
{
"icon_id": "23472258",
"name": "链接icon",
"font_class": "lianjieicon",
"unicode": "e887",
"unicode_decimal": 59527
},
{
"icon_id": "23472259",
"name": "合并请求icon",
"font_class": "hebingqingqiuicon",
"unicode": "e888",
"unicode_decimal": 59528
},
{
"icon_id": "23472263",
"name": "默认点赞_icon",
"font_class": "morendianzan_icon",
"unicode": "e88e",
"unicode_decimal": 59534
},
{
"icon_id": "23472265",
"name": "目录icon",
"font_class": "muluicon",
"unicode": "e894",
"unicode_decimal": 59540
},
{
"icon_id": "23472267",
"name": "设 置",
"font_class": "a-shezhi",
"unicode": "e899",
"unicode_decimal": 59545
},
{
"icon_id": "23472269",
"name": "提交icon",
"font_class": "tijiaoicon",
"unicode": "e89e",
"unicode_decimal": 59550
},
{
"icon_id": "23472270",
"name": "默认关注_ICON",
"font_class": "morenguanzhu_ICON",
"unicode": "e89f",
"unicode_decimal": 59551
},
{
"icon_id": "23472272",
"name": "下拉按钮",
"font_class": "xialaanniu1",
"unicode": "e8a4",
"unicode_decimal": 59556
},
{
"icon_id": "23472276",
"name": "左滑icon",
"font_class": "zuohuaicon",
"unicode": "e8b5",
"unicode_decimal": 59573
},
{
"icon_id": "23472277",
"name": "master_icon",
"font_class": "master_icon",
"unicode": "e8b6",
"unicode_decimal": 59574
},
{
"icon_id": "23472278",
"name": "默认复刻_icon",
"font_class": "morenfuke_icon",
"unicode": "e8b7",
"unicode_decimal": 59575
},
{
"icon_id": "23472279",
"name": "wiki icon",
"font_class": "a-wikiicon",
"unicode": "e8b8",
"unicode_decimal": 59576
},
{
"icon_id": "23472280",
"name": "易修icon",
"font_class": "yixiuicon",
"unicode": "e8b9",
"unicode_decimal": 59577
},
{
"icon_id": "23436350",
"name": "缩放",
"font_class": "suofang",
"unicode": "e87f",
"unicode_decimal": 59519
},
{
"icon_id": "23436351",
"name": "放大icon",
"font_class": "fangdaicon",
"unicode": "e881",
"unicode_decimal": 59521
},
{
"icon_id": "23384231",
"name": "搜索_icon",
"font_class": "sousuo_icon1",
"unicode": "e873",
"unicode_decimal": 59507
},
{
"icon_id": "23384232",
"name": "欢迎_icon",
"font_class": "huanying_icon",
"unicode": "e878",
"unicode_decimal": 59512
},
{
"icon_id": "23384233",
"name": "文件夹",
"font_class": "wenjianjia2",
"unicode": "e879",
"unicode_decimal": 59513
},
{
"icon_id": "23384234",
"name": "删除icon",
"font_class": "shanchuicon1",
"unicode": "e87a",
"unicode_decimal": 59514
},
{
"icon_id": "23261798",
"name": "请求icon",
"font_class": "qingqiuicon",
"unicode": "e871",
"unicode_decimal": 59505
},
{
"icon_id": "23261799",
"name": "响应icon",
"font_class": "xiangyingicon",
"unicode": "e87c",
"unicode_decimal": 59516
},
{
"icon_id": "23144143",
"name": "多选选中",
"font_class": "duoxuanxuanzhong",
"unicode": "e88f",
"unicode_decimal": 59535
},
{
"icon_id": "23144144",
"name": "错误icon",
"font_class": "cuowuicon",
"unicode": "e890",
"unicode_decimal": 59536
},
{
"icon_id": "23144146",
"name": "成功icon",
"font_class": "chenggongicon",
"unicode": "e892",
"unicode_decimal": 59538
},
{
"icon_id": "23144147",
"name": "未选中响应icon",
"font_class": "weixuanzhongxiangyingicon",
"unicode": "e893",
"unicode_decimal": 59539
},
{
"icon_id": "23144149",
"name": "必填icon",
"font_class": "bitianicon",
"unicode": "e895",
"unicode_decimal": 59541
},
{
"icon_id": "23144151",
"name": "未选中项目标签icon",
"font_class": "weixuanzhongxiangmubiaoqianicon",
"unicode": "e897",
"unicode_decimal": 59543
},
{
"icon_id": "23144152",
"name": "列表icon",
"font_class": "liebiaoicon",
"unicode": "e898",
"unicode_decimal": 59544
},
{
"icon_id": "23144158",
"name": "协作者管理icon",
"font_class": "xiezuozheguanliicon",
"unicode": "e8a1",
"unicode_decimal": 59553
},
{
"icon_id": "23144160",
"name": "选中分支icon",
"font_class": "xuanzhongfenzhiicon",
"unicode": "e8a3",
"unicode_decimal": 59555
},
{
"icon_id": "23144162",
"name": "选中基本设置icon",
"font_class": "xuanzhongjibenshezhiicon",
"unicode": "e8a5",
"unicode_decimal": 59557
},
{
"icon_id": "23144165",
"name": "选中项目标签icon",
"font_class": "xuanzhongxiangmubiaoqianicon",
"unicode": "e8aa",
"unicode_decimal": 59562
},
{
"icon_id": "23144167",
"name": "选中webhook icon",
"font_class": "a-xuanzhongwebhookicon",
"unicode": "e8af",
"unicode_decimal": 59567
},
{
"icon_id": "23046290",
"name": "shanchu_tc_icon",
"font_class": "shanchu_tc_icon",
"unicode": "e88c",
"unicode_decimal": 59532
},
{
"icon_id": "23046293",
"name": "wiki_icon",
"font_class": "wiki_icon",
"unicode": "e88d",
"unicode_decimal": 59533
},
{
"icon_id": "23046244",
"name": "导入模版_icon",
"font_class": "daorumoban_icon",
"unicode": "e86f",
"unicode_decimal": 59503
},
{
"icon_id": "23046252",
"name": "错误",
"font_class": "cuowu",
"unicode": "e872",
"unicode_decimal": 59506
},
{
"icon_id": "23046255",
"name": "更多_icon",
"font_class": "gengduo_icon",
"unicode": "e874",
"unicode_decimal": 59508
},
{
"icon_id": "23046258",
"name": "复层关闭_icon",
"font_class": "fucengguanbi_icon",
"unicode": "e875",
"unicode_decimal": 59509
},
{
"icon_id": "23046268",
"name": "删除icon",
"font_class": "shanchuicon",
"unicode": "e877",
"unicode_decimal": 59511
},
{
"icon_id": "23046273",
"name": "搜索_删除icon",
"font_class": "sousuo_shanchuicon",
"unicode": "e87b",
"unicode_decimal": 59515
},
{
"icon_id": "23046275",
"name": "搜索_icon",
"font_class": "sousuo_icon",
"unicode": "e87d",
"unicode_decimal": 59517
},
{
"icon_id": "23046276",
"name": "文档预览_icon",
"font_class": "wendangyulan_icon",
"unicode": "e87e",
"unicode_decimal": 59518
},
{
"icon_id": "23046278",
"name": "下拉按钮",
"font_class": "xialaanniu",
"unicode": "e880",
"unicode_decimal": 59520
},
{
"icon_id": "22906287",
"name": "二次确认_icon",
"font_class": "erciqueren_icon",
"unicode": "e867",
"unicode_decimal": 59495
},
{
"icon_id": "22906288",
"name": "选中ssh_icon",
"font_class": "xuanzhongssh_icon",
"unicode": "e868",
"unicode_decimal": 59496
},
{
"icon_id": "22906289",
"name": "未选中安全设置_icon",
"font_class": "weixuanzhonganquanshezhi_icon",
"unicode": "e869",
"unicode_decimal": 59497
},
{
"icon_id": "22906290",
"name": "未选中ssh_icon",
"font_class": "weixuanzhongssh_icon",
"unicode": "e86a",
"unicode_decimal": 59498
},
{
"icon_id": "22906291",
"name": "选中安全设置_icon",
"font_class": "xuanzhonganquanshezhi_icon",
"unicode": "e86b",
"unicode_decimal": 59499
},
{
"icon_id": "22906292",
"name": "删除_icon",
"font_class": "shanchu_icon",
"unicode": "e86c",
"unicode_decimal": 59500
},
{
"icon_id": "22906293",
"name": "列表ssh_icon",
"font_class": "liebiaossh_icon",
"unicode": "e86e",
"unicode_decimal": 59502
},
{
"icon_id": "17575494",
"name": "file-submodule",
"font_class": "file-submodule",
"unicode": "e866",
"unicode_decimal": 59494
},
{
"icon_id": "7539612",
"name": "nv",
"font_class": "nv1",
"unicode": "e864",
"unicode_decimal": 59492
},
{
"icon_id": "7539613",
"name": "nan",
"font_class": "nan1",
"unicode": "e865",
"unicode_decimal": 59493
},
{
"icon_id": "21936935",
"name": "邮箱",
"font_class": "youxiang",
"unicode": "e8b2",
"unicode_decimal": 59570
},
{
"icon_id": "21936924",
"name": "单位",
"font_class": "danwei",
"unicode": "e8a7",
"unicode_decimal": 59559
},
{
"icon_id": "21936925",
"name": "待办事项",
"font_class": "daibanshixiang",
"unicode": "e8a8",
"unicode_decimal": 59560
},
{
"icon_id": "21936928",
"name": "概览",
"font_class": "gailan",
"unicode": "e8ab",
"unicode_decimal": 59563
},
{
"icon_id": "21936929",
"name": "男",
"font_class": "nan",
"unicode": "e8ac",
"unicode_decimal": 59564
},
{
"icon_id": "21936930",
"name": "女",
"font_class": "nv",
"unicode": "e8ad",
"unicode_decimal": 59565
},
{
"icon_id": "21936931",
"name": "工作流",
"font_class": "gongzuoliu1",
"unicode": "e8ae",
"unicode_decimal": 59566
},
{
"icon_id": "21936934",
"name": "数据统计",
"font_class": "shujutongji",
"unicode": "e8b1",
"unicode_decimal": 59569
},
{
"icon_id": "21936936",
"name": "项目",
"font_class": "xiangmu",
"unicode": "e8b3",
"unicode_decimal": 59571
},
{
"icon_id": "21936937",
"name": "组织",
"font_class": "zuzhi",
"unicode": "e8b4",
"unicode_decimal": 59572
},
{
"icon_id": "14835599",
"name": "右箭头",
"font_class": "arrowRight",
"unicode": "e863",
"unicode_decimal": 59491
},
{
"icon_id": "21151489",
"name": "箭头镂空-左",
"font_class": "jiantouloukong-zuo",
"unicode": "e861",
"unicode_decimal": 59489
},
{
"icon_id": "21151557",
"name": "箭头镂空-右",
"font_class": "jiantouloukong-you",
"unicode": "e862",
"unicode_decimal": 59490
},
{
"icon_id": "21568989",
"name": "分享",
"font_class": "fenxiang1",
"unicode": "e89c",
"unicode_decimal": 59548
},
{
"icon_id": "21568990",
"name": "回到顶部",
"font_class": "huidaodingbu1",
"unicode": "e89d",
"unicode_decimal": 59549
},
{
"icon_id": "21568993",
"name": "帮助",
"font_class": "bangzhu",
"unicode": "e8a0",
"unicode_decimal": 59552
},
{
"icon_id": "991344",
"name": "提交",
@ -5146,7 +4236,7 @@
{
"icon_id": "1004630",
"name": "点赞2",
"font_class": "dianzaned",
"font_class": "dianzan1",
"unicode": "e639",
"unicode_decimal": 58937
},

1874
public/css/iconfont.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 733 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/favicon.ico Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="zh-CN" class="notranslate translated-ltr" translate="no">
<html lang="en">
<head>
<meta charset="utf-8">
<meta name=”Keywords” Content=”trustie,trustieforge,forge,确实让创建更美好,协同开发平台″>

View File

@ -3319,9 +3319,9 @@
text = text.replace(emailReg, function ($1, $2, $3, $4) {
return $1.replace(/@/g, "_#_&#64;_#_");
});
// " + editormd.urls.atLinkBase + "" + $2 + "
text = text.replace(atLinkReg, function ($1, $2) {
return "<span title=\"&#64;" + $2 + "\" class=\"at-link\"> " + $1 + " </span>";
return "<a href=\"" + editormd.urls.atLinkBase + "" + $2 + "\" title=\"&#64;" + $2 + "\" class=\"at-link\">" + $1 + "</a>";
}).replace(/_#_&#64;_#_/g, "@");
}

View File

@ -60,13 +60,12 @@ body {
.ant-progress-textno {
color: #f5222d;
}
.CodeMirror pre.CodeMirror-line{
font-size: 16px!important;
}
/* md多空格 */
.markdown-body p {
margin:10px 0px!important;
font-size: 16px !important;
line-height: 2 !important;
white-space: pre-wrap;
}
@ -88,10 +87,6 @@ body {
border-left: 1px solid rgb(221, 221, 221);
/* 某些情况下被cm盖住了 */
z-index: 99;
padding:8px 8px 50px;
}
.editormd-preview .markdown-body{
padding:0px !important;
}
/* 图片点击放大的场景,隐藏图片链接 */

View File

@ -3,7 +3,7 @@ import './App.css';
import { ConfigProvider } from 'antd'
import zhCN from 'antd/lib/locale-provider/zh_CN';
import {
// BrowserRouter as Router,
BrowserRouter as Router,
Route,
Switch
} from 'react-router-dom';
@ -17,9 +17,10 @@ import marked from './common/marked';
import moment from 'moment'
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
import SiderBar from './forge/Component/SiderBar'
import { SnackbarHOC } from 'educoder';
import history from './history';
import { SnackbarHOC } from 'educoder'
import { initAxiosInterceptors } from './AppConfig'
import { Provider } from 'react-redux';
import configureStore from './redux/stores/configureStore';
@ -39,16 +40,6 @@ const Projects = Loadable({
loader: () => import('./forge/Index'),
loading: Loading,
})
// forge项目详情
const ProjectDetail = Loadable({
loader: () => import("./forge/Main/DetailAdaptor"),
loading: Loading,
});
//forge安全设置
const Security = Loadable({
loader: () => import('./forge/SecuritySetting/Index'),
loading: Loading,
})
//forge项目-devOps详情
const OpsDetail = Loadable({
loader: () => import('./forge/DevOps/opsDetail'),
@ -83,27 +74,6 @@ const EducoderLogin = Loadable({
loader: () => import('./modules/login/EducoderLogin'),
loading: Loading,
})
const Search = Loadable({
loader: () => import('./modules/search/'),
loading: Loading,
})
const WikiPreview = Loadable({
loader: () => import('./forge/Wiki/Preview'),
loading: Loading,
})
const ProjectIndex = Loadable({
loader: () => import("./forge/Index"),
loading: Loading,
});
// const CreateMerge = Loadable({
// loader: () => import('./forge/Merge/NewMerge'),
// loading: Loading,
// })
// 此处仅维护前端可能的一级路由,不用进行项目或者组织判断的字段。
const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize"];
class App extends Component {
constructor(props) {
@ -114,51 +84,6 @@ class App extends Component {
mydisplay: false,
occupation: 0,
mygetHelmetapi: null,
pathType: null,
pathName: null,
}
}
UNSAFE_componentWillMount() {
initAxiosInterceptors(this.props);
let pathname = window.location.pathname ? window.location.pathname.split('/')[1] : '';
pathname && this.getPathnameType(pathname);
// 添加路由监听,决定组织还是个人
this.unlisten = this.props.history.listen((location) => {
let newPathname = location.pathname.split('/')[1];
if (this.state.pathName !== newPathname) {
// this.setState({ pathType: '' });
newPathname && this.getPathnameType(newPathname);
}
});
}
shouldComponentUpdate(nextProps, nextState) {
// (!keyWord.includes(this.props.location.pathname.split('/')[1])) &&
if (nextProps.location.pathname.split('/')[1] !== this.props.location.pathname.split('/')[1] && nextState.pathType === this.state.pathType) {
return false;
} else {
return true;
}
}
getPathnameType = (pathname) => {
if (!keyWord.includes(pathname)) {
let url = `/owners/${pathname}.json`;
axios.get(url).then((response) => {
if (response && response.status === 200) {
this.setState({
pathType: response.data.type || '404',
pathName: pathname,
})
}
});
}else{
this.setState({
pathType: pathname,
pathName: pathname,
});
}
}
@ -175,22 +100,43 @@ class App extends Component {
Addcoursestypes: false
})
};
ModalCancelsy = () => {
this.setState({
mydisplay: false,
})
window.location.href = "/";
};
ModalshowCancelsy = () => {
this.setState({
mydisplay: true,
})
};
disableVideoContextMenu = () => {
window.$("body").on("mousedown", "video", function (event) {
if (event.which === 3) {
window.$('video').bind('contextmenu', function () { return false; });
} else {
window.$('video').unbind('contextmenu');
}
});
}
componentDidMount() {
document.title = "loading...";
this.disableVideoContextMenu();
history.listen(() => {
this.forceUpdate()
const $ = window.$
$("html").animate({ scrollTop: $('html').scrollTop() - 0 })
});
initAxiosInterceptors(this.props);
this.getAppdata();
window.addEventListener('error', (event) => {
const msg = `${event.type}: ${event.message}`;
});
}
componentWillUnmount() {
this.unlisten && this.unlisten(); // 执行解绑
}
//修改登录方法
Modifyloginvalue = () => {
this.setState({
@ -261,139 +207,69 @@ class App extends Component {
};
render() {
const { mygetHelmetapi, pathType} = this.state;
let personal = mygetHelmetapi && mygetHelmetapi.personal;
return (
<Provider store={store}>
<ConfigProvider locale={zhCN}>
<MuiThemeProvider theme={theme}>
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
<SiderBar />
{/* <Router> */}
<Switch>
{/* wiki预览 */}
<Route path="/:owner/:projectsId/wiki/preview/:projectName/:projectId" render={
(props) => {
return (<WikiPreview {...this.props} {...props} {...this.state} />)
}
} />
{/* 项目PR */}
<Route path="/:owner/:projectsId/compare"
render={
(props) => (<ProjectDetail {...this.props} {...props} {...this.state} />)
}
></Route>
{/*项目*/}
<Route
path={"/:owner/:projectId/devops/:opsId/detail"}
render={
(props) => {
return (<OpsDetail {...this.props} {...props} {...this.state} />)
}
}>
</Route>
<Route
path={"/settings"}
render={
(props) => {
return (<Security {...this.props} {...props} {...this.state} />)
}
}>
</Route>
<Route
path="/register"
render={
(props) => {
return (<EducoderLogin {...this.props} {...props} {...this.state} />)
}
}
/>
{/*403*/}
<Route path="/403" component={Shixunauthority} />
<Route path="/500" component={http500} />
{/*404*/}
<Route path="/nopage" component={Shixunnopage} />
{/* 查询 */}
<Route path="/search" component={Search} />
<Route exact path="/explore"
render={
(props) => (
<ProjectIndex {...this.props} {...props} />
)
}
/>
{/* 组织 */}
<Route path={"/organize"}
render={
(props) => {
return (<OrganizeIndex {...props} {...this.props} {...this.state} />)
}
}>
</Route>
{/*新建项目等*/}
<Route
path={"/projects"}
render={
(props) => {
return (<Projects {...this.props} {...props} {...this.state} />)
}
}>
</Route>
{/* 判断为用户/组织,并进入对应页面 */}
{
pathType === 'User' ?
<Route exact path="/:username"
render={
(props) => {
return (<InfosIndex {...this.props} {...this.state} />)
}
<Router>
<Switch>
{/*项目*/}
<Route
path={"/projects/:owner/:projectId/devops/:opsId/detail"}
render={
(props) => {
return (<OpsDetail {...this.props} {...props} {...this.state} />)
}
}>
</Route>
{/*项目*/}
<Route
path={"/projects"}
render={
(props) => {
return (<Projects {...this.props} {...props} {...this.state} />)
}
}>
</Route>
<Route
path="/register"
render={
(props) => {
return (<EducoderLogin {...this.props} {...props} {...this.state} />)
}
/> : pathType === 'Organization' ? <Route path={"/:OIdentifier"}
render={
(props) => {
return (<OrganizeIndex {...props} {...this.props} {...this.state} />)
}
}>
</Route> : pathType === '404' ? <Route component={Shixunnopage} />:
<Route exact path="/"
render={
(props) => (
personal && personal.length > 0 ?
<InfosIndex {...this.props} {...props} />
:
<ProjectIndex {...this.props} {...props} />
)
}
/>
// <Route path="/" component={Loading} />
// <Route path="/" component={Shixunnopage} />
}
{/* 个人主页 */}
<Route path="/:username"
render={
(props) => {
return (<InfosIndex {...this.props} {...this.state} />)
}
/>
{/*403*/}
<Route path="/403" component={Shixunauthority} />
<Route path="/500" component={http500} />
<Route path={"/organize"}
render={
(props) => {
return (<OrganizeIndex {...props} {...this.props} {...this.state} />)
}
}>
</Route>
{/*404*/}
<Route path="/nopage" component={Shixunnopage} />
{/* 个人主页 */}
<Route path="/users/:username"
render={
(props) => {
return (<InfosIndex {...this.props} {...this.state} />)
}
}></Route>
<Route component={Shixunnopage} />
</Switch>
{/* </Router> */}
<Route exact path="/"
render={
(props) => (
<Projects {...this.props} {...props} {...this.state}></Projects>
)
}
/>
<Route component={Shixunnopage} />
</Switch>
</Router>
</MuiThemeProvider>
</ConfigProvider>
</Provider>

View File

@ -2,7 +2,7 @@ import axios from 'axios';
import { requestProxy } from "./indexEduplus2RequestProxy";
import { broadcastChannelOnmessage, isDev, queryString } from 'educoder';
import { notification } from 'antd';
import cookie from 'react-cookies';
import './index.css';
let message501 = false;
@ -11,8 +11,10 @@ broadcastChannelOnmessage('refreshPage', () => {
})
function locationurl(list) {
if (window.location.port !== "3007") {
window.location.href = list
if (window.location.port === "3007") {
} else {
window.location.href = list
}
}
// TODO 开发期多个身份切换
@ -24,22 +26,53 @@ if (isDev) {
parsed = queryString.parse(_search);
}
debugType = window.location.search.indexOf('debug=t') !== -1 ? 'teacher' :
window.location.search.indexOf('debug=s') !== -1 ? 'student' :
window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin'
window.location.search.indexOf('debug=s') !== -1 ? 'student' :
window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin'
}
function clearAllCookie() {
cookie.remove('_educoder_session', { path: '/' });
cookie.remove('autologin_trustie', { path: '/' });
setpostcookie()
}
clearAllCookie();
function setpostcookie() {
const str = window.location.pathname;
if (str.indexOf("/wxcode") !== -1) {
cookie.remove('_educoder_session', { path: '/' });
cookie.remove('autologin_trustie', { path: '/' });
const _params = window.location.search;
if (_params) {
let _search = _params.split('?')[1];
let _educoder_sessions = _search.split('&')[0].split('=');
cookie.save('_educoder_session', _educoder_sessions[1], { domain: '.educoder.net', path: '/' });
let autologin_trusties = _search.split('&')[1].split('=');
cookie.save('autologin_trustie', autologin_trusties[1], { domain: '.educoder.net', path: '/' });
}
}
}
setpostcookie();
window._debugType = debugType;
export function initAxiosInterceptors(props) {
// 判断网络是否连接
initOnlineOfflineListener();
var proxy = "http://localhost:3000";
proxy = "https://testforgeplus.educoder.net";
var proxy = "https://testforgeplus.trustie.net";
const requestMap = {};
window.setfalseInRequestMap = function (keyName) {
requestMap[keyName] = false;
}
//响应前的设置
axios.interceptors.request.use(
config => {
if(config.url.indexOf("http") !== -1) {
setpostcookie()
clearAllCookie()
if (config.url.indexOf(proxy) !== -1) {
return config
}
requestProxy(config);
requestProxy(config)
let url = `/api${config.url}`;
if (`${config[0]}` !== `true`) {
@ -53,6 +86,12 @@ export function initAxiosInterceptors(props) {
} else {
config.url = url;
}
setpostcookie();
}
if (config.url.indexOf('update_file') === -1) {
requestMap[config.url] = true;
window.setTimeout("setfalseInRequestMap('" + config.url + "')", 900)
}
return config;
},
@ -85,10 +124,7 @@ export function initAxiosInterceptors(props) {
}
if (response.data.status === 404) {
let responseURL = response.request ? response.request.responseURL:'';
if (responseURL.indexOf('/api/users/') === -1 && responseURL.indexOf('/api/organizations/') === -1 ) {
locationurl('/nopage');
}
locationurl('/nopage');
}
if (response.data.status === 500) {
@ -110,6 +146,8 @@ export function initAxiosInterceptors(props) {
message501 = false
}, 2000);
}
requestMap[response.config.url] = false;
setpostcookie();
return response;
}, function (error) {
return Promise.reject(error);

View File

@ -9,7 +9,20 @@ class Loading extends Component {
}
render() {
return ""
return (
<div className="App" style={{ minHeight: '800px', width: "100%" }}>
<style>
{
`
.margintop{
margin-top:20%;
}
`
}
</style>
<Spin size="large" className={"margintop"} />
</div>
);
}
}

View File

@ -195,7 +195,7 @@ class College extends Component {
align: 'center',
className: "edu-txt-center font-14 maxnamewidth105",
render: (text, record) => (
<a href={`/${record.login}`} title={record.name} target="_blank" className="task-hide maxnamewidth105" style={{
<a href={`/users/${record.login}`} title={record.name} target="_blank" className="task-hide maxnamewidth105" style={{
color:'#007bff',
}}> {

View File

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

View File

@ -1,5 +1,4 @@
import moment from "moment";
import { number } from "prop-types";
// 处理整点 半点
// 取传入时间往后的第一个半点
@ -98,41 +97,3 @@ export function formatDuring(mss){
}
return days + "天" + hours + "小时" + minutes + "分";
}
/*
返回多久以前
backDate以前的某个日期
*/
export function timeAgo(backDate) {
try {
moment(backDate);
} catch (e) {
return '刚刚';
}
if(typeof backDate ==='number'){
backDate=backDate*1000
}else{
backDate= moment(backDate);
}
let time = new Date() - backDate;
var days = Math.floor(time / (1000 * 60 * 60 * 24));
var hours = Math.floor((time % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
var minutes = Math.floor((time % (1000 * 60 * 60)) / (1000 * 60));
var seconds = Math.floor((time % (1000 * 60 * 60)) / 1000);
if (time <= 0) {
return "刚刚";
}
if (days) {
return days + "天前";
}
if (hours) {
return hours + "小时前";
}
if (minutes) {
return minutes + "分前";
}
if (seconds) {
return seconds + "秒前";
}
return "刚刚";
}

View File

@ -69,7 +69,7 @@ export function appendFileSizeToUploadFile(item) {
}
export function appendFileSizeToUploadFileAll(fileList) {
return fileList.map(item => {
if (item.name.indexOf(uploadNameSizeSeperator) === -1) {
if (item.name.indexOf(uploadNameSizeSeperator) == -1) {
return Object.assign({}, item, { name: `${item.name}${uploadNameSizeSeperator}${bytesToSize(item.size)}` })
}
return item

View File

@ -18,23 +18,6 @@ export function getImageUrl(path) {
return `${path}`;
}
export function numFormat(num, digits){
let d = digits || 1;
var si = [
{ value: 1, symbol: "" },
{ value: 1E3, symbol: "k" },
{ value: 1E4, symbol: "W" }
];
var rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
var i;
for (i = si.length - 1; i > 0; i--) {
if (num >= si[i].value) {
break;
}
}
return (num / si[i].value).toFixed(d).replace(rx, "$1") + si[i].symbol;
}
export function getImage(path) {
// https://www.educoder.net
// https://testbdweb.trustie.net
@ -179,28 +162,28 @@ export function getmyUrl(geturl) {
}
export function getUploadActionUrl(path, goTest) {
return `${getUrl()}/api/attachments.json${isDev ?`${isDev ?`?debug=${window._debugType || 'admin'}` : ""}` : ""}`;
return `${getUrl()}/api/attachments.json`;
}
export function getUploadLogoActionUrl() {
return `${getUrl()}/api/resumes/logo.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`;
return `${getUrl()}/api/resumes/logo.json?debug=${window._debugType || 'admin'}`;
}
export function getUploadActionUrltwo(id) {
return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`
return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json?debug=${window._debugType || 'admin'}`
}
export function getUploadActionUrlthree() {
return `${getUrlmys()}/api/jupyters/import_with_tpm.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`
return `${getUrlmys()}/api/jupyters/import_with_tpm.json?debug=${window._debugType || 'admin'}`
}
export function getupload_git_file(id) {
return `${getUrlmys()}/api/shixuns/${id}/upload_git_file.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`
return `${getUrlmys()}/api/shixuns/${id}/upload_git_file.json?debug=${window._debugType || 'admin'}`
}
export function getUploadActionUrlOfAuth(id) {
return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`
return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json?debug=${window._debugType || 'admin'}`
}
export function getRandomNumber(type) {

View File

@ -3,7 +3,7 @@
// export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil';
export {
getUploadLogoActionUrl as getUploadLogoActionUrl,numFormat as numFormat,
getUploadLogoActionUrl as getUploadLogoActionUrl,
getImageUrl as getImageUrl,getImage as getImage, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode, getupload_git_file as getupload_git_file, getcdnImageUrl as getcdnImageUrl
@ -27,7 +27,7 @@ export {
markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension,
downloadFile, sortDirections, validateLength, mdJSONParse, exportMdtoHtml
} from './TextUtil'
export { handleDateString, getNextHalfHourOfMoment, formatDuring, formatSeconds ,timeAgo} from './DateUtil'
export { handleDateString, getNextHalfHourOfMoment, formatDuring, formatSeconds } from './DateUtil'
export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil'

View File

@ -46,18 +46,18 @@ export default ({
let id = decodeURIComponent(u.split("#")[1]);
let ele = document.getElementById(id);
if(ele){
window.scrollTo(0, ele.offsetTop + 120);
window.scrollTo(0, ele.offsetTop + 220);
}
}
}
},[url,html])
},[url])
const el = useRef();
function onAncherHandler(e) {
let target = e.target;
let target = e.target
if (target.tagName.toUpperCase() === 'A') {
let ancher = target.getAttribute('href');
if (ancher && ancher.startsWith('#')) {
let ancher = target.getAttribute('href')
if (ancher.startsWith('#')) {
e.preventDefault()
let viewEl = document.getElementById(ancher.replace('#', ''))
if (viewEl) {

View File

@ -435,11 +435,11 @@ class TPIContextProvider extends Component {
image_url: "avatars/User/1"
login: "innov"
name: "Coder"
user_url: "/innov"
user_url: "/users/innov"
*/
let user = resData.user;
user.username = resData.user.name;
user.user_url = `/${resData.user.login}`;
user.user_url = `/users/${resData.user.login}`;
// user.image_url = resData.image_url;
user.is_teacher = resData.is_teacher;
resData.user = user;

View File

@ -1,7 +1,7 @@
import React , { Component } from 'react';
import { Dropdown , Menu , Icon , Pagination , Spin } from 'antd';
import '../css/index.scss';
import '../Branch/branch.scss';
import '../Branch/branch.css';
import './activity.css';
import NoneData from '../Nodata';
@ -10,10 +10,6 @@ import ActivityItem from './ActivityItem';
import axios from 'axios';
const LIMIT = 15;
const ARRAY = [
{
id:"",
name:'全部'
},
{
id:1,
name:'1天'
@ -36,15 +32,10 @@ class Activity extends Component{
constructor(props){
super(props);
this.state={
time:undefined,
time:'30',
type:undefined,
state:undefined,
page:1,
pr_count:undefined,
new_pr_count:undefined,
close_issues_count:undefined,
open_issues_count:undefined,
pr_all_count:undefined,issues_count:undefined,
data:undefined,
project_trends:undefined,
@ -72,15 +63,8 @@ class Activity extends Component{
this.setState({
data:result.data,
project_trends:result.data.project_trends,
isSpin:false,
pr_count:result.data.pr_count,
new_pr_count:result.data.new_pr_count,
close_issues_count:result.data.close_issues_count,
open_issues_count:result.data.open_issues_count,
pr_all_count:result.data.pr_all_count,
issues_count:result.data.issues_count,
isSpin:false
})
window.scrollTo(0,0);
}
}).catch(error=>{
console.log(error);
@ -90,19 +74,19 @@ class Activity extends Component{
// 切换周期
changeTime=(e)=>{
this.setState({
time:e.key ==="item_0"?undefined:e.key,
time:e.key,
isSpin:true
})
const { type,status,page } = this.state;
this.getInfo(e.key ==="item_0"?undefined:e.key,type,status,page);
this.getInfo(e.key,type,status,page);
}
//筛选
changeTrends=(type,status)=>{
this.setState({
type,status,page:1
type,status
})
const {time}=this.state;
this.getInfo(time,type,status,1);
const {time,page}=this.state;
this.getInfo(time,type,status,page);
}
// 分页
ChangePage=(page)=>{
@ -124,14 +108,12 @@ class Activity extends Component{
</Menu>
)
render(){
const { time , data , page , project_trends , isSpin , pr_count , new_pr_count , close_issues_count , open_issues_count , pr_all_count ,issues_count } = this.state;
let name = time ? ARRAY.filter(item=>item.id === parseInt(time)) :[{name:"全部"}];
const { time , data , page , project_trends , isSpin } = this.state;
const first_per = pr_all_count > 0 ? `${parseFloat(pr_count/pr_all_count).toFixed(2)*100}%` :"50%";
const second_per =pr_all_count > 0 ? `${parseFloat(new_pr_count/pr_all_count).toFixed(2)*100}%` :"50%";
const third_per =issues_count > 0 ?`${parseFloat(close_issues_count/issues_count).toFixed(2)*100}%` :"50%";
const fourth_per =issues_count > 0 ?`${parseFloat(open_issues_count/issues_count).toFixed(2)*100}%` :"50%";
let name = time && ARRAY.filter(item=>item.id === parseInt(time)) ;
const second_per = (parseInt(data && data.close_issues_count)/parseInt(data && data.issues_count)*100)+'%';
const third_per = (parseInt(data && data.close_issues_count)/parseInt(data && data.issues_count)*100)+'%';
const fourth_per = (parseInt(data && data.open_issues_count)/parseInt(data && data.issues_count)*100)+'%';
return(
<div className="main">
@ -140,7 +122,7 @@ class Activity extends Component{
<div className="orderInfo">
<div>
<div className="percentLine prPercent">
<p className="percent_purple" style={{width:first_per}}></p>
<p className="percent_purple" style={{width:'100%'}}></p>
<p className="percent_green resetStyle" style={{width:`${second_per}`}}></p>
</div>
<span>{data && data.pr_all_count}合并请求</span>
@ -150,25 +132,25 @@ class Activity extends Component{
<p className="percent_red" style={{width:`${third_per}`}}></p>
<p className="percent_green" style={{width:`${fourth_per}`}}></p>
</div>
<span>{data && data.issues_count}易修</span>
<span>{data && data.issues_count}任务</span>
</div>
</div>
<ul className="percentBox">
<li>
<span className="purple">{data && data.pr_count}</span>
<span className="change" onClick={()=>this.changeTrends("PullRequest","delay")}>已处理的合并请求</span>
<span className="change" onClick={()=>this.changeTrends("PullRequest","close")}>已处理的合并请求</span>
</li>
<li>
<span className="green">{data && data.new_pr_count}</span>
<span className="change" onClick={()=>this.changeTrends("PullRequest","not_delay")}>未处理的合并请求</span>
<span className="change" onClick={()=>this.changeTrends("PullRequest","create")}>未处理的合并请求</span>
</li>
<li>
<span className="red">{data && data.close_issues_count}</span>
<span className="change" onClick={()=>this.changeTrends("Issue","delay")}>已关闭的易修</span>
<span className="change" onClick={()=>this.changeTrends("Issue","close")}>已关闭的任务</span>
</li>
<li>
<span className="green">{data && data.open_issues_count}</span>
<span className="change" onClick={()=>this.changeTrends("Issue","not_delay")}>未处理的易修</span>
<span className="change" onClick={()=>this.changeTrends("Issue","create")}>未处理的任务</span>
</li>
</ul>
</div>

View File

@ -14,25 +14,25 @@ class ActivityItem extends Component {
{/* 如果是版本发布 */}
{item.trend_type === "VersionRelease" ?
<p className="itemLine">
<Link to={`/${owner}/${projectsId}/releases`} className="color-blue font-16">{item.name}</Link>
<Link to={`/projects/${owner}/${projectsId}/version`} className="color-blue font-16">{item.name}</Link>
<span className="activity_type">{item.trend_type}</span>
</p >
:
// 如果是任务
item.trend_type === "Issue" ?
<p className="itemLine">
<Link to={`/${owner}/${projectsId}/issues/${item.trend_id}`} className="color-blue font-16">{item.name}</Link>
<Link to={`/projects/${owner}/${projectsId}/issues/${item.trend_id}/detail`} className="color-blue font-16">{item.name}</Link>
<span className="activity_type">{item.trend_type}</span>
</p >
:
// 如果是合并请求
<p className="itemLine">
<Link to={`/${owner}/${projectsId}/pulls/${item.trend_id}`} className="color-blue font-16">{item.name}</Link>
<Link to={`/projects/${owner}/${projectsId}/pulls/${item.trend_id}/Messagecount`} className="color-blue font-16">{item.name}</Link>
<span className="activity_type">{item.trend_type}</span>
</p >
}
<p className="itemLine mt10">
<Link to={`/${item && item.user_login}`} className="show-user-link">
<Link to={`/users/${item && item.user_login}`} className="show-user-link">
<img alt="" src={getImageUrl(`/${item.user_avatar}`)} className="createImage" />
<span className="mr20">{item.user_name}</span>
</Link>

View File

@ -1,27 +1,39 @@
import React, { useState } from 'react';
import { Menu } from 'antd';
import "./branch.scss";
import CopyTool from '../Component/CopyTool';
import React, { Component } from 'react';
import { Dropdown, Icon, Tooltip } from 'antd';
import "./branch.css";
function CloneAddress({http_url , ssh_url , zip_url , tar_url}) {
const [ key , setKey ] = useState("HTTP");
return (
<div className="downMenu">
<div style={{borderBottom:"1px solid #eee"}}>
<Menu className="urlMenu" selectedKeys={[key]} mode={"horizontal"}>
<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>
<div className="gitAddressClone">
<input type="text" id="copy_rep_content" value={key==="HTTP" ? http_url:ssh_url} />
<CopyTool inputId="copy_rep_content" className="copytool"/>
</div>
class CloneAddress extends Component {
// 点击按钮复制功能
jsCopy = () => {
var e = document.getElementById("copy_rep_content");
e.select();
document.execCommand("Copy");
}
render() {
const { http_url, downloadUrl } = this.props;
return (
<div className="gitAddressClone">
{/* <p className="addressTips"><span>版本库地址已变更,请基于新地址提交代码</span></p> */}
{
http_url && <span>HTTP</span>
}
<input type="text" id="copy_rep_content" value={http_url} />
<Tooltip title="复制链接">
<span className="color-blue" onClick={() => this.jsCopy()}><i className="iconfont icon-fuzhi"></i></span>
</Tooltip>
{
downloadUrl &&
<span>
<Dropdown overlay={downloadUrl} trigger={['click']} placement="bottomRight">
<a className="ant-dropdown-link">
<Icon type="cloud-download" className="font-18 fl color-blue" />
</a>
</Dropdown>
</span>
}
</div>
<Menu className="edu-txt-center">
<Menu.Item><a href={zip_url}>下载 ZIP</a></Menu.Item>
<Menu.Item><a href={tar_url}>下载 TAR.GZ</a></Menu.Item>
</Menu>
</div>
)
)
}
}
export default CloneAddress;

View File

@ -1,65 +1,116 @@
import React , { useState , useEffect , useRef } from 'react';
import { Dropdown} from 'antd';
import './branch.scss';
import SelectOverlay from './SelectOverlay';
import { findDOMNode } from 'react-dom';
import React , { useState , useEffect } from 'react';
import { Popover , Input , Spin } from 'antd';
import './branch.css';
import { getBranch , getTag } from '../GetData/getData';
export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true })=>{
const [ showValue , setShowValue ] = useState(branch);
const [ visible , setVisible ] = useState(false);
const [ inputValue , setInputValue] = useState(undefined);
const [ nav , setNav ] = useState(0);
const [ isSpin , setIsSpin ] = useState(true);
const [ flag , setFlag ] = useState(false);
const refFa = useRef(null);
const refBox = useRef(null);
useEffect(() => {
document.addEventListener('click', clickMe , false);
}, [])
const clickMe = ({ target }) => {
//
const faComponent = findDOMNode(refFa.current);
const boxComponent = findDOMNode(refBox.current);
if (faComponent && boxComponent) {
const isChild = faComponent.contains(target);
const isBox = boxComponent.contains(target);
if(!isChild && !isBox){
setVisible(false);
}
}
}
const [ data , setData ] = useState(undefined);
const [ datas , setDatas ] = useState(undefined);
useEffect(()=>{
setShowValue(branch);
},[branch])
function ChangeB(params) {
setVisible(false);
changeBranch(params);
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 = (
<div ref={refFa}>
<SelectOverlay
visible={visible}
changeBranch={ChangeB}
tagflag={tagflag}
projectsId={projectsId}
owner={owner}
branchList={branchList}
/>
<div>
<div className="padding10 bor-bottom-greyE">
<Input
placeholder="请输入分支或标签名称搜索"
autocomplete="off" className="OptionsInput" value={inputValue}
onChange={changeInputValue} style={{width:"220px"}}
/>
<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(
<Dropdown placement='bottomLeft' visible={visible} overlay={menu} overlayClassName="branch-tagBox-list" trigger={['click']} >
<div className="branch-tagBox" ref={refBox} onClick={()=>setVisible(visible ? false : true)}>
<Popover placement="bottom" visible={flag} content={menu} onClick={()=>setFlag(!flag)} overlayClassName="branch-tagBox-list">
<div className="branch-tagBox">
{/* {nav === 0 ?"分支":"标签"} */}
<span className="color-grey-9 mr3 ml8"><i className="iconfont icon-fenzhi2 font-18"></i></span>
<span className="ant-dropdown-link task-hide" style={{fontWeight:"500",minWidth:"45px",maxWidth:"270px"}}>
<a className="ant-dropdown-link">
{showValue}
</span>
<i className="showtag iconfont icon-sanjiaoxing-down font-15 color-grey-9 mr5 ml5 mt1" />
</a>
<i className="showtag iconfont icon-xiajiantou font-14 color-grey-9 mr8" />
</div>
</Dropdown>
</Popover>
)
})

View File

@ -1,90 +0,0 @@
import React , { useState , useEffect } from 'react';
import { Input , Spin , Menu } from 'antd';
import { getBranch , getTag } from '../GetData/getData';
function SelectOverlay({ changeBranch , tagflag , projectsId , owner , visible }) {
const [ inputValue , setInputValue] = useState(undefined);
const [ nav , setNav ] = useState(0);
const [ isSpin , setIsSpin ] = useState(true);
const [ data , setData ] = useState(undefined);
const [ datas , setDatas ] = useState(undefined);
const [ keys ,setKeys] = useState("branch");
useEffect(()=>{
if(visible){
setKeys("branch");
getBranchs(projectsId,owner);
setIsSpin(true);
}
},[visible])
async function getBranchs(id,owner){
let result = await getBranch(id,owner);
setData(result);
setDatas(result);
setIsSpin(false);
}
async function getTags(id,owner){
let result = await getTag(id,owner);
setData(result);
setDatas(result);
setIsSpin(false);
}
function chooseitem(value){
changeBranch(value);
}
function changeInputValue(e){
setInputValue(e.target.value);
let filter = e.target.value ? data && data.length>0 && data.filter(item=>item.name.indexOf(e.target.value)>-1) : data;
setDatas(filter);
}
function changeNav(e){
setKeys(e.key);
setIsSpin(true);
if(e.key === "branch"){
getBranchs(projectsId,owner);
setNav(0);
}else{
getTags(projectsId,owner);
setNav(1);
}
}
return(
<div className="overlayBranch">
<div className="padding15" style={{paddingBottom:"0px"}}>
<Input
prefix={<i className="iconfont icon-sousuo_icon1 font-14"></i>}
placeholder={`请输入分支${tagflag ? "或标签" :""}名称搜索`}
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>
)
})
}
{
datas && datas.length === 0 &&
<p className="listTips">暂无{inputValue}{nav === 0 ?"分支":"标签"}~</p>
}
</ul>
</Spin>
</div>
)
}
export default SelectOverlay;

View File

@ -0,0 +1,84 @@
.branchDropdown{
border:1px solid #eee;
border-radius: 4px;
display: flex;
justify-content: center;
height: 40px;
line-height: 40px;
min-width: 220px;
}
.branchDropdown .ant-dropdown-trigger{
width: 100%;
padding:0px 15px;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
}
.branchOptions{
width: 220px;
box-shadow: 0px 0px 3px 1px rgba(134, 134, 134, 0.4);
border-radius: 3px;
background: #fff;
max-height: 300px;
}
.OptionsUl{
max-height: 220px;
overflow-y: auto;
}
.OptionsUl li{
height: 35px;
line-height: 35px;
cursor: pointer;
padding:0px 10px;
}
.OptionsUl li:hover{
background-color: #F0F0F0;
}
.OptionsUl li a{
display: block;
}
.OptionsInput{
height: 32px;
padding-left: 4px;
line-height: 32px;
width: 100%;
}
.branch-tagBox{
border:1px solid #eee;
border-radius: 3px;
height: 40px;
display: flex;
align-items: center;
cursor: pointer;
min-width: 140px;
}
.branch-tagBox-list .ant-popover-arrow{
display: none;
}
.branch-tagBox-list.ant-popover.ant-popover-placement-bottom{
padding-top:0px;
}
.branch-tagBox .ant-dropdown-link{
display: block;
flex:1;
}
.branch-tagBox-list .ant-popover-inner-content{
padding:0px;
}
.navUl{
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 5px;
}
.navUl li{
cursor: pointer;
}
.navUl li.active{
color:#5091FF;
}
.listTips{
padding:20px 0px;
text-align: center;
}

View File

@ -1,129 +0,0 @@
.branchDropdown{
border:1px solid #eee;
border-radius: 4px;
display: flex;
justify-content: center;
height: 40px;
line-height: 40px;
min-width: 220px;
}
.branchDropdown .ant-dropdown-trigger{
width: 100%;
padding:0px 15px;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
}
.branchOptions{
width: 220px;
box-shadow: 0px 0px 3px 1px rgba(134, 134, 134, 0.4);
border-radius: 3px;
background: #fff;
max-height: 300px;
}
.OptionsUl{
min-height: 50px;
max-height: 220px;
overflow-y: auto;
}
.OptionsUl li{
height: 30px;
line-height: 30px;
cursor: pointer;
padding:0px 20px;
margin:5px 0px;
}
.OptionsUl li:hover{
background-color: #F0F0F0;
}
.OptionsUl li a{
display: block;
}
.OptionsInput{
height: 32px;
padding-left: 4px;
line-height: 32px;
width: 100%;
}
.branch-tagBox{
border:1px solid #D0D0D0;
border-radius: 3px;
height: 32px;
display: flex;
align-items: center;
cursor: pointer;
min-width: 104px;
}
.branch-tagBox:hover{
background-color: #F3F4F6;
}
.branch-tagBox-list{
background: #FFFFFF;
box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5);
border-radius: 4px;
.ant-popover-arrow{
display: none;
}
&.ant-popover.ant-popover-placement-bottom{
padding-top:0px;
}
.branch-tagBox .ant-dropdown-link{
display: block;
flex:1;
max-width: 105px;
}
.ant-popover-inner-content{
padding:0px;
}
}
.overlayBranch{
width: 325px;
.navUl{
margin-top: 8px;
height: 30px;
line-height: 30px;
li{
height: 30px;
line-height: 30px;
padding:0px 5px;
margin-left: 20px!important;
&.ant-menu-item-selected{
border-color:#466aff!important;
color:#466aff!important;
}
&.ant-menu-item-active{
border-color:transparent ;
}
}
}
}
.listTips{
padding:20px 0px;
text-align: center;
}
.urlMenu{
line-height: 30px;
margin-bottom: 10px;
padding:15px 20px 0px 20px;
border-bottom: none;
li.ant-menu-item{
height: 30px;
line-height: 30px;
padding:0px 5px;
margin-right: 20px!important;
&.ant-menu-item-selected,&.ant-menu-item-active{
color: #333;
}
&.ant-menu-item-selected{
border-color:#466aff!important;
}
&.ant-menu-item-active{
border-color:transparent ;
}
}
}
.copytool{
margin:0px 10px;
}

View File

@ -55,7 +55,6 @@ function AddGroup({organizeId,getGroupID}){
function addCollaborator(){
getGroupID && getGroupID(id);
setID(undefined);
}
return(

View File

@ -4,7 +4,7 @@ import axios from 'axios';
import { getImageUrl } from 'educoder';
const { Option } = AutoComplete;
function AddMember({getID,login,showNotification}){
function AddMember({getID,login}){
const [ id , setID ] = useState(undefined);
const [ source , setSource ] = useState(undefined);
const [ searchKey , setSearchKey ] = useState(undefined);
@ -45,7 +45,7 @@ function AddMember({getID,login,showNotification}){
src={getImageUrl(`/${item && item.image_url}`)}
alt=""
/>
<span className="ml10" style={{ verticalAlign: "middle" }}>
<span className="ml10" style={{ "vertical-align": "middle" }}>
{item.username}
<span className="color-grey ml10">({item.login})</span>
</span>
@ -66,12 +66,7 @@ function AddMember({getID,login,showNotification}){
};
function addCollaborator(){
if(source && source.length>0){
getID && getID(id);
setSearchKey(undefined);
}else{
showNotification("请选择存在的用户!");
}
getID && getID(id);
}
return(

View File

@ -3,7 +3,7 @@ import { getImageUrl } from 'educoder';
import { Link } from 'react-router-dom';
import './Component.scss';
function Cards({img , title, desc , rightBtn , src , bottomInfos}){
function Cards({img , title, desc , rightBtn , src}){
return(
<div className="cards">
{img &&<div className="img"><img src={getImageUrl(`/${img}`)} alt=""/></div>}
@ -15,7 +15,6 @@ function Cards({img , title, desc , rightBtn , src , bottomInfos}){
<div className="desc">
{desc}
</div>
{bottomInfos}
</div>
</div>
)

View File

@ -112,16 +112,6 @@ li.ant-menu-item{
right:240px;
z-index: 10000;
}
.laterest{
background-color: #EF3131;
color: #fff;
font-size: 12px;
margin-left: 10px;
padding:0px 5px;
border-radius: 2px;
height: 18px;
line-height: 18px;
}
@media screen and (max-width: 1800px){
.handleBox{
@ -162,280 +152,41 @@ li.ant-menu-item{
margin:0px 20px!important;
}
}
.hoverA{
display:flex;
align-items: center;
max-width: 78px;
&:hover a{
color:#2A61FF !important ;
}
}
.menuPanels{
width: 295px;
.leftline{
position: relative;
color: #666;
height: 16px;
margin-left: 14px;
font-size: 12px;
&::before{
position: absolute;
left: -7px;
top:3px;
height: 12px;
width: 1px;
background-color: #999;
content: "";
}
}
.ant-btn{
height: 36px;
line-height: 34px;
width: 83px;
text-align: center;
padding:0px ;
font-weight: 500;
font-size: 14px;
&.currentBtn{
cursor: default;
color: #333;
&:hover{
color: #333;
border-color: #d0d0d0;
}
}
}
.ant-btn-default{
color: #333;
border-color: #d0d0d0;
&:hover{
background: #F3F4F6;
}
}
.ant-btn{
width: 102px;
height: 32px;
line-height: 30px;
}
.ant-btn-primary{
color: #fff;
background-color: #466AFF;
border:none;
&:hover{
background-color: rgba(70,106,255,0.85);
}
}
.focusPanelHeadInfo{
padding:14px 16px;
border-bottom: 1px solid #eee;
}
width: 240px;
height: 180px;
.ant-popover-content,.ant-popover-inner{
height: 100%;
width: 100%;
}
.ant-popover-inner-content{
padding:0px;
}
}
.halfs{
margin-top: 24px;
padding:24px 0px 0px 0px;
border-top: 1px solid #e8e8e8;
}
.aboutSubTitle{
display: flex;
align-items: center;
}
.menuMaininfos{
padding:10px 16px 14px;
border-bottom: 1px solid #eee;
.attrPerson{
padding-bottom: 24px;
}
}
.menuinfos{
padding:10px 20px 16px;
padding:15px 0px;
&>a{
display: flex;
flex-direction: column;
align-items: center;
border-right: 1px solid #eee;
flex: 1;
& >span:first-child{
font-size: 16px;
font-weight: 500;
font-size: 18px;
font-weight: 400;
color: #333;
line-height: 22px;
}
& >span:last-child{
color: #666;
font-weight: 400;
line-height: 20px;
margin-top: 6px;
}
&:last-child{
border-right: none;
}
}
}
/*-------------------个人主页:右侧提示区域--------------------------*/
.-task-sidebar {
position: fixed;
width: 40px;
right: 0;
bottom: 80px;
z-index: 10;
}
@media screen and (max-width: 1920px){
.-task-sidebar{
right:220px;
}
}
@media screen and (max-width: 1750px){
.-task-sidebar{
right:160px;
}
}
@media screen and (max-width: 1650px){
.-task-sidebar{
right:115px;
}
}
@media screen and (max-width: 1550px){
.-task-sidebar{
right:90px;
}
}
@media screen and (max-width: 1450px){
.-task-sidebar{
right:45px;
}
}
@media screen and (max-width: 1200px){
.-task-sidebar{
right:0px;
display: none;
}
}
.-task-sidebar>div {
height: 40px;
line-height: 40px;
box-sizing: border-box;
width: 40px;
color: #999;
font-size: 20px;
text-align: center;
margin-bottom: 20px;
border-radius: 50%;
background: #FFFFFF;
box-shadow: 0px 0px 10px 1px #F1F1F1;
}
.-task-sidebar>div i {
color: #999;
}
.-task-sidebar>div:hover i {
color: #fff !important;
}
.-task-sidebar>div:hover{
background: #1890FF;
box-shadow: 0px 0px 10px 2px #B6D0FC;
}
.helpBox{
width: 260px;
z-index: 103;
&.shareContent{
width: 200px;
}
.ant-popover-inner-content{
padding:0px;
}
p.titlecontent{
font-size: 18px;
color: #333;
line-height: 20px;
padding:15px 20px;
}
.faqUl{
padding:0px 20px 10px;
max-height: 230px;
overflow-y: auto;
li{
background: #F5F5F5;
border-radius: 20px;
padding:0px 20px;
color: #333;
height: 34px;
line-height: 34px;
margin-bottom: 10px;
a{
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
&:hover{
background-color: #D1E9FF;
a{
color: #333!important;
}
}
}
}
.shareUl{
padding:10px 0px;
display: flex;
align-items: center;
.titlecontent{
margin-right: 20px;
}
li > i{
font-size: 32px!important;
}
}
}
.-task-desc {
background: #494949;
width: 90px;
line-height: 36px;
text-align: center;
position: absolute;
color: #fff;
font-size: 13px;
z-index: 999999;
opacity: 0;
}
.-task-desc div {
position: absolute;
top: 10px;
right: -7px;
height: 13px;
}
.-task-desc div img {
float: left
}
.-task-sidebar .scan_ewm {
position: absolute !important;
right: 45px !important;
bottom: 0px !important;
background-color: #494949 !important;
-webkit-box-sizing: border-box !important;
box-sizing: border-box !important;
font-size: 14px !important;
line-height: 16px !important;
display: none;
height: 213px !important;
}
.trangle_right {
position: absolute;
right: -5px;
bottom: 15px;
width: 0;
height: 0px;
border-top: 6px solid transparent;
border-left: 5px solid #494949;
border-bottom: 6px solid transparent
}
}

View File

@ -1,13 +1,13 @@
import React, { useEffect, useState } from 'react';
import { AlignCenter , FlexAJ } from '../Component/layout';
import { Link } from 'react-router-dom';
import { Popover , Spin , Button } from 'antd';
import { Popover , Spin } from 'antd';
import { getImageUrl } from 'educoder';
import './Component.scss';
import { getUser } from '../GetData/getData';
import axios from 'axios';
function Contributors({contributors,owner,projectsId,currentLogin}){
function Contributors({contributors,owner,projectsId}){
const [ menuList ,setMenuList ]= useState([]);
const [ list , setList ]= useState(undefined);
const [ total , setTotal ]= useState(0);
@ -46,60 +46,46 @@ function Contributors({contributors,owner,projectsId,currentLogin}){
}
}
function renderOrganize(list) {
let str = "";
list.map(i=>{
str = str+i.name + "、";
})
return str && str.substr(0,str.length - 1);
}
function setMenusFunc(data){
if(data){
let ele = (
<Spin spinning={isSpin}>
<FlexAJ className="menuMaininfos">
<FlexAJ>
<AlignCenter>
<Link to={`/${data.login}`}><img src={getImageUrl(`/${data.image_url}`)} alt="" className="radius" width="38px" height="38px"/></Link>
<div className="ml10">
<Link to={`/${data.login}`}>{data.name}</Link>
{ data.location && <span className="leftline">{data.location}</span> }
{
data.organizations && data.organizations.length>0&&
<p className="task-hide" style={{maxWidth:"215px"}}>
所属组织{renderOrganize(data.organizations)}
</p>
}
</div>
<Link to={`/users/${data.login}`}><img src={getImageUrl(`/${data.image_url}`)} alt="" className="radius" width="38px" height="38px"/></Link>
<Link to={`/users/${data.login}`} className="ml10">{data.name}</Link>
</AlignCenter>
{
data.is_watch ? <a className="color-grey-9" onClick={()=>FocusFunc(false,data.login)}>取消关注</a>:<a className="color-blue" onClick={()=>FocusFunc(true,data.login)}>关注</a>
}
</FlexAJ>
<AlignCenter className="menuinfos">
<Link to={`/${data.login}/projects`}>
<a href={data.projects_url}>
<span>{data.projects_count}</span>
<span>项目数</span>
</Link>
<Link to={`/${data.login}/followers`}>
</a>
<a href={data.followers_url}>
<span>{data.followers_count}</span>
<span>粉丝数</span>
</Link>
<Link to={`/${data.login}/following`}>
</a>
<a href={data.following_url}>
<span>{data.following_count}</span>
<span>关注数</span>
</Link>
</a>
</AlignCenter>
<div className={"pb20"} style={{display:"flex",justifyContent:'center'}}>
{
currentLogin && (currentLogin === data.login)
?
<Button className="currentBtn">当前用户</Button>
:
data.is_watch ?
<Button type={"default"} onClick={()=>FocusFunc(false,data.login)}>已关注</Button>
:
<Button type={"primary"} onClick={()=>FocusFunc(true,data.login)}>关注TA</Button>
}
</div>
{
data.organizations && data.organizations.length > 0 ?
<AlignCenter className="font-12 pt4 pb4">
<span>所属组织</span>
<div className="task-hide flex1">
{renderArray(data.organizations)}
</div>
</AlignCenter>
:""
}
{
data.location && <AlignCenter className="font-12 pt4 pb4"><span>所在地址:</span><span className="ml5">{data.location}</span></AlignCenter>
}
</Spin>
)
setMenu(ele);
@ -149,17 +135,17 @@ function Contributors({contributors,owner,projectsId,currentLogin}){
return(
<div className="halfs">
<Link to={`/${owner}/${projectsId}/contribute`} className="font-16 color-ooo hoverA">
<span>贡献者</span>
{ contributors && contributors.total_count > 0 && <span className="infoCount">{contributors.total_count}</span>}
</Link>
<FlexAJ>
<AlignCenter><span className="font-16 color-grey-6">贡献者</span>{ contributors && contributors.total_count > 0 && <span className="infoCount">{contributors.total_count}</span>}</AlignCenter>
<Link className="font-12 color-grey-9" to={`/projects/${owner}/${projectsId}/contribute`}>全部</Link>
</FlexAJ>
<div className="attrPerson" onMouseLeave={()=>setVisibleFunc(false)}>
{
total > 0 ?
list.map((item,key)=>{
return(
<Popover content={menu} visible={item.visible} overlayClassName="menuPanels" placement="top">
<Link key={key} to={`/${item.login}`}>
<Link key={key} to={`/users/${item.login}`}>
<img src={getImageUrl(`/${item.image_url}`)} alt="" onMouseOver={()=>setVisibleFunc(true,item.login,key)}/>
</Link>
</Popover>

View File

@ -1,51 +0,0 @@
import React, { useState, useCallback, memo } from 'react';
import { Tooltip } from 'antd';
CopyTool.defaultProps = {
beforeText: '复制链接', //
afterText: '复制成功', //
className: '', //svgclass
inputId: 'copyText', //ID
timeOut:true, //beforeText
};
function CopyTool({ beforeText, afterText, className , inputId , timeOut }) {
const [title, setTitle] = useState(() => {
return beforeText;
});
//
const copyUrl = useCallback(() => {
const copyEle = document.querySelector(`#${inputId}`); //
if (!copyEle) {
console.error("您的CopyTool未设置正确的inputId");
return;
}
copyEle.select(); //
if (document.execCommand('copy')) {
document.execCommand('copy');
}
document.getSelection().removeAllRanges();
setTitle(afterText);
if(timeOut){
setTimeout(function(){
setTitle(beforeText);
},1500)
}
}, []);
return (
<Tooltip
placement="top"
title={title}
onVisibleChange={() => { setTitle(beforeText) }}
>
<i className={`iconfont icon-fuzhiicon ${className}`} style={{ color: '#466aff' }} onClick={copyUrl}></i>
</Tooltip>
);
}
export default memo(CopyTool);

View File

@ -1,33 +0,0 @@
import React from 'react';
import { AlignCenter } from '../layout';
import { Button } from 'antd';
import Modals from '../PublicModal/Index';
function DeleteBox({
visible ,
onCancel ,
onSuccess ,
title ,
subTitle,
content
}) {
return(
<Modals
title={title}
btn={
<div>
<Button size={'large'} onClick={onCancel}>取消</Button>
<Button type={"danger"} size={"large"} onClick={onSuccess}>确认删除</Button>
</div>
}
onCancel={onCancel}
visible={visible}
>
<div className="desc">
<AlignCenter className="descMain"><i className="iconfont icon-shanchu_tc_icon mr10"></i>{content}</AlignCenter>
<p>{subTitle}</p>
</div>
</Modals>
)
}
export default DeleteBox;

View File

@ -4,12 +4,6 @@ import './Component.scss';
import axios from 'axios';
const { TreeNode , DirectoryTree } = Tree;
function turnbar(str){
if(str && str.length>0 && str.indexOf("/")>-1){
return str.replaceAll('/','%2F');
}
return str;
}
function DrawerPanel({visible,onClose,branch,owner,projectsId,history, name , list}){
const [ treeData , setTreeData ] = useState(undefined);
const [ isSpin , setIsSpin ] = useState(true);
@ -77,8 +71,7 @@ function DrawerPanel({visible,onClose,branch,owner,projectsId,history, name , li
let dataref = event.node.props.dataRef;
if(dataref.type==="file"){
onClose();
let value = turnbar(branch);
history.push(`/${owner}/${projectsId}/tree/${value}/${dataref.path}`);
history.push(`/projects/${owner}/${projectsId}/tree/${branch}/${dataref.path}`);
}
}

View File

@ -1,6 +1,9 @@
.ant-modal-mask{
z-index: 1031;
z-index: 10000;
}
.ant-modal-wrap{
z-index: 1032;
z-index: 10001;
.ant-form-explain{
position: absolute;
}
}

View File

@ -35,21 +35,26 @@ function EducoderAccount({form , visible , onOk , email}){
>
<div>
<p className="mb15 edu-txt-center" style={{maxWidth:"350px",margin:"0px auto"}}>
为确保您能正常使用平台功能请确认以下信息:
{
email ?
`平台已检测到您已绑定邮箱${email},请您确认如下操作`
:
"平台已检测到您未绑定邮箱,为不影响使用协同开发功能,请先绑定邮箱"
}
</p>
<Form {...layout}>
<Form.Item label="邮箱">
{getFieldDecorator("email",{
rules:[{required:true,message:"请输入邮箱账号"}]
})(
<Input placeholder="请输入您的邮箱账号" width="220px"/>
<Input placeholder="请输入您的邮箱账号" width="220px" disabled={email}/>
)}
</Form.Item>
<Form.Item label="密码">
{getFieldDecorator("password",{
rules:[{required:true,message:"请输入邮箱密码"}]
rules:[{required:true,message:"请输入您的平台密码"}]
})(
<Input.Password placeholder="请输入您的邮箱密码" width="220px"/>
<Input.Password placeholder="请输入您的平台密码" width="220px"/>
)}
</Form.Item>
</Form>

View File

@ -1,41 +0,0 @@
import React, { useState } from "react";
import { Input ,notification} from "antd";
const { Search } = Input;
export default ({history}) => {
const [openSearch, setOpenSearch] = useState(false);
function onGlobalSearch(value) {
history.push('/search?value=' + value);
// window.location.href = `search?value=` + value;
// history.push({
// pathname:'/search',
// state:value
// })
}
return (
<React.Fragment>
{
openSearch ?
<div
onBlur={() => {
setTimeout(() => {
setOpenSearch(false)
}, 500)
}}
>
<Search placeholder="请输入搜索关键字"
className={`search-input mr20`}
onSearch={onGlobalSearch}
autoFocus={true}
style={{width:'260px'}}
/>
</div>
:
<i className="iconfont icon-sousuo font-18 color-grey-6 ml30" onClick={() => {
setOpenSearch(true)
}} />
}
</React.Fragment>
)
};

View File

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

View File

@ -45,15 +45,15 @@ const Div = styled.div`{
export default (({ user , img, name, time, focusStatus, is_current_user, login , successFunc }) => {
return (
<Div>
<Link to={`/${user && user.login}`}><Img src={getImageUrl(`/${img}`)} /></Link>
<Link to={`/users/${user && user.login}`}><Img src={getImageUrl(`/${img}`)} /></Link>
<div className="m-infos">
<Link to={`/${user && user.login}`}><Name>{name}</Name></Link>
<Link to={`/users/${user && user.login}`}><Name>{name}</Name></Link>
<Time><I className="iconfont icon-shijian"></I>加入时间:{time}</Time>
{
is_current_user ?
<Button type="default">当前用户</Button>
:
<FocusButton is_watch={focusStatus} id={login} successFunc={successFunc} notReset={true}/>
<FocusButton is_watch={focusStatus} id={login} successFunc={successFunc}/>
}
</div>
</Div>

View File

@ -1,125 +0,0 @@
/* eslint-disable react/jsx-no-duplicate-props */
import React, { useState } from 'react';
import * as ReactDOM from 'react-dom';
import { Modal, Button } from 'antd';
import './index.scss';
//
InitModal.defaultProps = {
okText: '确认', //
cancelText: '取消', //
className: '', //
inputId: 'copyText', //ID
onCancel:()=>{}, //
onOk:()=>{}, //
title:'提示', //
contentTitle:'', //
content:'', //
afterClose:()=>{}, //
};
// 使
export default function DelModal(props) {
renderModal({ ...props, type: 'delete' })
}
// 使
export function Confirm(props) {
renderModal({ ...props, type: 'confirm' })
}
function renderModal(props) {
const { type, afterClose } = props;
const div = document.createElement('div');
document.body.appendChild(div);
function destroy() {
afterClose && afterClose();
const unmountResult = ReactDOM.unmountComponentAtNode(div);
if (unmountResult && div.parentNode) {
div.parentNode.removeChild(div);
}
}
function modalType(type) {
if (type === 'delete') {
return <InitModal
title="删除"
contentTitle="确定要删除吗?"
okText="确认删除"
{...props}
afterClose={destroy}
contentTitle={<React.Fragment>
<i className="red-circle iconfont icon-shanchu_tc_icon mr3"></i>
{props.contentTitle}
</React.Fragment>}
/>
} else if (type === 'confirm') {
return <InitModal title="选择" afterClose={destroy} {...props} />
} else {
return <InitModal title="选择" afterClose={destroy} {...props} />
}
}
function render() {
setTimeout(() => {
ReactDOM.render(
modalType(type),
div,
);
});
}
render();
}
//
function InitModal({
onCancel,
onOk,
title,
contentTitle,
content,
okText,
cancelText,
afterClose,
className,
}) {
const [visible, setVisible] = useState(true);
function onCancelModal() {
setVisible(false);
onCancel && onCancel()
}
function onSuccess() {
setVisible(false);
onOk && onOk();
}
return (
<Modal
visible={visible}
onCancel={onCancelModal}
afterClose={afterClose}
title={title}
className={`myself-modal ${className}`}
centered
footer={[
<Button type="default" key="back" onClick={onCancelModal}>
{cancelText}
</Button>,
<Button className="foot-submit" key="submit" onClick={onSuccess}>
{okText}
</Button>,
]}
>
<div>
{contentTitle && <p className="content-title">{contentTitle}</p>}
<p className="content-descibe">{content}</p>
</div>
</Modal>
)
}

View File

@ -1,63 +0,0 @@
.myself-modal {
.ant-modal-header {
padding: 9px 24px;
background: #f8f8f8;
border-bottom: 1px solid #eee;
}
.ant-modal-title {
text-align: left;
}
.ant-modal-close {
top: 0px !important;
}
.ant-modal-close-x {
font-size: 24px;
}
.ant-modal-body {
text-align: center;
}
.content-title {
display: flex;
justify-content: center;
align-items: center;
margin: 2rem 0 1rem !important;
font-size: 16px;
color: #333;
letter-spacing: 0;
line-height: 29px;
font-weight: 400;
}
.red-circle {
align-self: flex-start;
color: #ca0002;
font-size: 1.5rem !important;
}
.content-descibe {
font-size: 14px;
color: #666;
line-height: 33px;
font-weight: 400;
}
.ant-modal-footer {
padding: 2rem 0;
text-align: center;
border: 0;
.ant-btn {
width: 6rem;
}
}
.foot-submit {
margin-left: 3rem;
color: #df0002;
&:hover {
border-color: #df0002;
}
}
.ant-btn-default:hover,
.ant-btn-default:active,
.ant-btn-default:focus {
background: #f3f4f6;
color: #333;
border-color: #d0d0d0;
}
}

View File

@ -1,62 +0,0 @@
import React, {useEffect, useRef, useState} from 'react';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
import './Component.scss';
function Monaco(props) {
const {
style = { // dom
height: '400px',
},
value = '', //
onChange = () => { //
},
fontSize = 14, //
monacoOptions = {
scrollBeyondLastLine: false,
lineNumbers: "off",
wordWrap: true,
overviewRulerBorder: true,
lineHeight: 24,
readOnly:true
}, // monaco
language = 'html', // js ts sql css json html
} = props;
const editOrRef = useRef();
const ThisEditor = useRef();
useEffect(() => {
ThisEditor.current = monaco.editor.create(editOrRef.current, {
value: value || '',
language,
theme: "vs-grey",
fontSize: fontSize + 'px',
minimap: { //
enabled: false,
},
...monacoOptions,
});
ThisEditor.current.onDidChangeModelContent((e) => {
let newValue = ThisEditor.current.getValue();
onChange(newValue);
});
return () => {
ThisEditor.current.dispose();
ThisEditor.current = undefined; //
}
}, []);
useEffect(() => {
if (ThisEditor.current) {
ThisEditor.current.updateOptions({
fontSize: fontSize + 'px',
})
}
}, [fontSize]);
return (
<div style={style} ref={editOrRef}>
</div>
);
}
export default Monaco;

View File

@ -1,90 +0,0 @@
.systemBox{
.ant-modal-body{
padding:1px 0px 0px 0px;
.sysBox{
background-image: url('./bg.png');
background-repeat: no-repeat;
background-size: 100% 334px;
margin-top: -55px;
}
.sysnoticeBox{
width: 100%;
padding:80px 0px 34px;
display: flex;
flex-direction: column;
width: 780px;
margin: 0px auto;
p.ntitle{
height: 33px;
font-size: 24px;
font-weight: 500;
color: #31FFF7;
line-height: 33px;
text-align: center;
}
p.nSubtitle{
height: 25px;
line-height: 25px;
font-size: 18px;
font-weight: 500;
color: #FFFFFF;
margin-top: 60px;
padding-left: 20px;
}
.markdown-body{
box-shadow: 0px 0px 17px rgba(0,0,0,0.2);
border-radius: 4px;
margin-top: 17px!important;
}
.nContent{
padding:20px 34px;
background-color: #fff;
line-height: 30px;
font-size: 15px;
font-weight: 400;
color: #333;
.realmName{
margin-top: 20px;
display: flex;
ul{
width: 50%;
padding-left: 0px!important;
li{
font-size: 15px;
font-weight: 500;
line-height: 32px;
text-align: left;
color: #000;
list-style-type: none!important;
&:first-child{
color: #E65714;
}
}
}
}
.nSubdesc{
font-size: 15px;
font-weight: 400;
color: #000000;
line-height: 31px;
margin-top: 20px;
}
.nInfo{
font-size: 14px;
font-weight: 400;
color: #333333;
text-align: right;
margin-top: 25px;
p{
height: 20px;
line-height: 20px;
}
}
}
.nBtn{
text-align: center;
margin-top: 33px;
}
}
}
}

View File

@ -1,76 +0,0 @@
import React , { useEffect , useState } from 'react';
import { Modal , Button } from 'antd';
import './Index.scss';
import '../../css/index.scss';
import RenderHtml from '../../../components/render-html';
import cookie from 'react-cookies';
function SystemNotice({system_notification,history}){
const [ visible , setVisible ] = useState(false);
useEffect(()=>{
if(system_notification && !cookie.load('notice_stage')){
setVisible(true);
}
},[system_notification,history.location])
function sureContinue() {
cookie.remove('notice_stage');
let inFifteenMinutes = new Date(new Date().getTime() + 24 * 3600 * 1000);//
// let inFifteenMinutes = new Date(new Date().getTime() + 60 * 1000);//
cookie.save('notice_stage', true,{ expires: inFifteenMinutes,path:"/" });
setVisible(false);
}
return (
<Modal
visible = {visible}
width="1000px"
footer={false}
title={false}
centered={true}
closable={false}
wrapClassName={'systemBox'}
>
<div className="sysBox">
<div className="sysnoticeBox">
<p className="ntitle">{system_notification && system_notification.subject}</p>
<p className="nSubtitle">{system_notification && system_notification.sub_subject}</p>
{/* <div className="nContent">
<div className="nMaindesc">
为了给用户提供更加稳定优质的服务我们即将对平台门户首页平台名称平台域名进行一次全面升级与变更原平台名称Trustie中文名确实将于2021年10月xx日统一更改为Gitlink中文名确实开源届时平台域名将统一进行更换更换规则如下
</div>
<div className="realmName">
<ul>
<li>原域名</li>
<li>官网顶级域名https://www.trustie.net</li>
<li>版本库子域名https://forgeplus.trustie.net</li>
<li>论坛子域名https://forum.trustie.net/forums</li>
</ul>
<ul>
<li>更换后域名</li>
<li>官网顶级域名https://www.gitlink.org.cn</li>
<li>版本库子域名https://www.git.gitlink.org.cn</li>
<li>论坛子域名https://forum.gitlink.org.cn</li>
</ul>
</div>
<div className="nSubdesc">
自2021年10月xx日起旧域名将停止访问因平台名称与域名变更给您带来的不便我们深表歉意!非常感谢您一直以来对本平台的信任与支持我们将一如既往地为您提供优质的服务 特此通知!
</div>
<div className="nInfo">
<p>Gitlink运营团队</p>
<p>2021年10月xx日</p>
</div>
</div> */}
<RenderHtml className="break_word_comments imageLayerParent" value={system_notification && system_notification.content} url={history.location}/>
<div className="nBtn">
<Button type="primary" className="btnblue" onClick={sureContinue}>确认并继续</Button>
</div>
</div>
</div>
</Modal>
)
}
export default SystemNotice;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

View File

@ -1,72 +0,0 @@
import React , { useEffect , useState } from 'react';
import Modals from '../PublicModal/Index';
import { Button } from 'antd';
import axios from 'axios';
import ProfileImg from './images/profile.png';
import './Index.scss';
function ProfileModal({visible,onCancel,history}) {
const [ modalVis , setModalVis ] = useState(visible);
const [ addMemberCheck , setAddMemberCheck ] = useState(false);
useEffect(()=>{
axios.interceptors.response.use((response) => {
if (response && (response.data.status === 411 || response.data.status === 412)) {
setModalVis(true);
if(response.data.status === 412){
setAddMemberCheck(true);
}
}
return response;
}, (error) => {
});
},[])
useEffect(()=>{
setModalVis(visible);
},[visible])
function onOk(){
onCancel();
setModalVis(false);
setTimeout(function(){
window.open(`/settings/profile`,"_blank");
},200)
}
function onNo() {
onCancel();
setModalVis(false);
}
return(
<Modals
title="完善资料"
onCancel={onNo}
visible={modalVis}
btn={
addMemberCheck?
<div>
<Button type={'primary'} size={"large"} onClick={onNo}>好的</Button>
</div>
:
<div>
<Button size={"large"} onClick={onNo}>暂不补充</Button>
<Button type={'primary'} size={"large"} onClick={onOk}>好的</Button>
</div>
}
>
<div className="contents">
<img src={ProfileImg} alt=""/>
{
addMemberCheck ?
<p>目标用户个人资料不完整需提醒目标用户补充资料后以进行后续操作</p>
:
<p>您目前的个人资料不完整需要补充资料以进行后续操作是否前往补充个人信息</p>
}
</div>
</Modals>
)
}
export default ProfileModal;

View File

@ -1,18 +0,0 @@
.contents{
display: flex;
align-items: center;
justify-content: center;
margin:10px auto 0px;
img{
margin-right: 13px;
width: 44px;
}
p{
line-height: 29px;
max-width: 327px;
font-size: 16px!important;
}
}
.font-44{
font-size: 44px!important;
}

View File

@ -1,17 +0,0 @@
import React from 'react';
function Profile({children,sureFunc,showCompeleteDialog , completeProfile, className}) {
function checkProfile() {
if(!completeProfile){
showCompeleteDialog && showCompeleteDialog();
}else{
sureFunc();
}
}
return(
<a className={className} onClick={checkProfile}>{children}</a>
)
}
export default Profile;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -1,20 +0,0 @@
import React from 'react';
import { Modal } from 'antd';
import './Index.scss';
function Modals({title,children,btn,onCancel,visible}) {
return(
<Modal
visible={visible}
onCancel={onCancel}
title={title}
width={"520px"}
footer={btn}
centered={true}
wrapClassName={"deleteBox"}
>
{children}
</Modal>
)
}
export default Modals;

View File

@ -1,75 +0,0 @@
.deleteBox{
z-index: 1033;
.ant-modal-close-x{
font-size: 17px!important;
}
.ant-modal-header{
background-color: #f8f8f8;
padding:10px 30px;
.ant-modal-title{
text-align: left;
font-size: 16px;
font-weight: bold;
}
}
.ant-modal-close{
top:0px !important;
font-size: 24px !important;
}
.ant-modal-body{
padding:30px 50px;
p{
font-size: 14px;
line-height: 26px;
color:#666;
word-break: break-all;
}
.desc{
.descMain{
align-items: center;
justify-content: center;
font-size: 20px;
margin-bottom: 10px;
i.red{
color:#DF0002;
}
}
}
}
.ant-modal-footer{
border-top: none;
text-align: center;
padding-bottom: 40px;
button,a{
width: 96px;
height: 32px;
margin:0px 20px;
font-weight: 400;
font-size: 14px;
&.ant-btn{
border-color: #D0D0D0;
color: #666;
&:hover,&:active,&:focus{
background: #f3f4f6;
}
}
&.ant-btn-danger{
background-color: #fff;
color: #DF0002;
border-color: #D0D0D0;
&:hover,&:active,&:focus{
border-color: #DF0002;
background-color: #fff;
}
}
&.ant-btn.ant-btn-primary{
background-color: #466AFF;
color: #fff;
border-color: #466AFF;
&:hover,&:focus,&:active{
background-color: rgba(70,106,255,0.85);
}
}
}
}
}

View File

@ -1,35 +1,38 @@
import React from 'react';
import { AlignTop } from '../Component/layout';
import { AlignCenter , AlignTop , FlexAJ } from '../Component/layout';
import { Link } from 'react-router-dom';
function Releases({ owner, projectsId, releaseVersions, distribution }) {
function Releases({owner,projectsId,releaseVersions}){
return(
<div>
<Link to={`/${owner}/${projectsId}/releases`} className="font-16 color-ooo hoverA">
<span>发行版</span>
{ releaseVersions && releaseVersions.total_count > 0 && <span className="infoCount">{releaseVersions.total_count}</span>}
</Link>
<FlexAJ>
<AlignCenter><span className="font-16 color-grey-6">发行版</span>
{ releaseVersions && releaseVersions.total_count > 0 && <span className="infoCount">{releaseVersions.total_count}</span>}
</AlignCenter>
{ releaseVersions && releaseVersions.total_count > 0 ?
<Link className="font-12 color-grey-9" to={`/projects/${owner}/${projectsId}/releases`}>全部</Link>
:
<Link className="font-12 color-blue" to={`/projects/${owner}/${projectsId}/releases/new`}>新建</Link>
}
</FlexAJ>
{
releaseVersions && releaseVersions.total_count>0 ?
releaseVersions.list.map((item,key)=>{
return(
key === 0 &&<AlignTop className="mt10">
<AlignTop className="mt10">
<i className="iconfont icon-biaoqian3 color-grey-6 font-18 mr10"></i>
<div>
<p className="font-16 color-grey-6" style={{display:'flex',alignItems:'center'}}>
{/* 如果是点击最新则发行版列表页只展示最新的一个 */}
<Link to={{pathname:`/${owner}/${projectsId}/releases`,query:{turnFromNew:true}}} style={{maxWidth:'200px',overflow: 'hidden',whiteSpace: 'nowrap',textOverflow:'ellipsis'}}>{item.name}</Link>
<p className="font-16 color-grey-6">
<Link to={`/projects/${owner}/${projectsId}/releases`}>{item.name}</Link>
<span className="font-12 laterest ml5">最新</span>
</p>
<p className="color-grey-3 font-12">{item.created_at}</p>
<p className="color-grey-9 font-13">{item.created_at}</p>
</div>
</AlignTop>
)
})
:
<div className="mt8">
您暂未发布任何版本
{distribution && <Link className="color-blue ml20" to={{pathname:`/${owner}/${projectsId}/releases/new`,state:{stable:true}}}>创建新版本</Link>}
</div>
:""
}
</div>

View File

@ -1,49 +1,45 @@
import React , { useState , useEffect } from 'react';
import React , { useState } from 'react';
import { AutoComplete } from 'antd';
import { getImageUrl } from "educoder";
import axios from 'axios';
const Option = AutoComplete.Option;
export default ({ getUser , placeholder, width ,value })=>{
const [ source , setSource ] = useState(undefined);
export default ({ getUser })=>{
const [ searchKey , setSearchKey ] = useState(undefined);
useEffect(()=>{
if(!value){
setSearchKey(undefined);
}
},[value])
useEffect(()=>{
getUserList();
},[searchKey])
const [ userDataSource , setUserDataSource ] = useState(undefined);
function getUserList(e){
const url = `/users/list.json`;
axios.get(url, {
params: {
search: searchKey,
search: e,
},
}).then((result) => {
})
.then((result) => {
if (result) {
sourceOptions(result.data.users);
setUserDataSource(result.data.users);
}
})
.catch((error) => {
console.log(error);
});
};
function changeInputUser(value){
setSearchKey(value);
getUserList(value);
}
function sourceOptions(userDataSource){
const s = userDataSource && userDataSource.map((item, key) => {
function selectInputUser(id, option){
setSearchKey(option.props.value);
getUserList(option.props.value);
getUser && getUser(id);
}
const source =
userDataSource && userDataSource.map((item, key) => {
return (
<Option
key={key}
value={`${item.user_id}`}
login={`${item.login}`}
name={item.username}
>
<Option key={key} value={`${item.login}`}>
<img
className="user_img radius"
width="28"
@ -58,31 +54,14 @@ export default ({ getUser , placeholder, width ,value })=>{
</Option>
);
});
setSource(s);
}
function changeInputUser(e){
setSearchKey(e);
};
//
function selectInputUser(e, option){
setSearchKey(option.props.name);
getUser(option.props.login);
};
return(
<div className="addPanel">
<AutoComplete
getPopupContainer={trigger => trigger.parentNode}
dataSource={source}
value={searchKey}
style={{ width: width || 300 }}
onChange={changeInputUser}
onSelect={selectInputUser}
placeholder={placeholder || "搜索需要添加的用户..."}
allowClear
/>
</div>
<AutoComplete
dataSource={source}
value={searchKey}
style={{ width: 300 }}
onChange={changeInputUser}
onSelect={selectInputUser}
placeholder="搜索需要添加的用户..."
/>
)
}

View File

@ -1,91 +0,0 @@
import React, { useEffect, useState } from 'react';
import { Popover , Tooltip } from 'antd';
import './Component.scss';
import axios from 'axios';
import ShareModal from './SiderBarShareModal';
const $ = window.$;
$(window).scroll(function () {
if ($(".gotop").length > 0) {
if ($(document).scrollTop() > 0) {
$(".-task-sidebar .gotop").show();
$(".gotop").click(function () {
$("html,body").scrollTop(0);
});
}
if ($(document).scrollTop() === 0) {
$(".-task-sidebar .gotop").hide();
}
}
});
function SiderBar() {
const [ data , setData ] = useState([]);
const [ visible , setVisible ] = useState(false);
useEffect(()=>{
getFAQ();
},[])
function getFAQ(){
const url = `/faqs.json`;
axios.get(url).then(result=>{
if(result && result.data){
setData(result.data);
}
}).catch(error=>{})
}
function content(list){
return <div>
<p className="titlecontent">帮助</p>
<ul className="faqUl">
{
list && list.map((i,k)=>{
return(
<li key={i.question+k}><a href={`${i.url}`} title={i.question} target="_blank">{i.question}</a></li>
)
})
}
</ul>
</div>
}
function shareContent(){
return <div>
<ul className="shareUl">
<p className="titlecontent">分享到</p>
<li onClick={()=>setVisible(true)}><i className="iconfont icon-weixin2" style={{color:"#62b900"}}></i></li>
</ul>
</div>
}
return (
<div className={"-task-sidebar"} >
<ShareModal visible={visible} urlValue={window.location.href} onCancel={()=>setVisible(false)}/>
{
data && data.length > 0 && (data[0] && data[0].question) ?
<Popover content={content(data)} overlayClassName="helpBox" placement={"left"}>
<div className="feedback">
<i className="iconfont icon-bangzhu font-22"></i>
</div>
</Popover>
:""
}
{/* <div className="scan pr" title="">
<span className="inline erweima"><i className="iconfont icon-erweima color-white font-22 fl"></i></span>
</div>*/}
<Popover content={shareContent()} overlayClassName="helpBox shareContent" placement={"left"}>
<div className="consult">
<i className="iconfont icon-fenxiang1"></i>
</div>
</Popover>
<div className="gotop">
<Tooltip title="返回顶部" placement={"right"}>
<a><i className="iconfont icon-huidaodingbu1"></i></a>
</Tooltip>
</div>
</div>
)
}
export default SiderBar;

View File

@ -1,27 +0,0 @@
import React from 'react';
import { Modal } from 'antd';
import QRCode from 'qrcode.react';
function SiderBarShareModal({visible,urlValue,onCancel}) {
return(
<Modal
title={"分享到微信"}
visible={visible}
width="500px"
closable={true}
footer={false}
onCancel={onCancel}
>
<div style={{textAlign:"center"}}>
{urlValue &&<QRCode
value={urlValue}
size={200}
fgColor="#000000"
style={{margin:"20px"}}
/>}
<p>打开微信扫一扫,点击右上角菜单即可将网页分享至朋友圈</p>
</div>
</Modal>
)
}
export default SiderBarShareModal;

View File

@ -2,9 +2,9 @@ import React from 'react';
import {Popover} from 'antd';
import './Component.scss';
export default (({menu , children, overlayClassName})=>{
export default (({menu , children})=>{
return(
<Popover content={menu} trigger={['click']} placement='bottom' overlayClassName={overlayClassName}>
<Popover content={menu} trigger={['click']} placement='bottom'>
{children}
</Popover>
)

View File

@ -1,11 +1,10 @@
import React from 'react';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
export default ({ url , name , column , id , login })=>{
export default ({ url , name , column })=>{
const Img = styled.span`
display:flex;
font-weight: bold;
${column && "flex-direction: column;text-align:center;"}
align-items: center;
& img{
@ -20,14 +19,6 @@ export default ({ url , name , column , id , login })=>{
}
`;
return(
id?
<Link to={`/${login}`}>
<Img>
{ url && <img src={url} alt=""/> }
<span>{name}</span>
</Img>
</Link>
:
<Img>
{ url && <img src={url} alt=""/> }
<span>{name}</span>

View File

@ -28,11 +28,6 @@ export const AlignTop = styled.div`{
display:flex;
align-items: flex-start;
}`
export const AlignAJBottom = styled.div`{
display:flex;
justify-content: space-between;
align-items: flex-end;
}`
//
export const Box = styled.div`{
display:flex;

View File

@ -36,6 +36,7 @@ function About(props, ref) {
const [ disabled, setDisabled ] = useState(false);
const [ typeFlag, setTypeFlag] = useState(false);
const AuthorLogin = props.projectDetail && props.projectDetail.author && props.projectDetail.author.login;
const CurrentLogin = props.current_user && props.current_user.login;
useEffect(()=>{
@ -55,6 +56,11 @@ function About(props, ref) {
setIsSpining(false);
if(result && result.data ){
setStep(result.data.step);
// setStep(0);
// setFieldsValue({...result.data.cloud_account});
// if(result.data.cloud_account){
// setDisabled(true);
// }
}
}).catch(error=>{
setIsSpining(false);
@ -149,7 +155,7 @@ function About(props, ref) {
axios.post(url).then(result=>{
setIsSpining(false);
if(result && result.data.status === 0){
props.history.push(`/${owner}/${projectsId}/devops`);
props.history.push(`/projects/${owner}/${projectsId}/devops/dispose`);
// open_devops
let { changeOpenDevops } = props;
changeOpenDevops && changeOpenDevops(true);

View File

@ -96,7 +96,7 @@ function Dispose(props){
setVisible(false);
if(result && result.data){
props.showNotification("流水线新增成功,请进行工作流配置!");
props.history.push(`/${owner}/${projectsId}/devops/${result.data.id}`);
props.history.push(`/projects/${owner}/${projectsId}/devops/dispose/${result.data.id}`);
}else{
props.showNotification("流水线新增失败,请稍后再试!");
}
@ -134,12 +134,12 @@ function Dispose(props){
//
function toModalManage(){
props.history.push(`/${owner}/${projectsId}/devops/mould`);
props.history.push(`/projects/${owner}/${projectsId}/devops/mould`);
}
//
function toparameter(){
props.history.push(`/${owner}/${projectsId}/devops/params`);
props.history.push(`/projects/${owner}/${projectsId}/devops/params`);
}
const operate = current_user && (permission && permission !== "Reporter");

View File

@ -10,12 +10,6 @@ import { Link } from 'react-router-dom';
// killed:"",
// pending:""
// }
function turnbar(str){
if(str && str.length>0 && str.indexOf("/")>-1){
return str.replaceAll('/','%2F');
}
return str;
}
function renderTableStatus(status) {
switch (status) {
case "running":
@ -71,9 +65,8 @@ function List({ list, operate , projectsId , owner , showModal , deleteFunc }){
width:"15%",
ellipsis:true,
render:(value,item)=>{
let v = turnbar(item.branch);
return(
<Link to={`/${owner}/${projectsId}/tree/${v}/${value}`} className="color-blue">{value}</Link>
<Link to={`/projects/${owner}/${projectsId}/tree/${item.branch}/${value}`} className="color-blue">{value}</Link>
)
}
},
@ -117,7 +110,7 @@ function List({ list, operate , projectsId , owner , showModal , deleteFunc }){
return(
<span>
{ operate ?
<Link to={`/${owner}/${projectsId}/devops/${item.id}`} className="mr10 color-grey-6">
<Link to={`/projects/${owner}/${projectsId}/devops/dispose/${item.id}`} className="mr10 color-grey-6">
<i className="iconfont icon-zaibianji font-13 mr3"></i>编辑</Link> :""
}
{ operate ?
@ -125,7 +118,7 @@ function List({ list, operate , projectsId , owner , showModal , deleteFunc }){
<a className="mr10 color-grey-6"><i className="iconfont icon-lajitong font-13 mr3"></i>删除</a>
</Popconfirm>:""
}
<Link to={`/${owner}/${projectsId}/devops/list/${item.branch}`} className="color-grey-6"><i className="iconfont icon-yunhang font-13 mr3"></i>查看运行记录</Link>
<Link to={`/projects/${owner}/${projectsId}/devops/list/${item.branch}`} className="color-grey-6"><i className="iconfont icon-yunhang font-13 mr3"></i>查看运行记录</Link>
</span>
)
}

View File

@ -42,7 +42,7 @@ function PipelineName({visible,onCancel,onOk,value ,branchList}){
</div>
<div className="choosenList mt20">
<span>触发条件:</span>
<Select value={branchValue} style={{width:"150px"}} dropdownClassName="chooseCon" onChange={(e)=>setBranchValue(e)}>
<Select value={branchValue} style={{width:"150px"}} onChange={(e)=>setBranchValue(e)}>
{
branchList && branchList.length>0 && branchList.map((item,key)=>{
return(
@ -51,7 +51,7 @@ function PipelineName({visible,onCancel,onOk,value ,branchList}){
})
}
</Select>
<Select mode="multiple" allowClear value={eventValue} dropdownClassName="chooseCon" style={{width:"180px",marginLeft:"10px"}} onChange={(e)=>{setEventValue(e)}}>
<Select mode="multiple" allowClear value={eventValue} style={{width:"180px",marginLeft:"10px"}} onChange={(e)=>{console.log(e);setEventValue(e)}}>
{
EVENT.map((item,key)=>{
return(

View File

@ -36,37 +36,39 @@ export default ((props)=>{
return(
<WhiteBack className="opsPanel">
<Switch {...props}>
<Route path="/:owner/:projectsId/devops/params"
<Route path="/projects/:owner/:projectsId/devops/dispose/:disposeId"
render={
(p) => (<New {...props} {...p}/>)
}
></Route>
<Route path="/projects/:owner/:projectsId/devops/params"
render={
(p) => (<Params {...props} {...p}/>)
}
></Route>
<Route path="/:owner/:projectsId/devops/mould"
<Route path="/projects/:owner/:projectsId/devops/mould"
render={
(p) => (<Mould {...props} {...p}/>)
}
></Route>
<Route path="/:owner/:projectsId/devops/new"
<Route path="/projects/:owner/:projectsId/devops/dispose/new"
render={
(p) => (<New {...props} {...p}/>)
}
></Route>
<Route path="/:owner/:projectsId/devops/list/:branch"
<Route path="/projects/:owner/:projectsId/devops/dispose"
render={
(p) => (<Dispose {...props} {...p}/>)
}
></Route>
<Route path="/projects/:owner/:projectsId/devops/list/:branch"
render={
(p) => (<Stucture {...props} {...p}/>)
}
></Route>
<Route path="/:owner/:projectsId/devops/:disposeId"
<Route path="/projects/:owner/:projectsId/devops"
render={
(p) => (<New {...props} {...p}/>)
}
></Route>
{/* 原本的两种合为一个 */}
<Route path="/:owner/:projectsId/devops"
render={
(p) =>{return( p.location.state.open_devops?<Dispose {...props} {...p}/>:<About {...props} {...p}/>)}
(p) => (<About {...props} {...p}/>)
}
></Route>
</Switch>

View File

@ -26,7 +26,7 @@ export default ((props)=>{
return(
<div className="disposePanel">
<Banner>
{ permission !=="Reporter" && <Link to={`/${owner}/${props.match.params.projectsId}/devops`}>工作流配置</Link>}
{ permission !=="Reporter" && <Link to={`/projects/${owner}/${props.match.params.projectsId}/devops/dispose`}>工作流配置</Link>}
</Banner>
<Div>
<Dispost {...props}/>

View File

@ -104,7 +104,7 @@ function Params(props){
<Banner>
<FlexAJ>
<span className="font-18">工作流 - 参数管理</span>
<Link to={`/${owner}/${projectsId}/devops`} className="font-14 color-grey-9 ml20">返回</Link>
<Link to={`/projects/${owner}/${projectsId}/devops/dispose`} className="font-14 color-grey-9 ml20">返回</Link>
</FlexAJ>
</Banner>
<Div className="disposeList">

View File

@ -126,7 +126,7 @@ function Mould(props){
<div>
<New wrappedComponentRef={(f) => childRef.current = f} ref={childRef} visible={visible} onCancel={()=>setVisible(false)} onOk={onOk}></New>
<Banner>
<FlexAJ><span>工作流 - 模板管理</span><Link to={`/${owner}/${projectsId}/devops`} className="font-14 color-grey-9">返回</Link></FlexAJ>
<FlexAJ><span>工作流 - 模板管理</span><Link to={`/projects/${owner}/${projectsId}/devops/dispose`} className="font-14 color-grey-9">返回</Link></FlexAJ>
</Banner>
<Div className="disposeList">
<FlexAJ>

View File

@ -1,8 +1,7 @@
import React, { useState, useEffect } from "react";
import { Spin , Menu } from "antd";
import { Spin } from "antd";
import { FlexAJ, AlignCenter } from "../Component/layout";
import axios from "axios";
import CodeSSH from './ssh/Index';
export default ({
data,
@ -18,8 +17,6 @@ export default ({
const [spining, setSpining] = useState(true);
const [stage, setStage] = useState(undefined);
const [step, setStep] = useState(undefined);
const [nav, setNav] = useState("0");
useEffect(() => {
setSpining(rightSpin);
}, [rightSpin]);
@ -38,7 +35,6 @@ export default ({
: p[0];
setStep(sub);
setNav("0");
if (sub && sub.status !== "skipped") {
getStep(pre.number, sub.number);
}
@ -69,55 +65,43 @@ export default ({
}
}
return (
<React.Fragment>
{/* <Menu className="devopsNav" onClick={(e)=>{setNav(e.key)}} selectedKeys={[nav]} mode="horizontal">
<Menu.Item key={'0'} value="0">开发流水线</Menu.Item>
<Menu.Item key={'1'} value="1">命令行</Menu.Item>
</Menu> */}
{
nav === "0" &&
<Spin spinning={spining}>
<div className="rightMainContent">
{data && data.status !== "error" ? (
<div>
<FlexAJ className="items">
<span>{step && step.name}</span>
<AlignCenter>
{step && step.duration_time}
<i className="iconfont icon-sanjiaoxing-down"></i>
</AlignCenter>
</FlexAJ>
<div>
{coders && coders.length > 0 ? (
coders.map((item, key) => {
return (
<div className="opsDetailOut">
<span>{key + 1}</span>
<p>{item.out}</p>
</div>
);
})
) : empty ? (
<Spin spinning={spining}>
<div className="rightMainContent">
{data && data.status !== "error" ? (
<div>
<FlexAJ className="items">
<span>{step && step.name}</span>
<AlignCenter>
{step && step.duration_time}
<i className="iconfont icon-sanjiaoxing-down"></i>
</AlignCenter>
</FlexAJ>
<div>
{coders && coders.length > 0 ? (
coders.map((item, key) => {
return (
<div className="opsDetailOut">
<span>1</span>
<p>
{stage && stage.name} {step && step.name}: Skipped
</p>
<span>{key + 1}</span>
<p>{item.out}</p>
</div>
) : (
""
)}
);
})
) : empty ? (
<div className="opsDetailOut">
<span>1</span>
<p>
{stage && stage.name} {step && step.name}: Skipped
</p>
</div>
</div>
) : (
<div style={{ color: "red" }}>error:{data && data.error}</div>
)}
) : (
""
)}
</div>
</div>
</Spin>
}
{
nav === "1" && <CodeSSH />
}
</React.Fragment>
) : (
<div style={{ color: "red" }}>error:{data && data.error}</div>
)}
</div>
</Spin>
);
};

View File

@ -12,7 +12,7 @@ function ServiceModal({sureModal}){
<div className="mt30" style={{textAlign:"center"}}>
<Radio.Group value={type} onChange={changeType}>
<Radio value={1}>自有服务器</Radio>
<Radio value={2}>Trustie服务器</Radio>
<Radio value={2}>EduCoder服务器</Radio>
</Radio.Group>
<p className="mt30"><Button type="primary" onClick={()=>sureModal(type)}>下一步</Button></p>
</div>

View File

@ -2,7 +2,7 @@ import React, { useState, useEffect , useImperativeHandle ,forwardRef } from "re
import { FlexAJ, AlignCenter , Banner } from "../Component/layout";
import { Table, Pagination, Popconfirm } from "antd";
import { truncateCommitId } from "../common/util";
import { getImageUrl } from 'educoder';
import {getUrl} from 'educoder';
import axios from "axios";
import { Link } from 'react-router-dom';
@ -198,7 +198,7 @@ function Structure(props,ref){
}
function clickRows(event,e){
props.history.push(`/${owner}/${projectsId}/devops/${e.number}/detail`);
props.history.push(`/projects/${owner}/${projectsId}/devops/${e.number}/detail`);
}
const column = [
{
@ -245,7 +245,7 @@ function Structure(props,ref){
{meg.sha && <span className="color-orange">{meg.sha}</span>}
</div>
<AlignCenter>
<img style={{borderRadius:"50%",marginRight:"10px",width:"25px",height:"25px"}} alt="" src={`${item.image_url && getImageUrl(`/${item.image_url}`)}`} />
<img style={{borderRadius:"50%",marginRight:"10px",width:"25px",height:"25px"}} alt="" src={`${item.image_url && getUrl(`/images/${item.image_url}`)}`} />
<div className="task-hide ml5" style={{ maxWidth: "300px" }}>
{meg.message}
</div>
@ -290,7 +290,7 @@ function Structure(props,ref){
<Banner>
<FlexAJ>
<span>构建列表</span>
<Link to={`/${owner}/${projectsId}/devops`} className="font-15 color-grey-9">返回</Link>
<Link to={`/projects/${owner}/${projectsId}/devops/dispose`} className="font-15 color-grey-9">返回</Link>
</FlexAJ>
</Banner>
<Div>

View File

@ -275,7 +275,7 @@ function disposePipeline(props){
...params
}).then(result=>{
if(result){
props.history.push(`/${owner}/${projectsId}/devops`);
props.history.push(`/projects/${owner}/${projectsId}/devops/dispose`);
}
setLoading(false);
}).catch(error=>{

View File

@ -194,18 +194,6 @@
&.rightSection{
width:100%;
background-color: #081930;
.devopsNav{
background-color: #111c24;
border-bottom: none;
.ant-menu-item{
color: #ccc;
padding:0px;
margin:0px 20px!important;
}
.ant-menu-item.ant-menu-item-selected{
color: #1890ff;
}
}
.rightMainContent{
padding:24px 30px;
height:100vh;
@ -391,9 +379,6 @@
}
}
}
.chooseCon.ant-select-dropdown{
z-index: 100001;
}
.choosenList{
display: flex;

View File

@ -48,7 +48,7 @@ export default (props) => {
axios.post(url).then((result) => {
if (result && result.data) {
props.showNotification("工作流正在重新构建!");
props.history.push(`/${owner}/${projectId}/devops/${result.data.number}/detail`);
props.history.push(`/projects/${owner}/${projectId}/devops/${result.data.number}/detail`);
}
})
.catch((error) => {
@ -87,7 +87,7 @@ export default (props) => {
</AlignCenter>
<Link
style={{ color: "#ddd" }}
to={`/${owner}/${projectId}/devops`}
to={`/projects/${owner}/${projectId}/devops/dispose`}
>
<i className="iconfont icon-yiguanbi font-15 mr5"></i>退出
</Link>

View File

@ -1,42 +0,0 @@
import React, { useState, useEffect } from "react";
import XmlPanel from "./XmlPanel";
import mediator from "./mediator";
import axios from "axios";
// const defaulturl = `http://47.111.130.18:48088`;
const defaultValue = {
host: "106.75.231.63",
port: "2021",
ws_url: "wss://pre-webssh.educoder.net/ws",
username: "root",
secret: "Dron_123123",
};
function Index() {
const [sshConfigData, setSshConfigData] = useState(undefined);
useEffect(() => {
if (!sshConfigData) {
init();
}
setTimeout(() => {
mediator.publish("create-socket", 1);
}, 300);
}, [sshConfigData]);
//
function init() {
const url = `/api/ci/pipelines/ssh_server.json`;
axios.get(url).then(result=>{
if(result && result.data){
setSshConfigData({...result.data})
}
}).catch(error=>{})
}
return (
<XmlPanel
sshConfigData={sshConfigData||{}}
sid={1}
/>
);
}
export default Index;

View File

@ -1,216 +0,0 @@
import React, { useRef, useEffect, useState } from 'react';
import { Base64 } from 'js-base64';
import { Terminal } from 'xterm';
import 'xterm/css/xterm.css';
import mediator from './mediator';
import ResizeObserver from 'resize-observer-polyfill';
function getColsAndRows(width, height, term) {
let w = term._core._renderService.dimensions.actualCellWidth || 9.5;
let h = term._core._renderService.dimensions.actualCellHeight || 18;
const rows = Math.floor(height / h);
const cols = Math.floor(width / w);
return [cols, rows];
}
function onLayout(term, el) {
const ro = new ResizeObserver(entries => {
console.log(entries);
for (let entry of entries) {
if (entry.target.offsetHeight > 0 || entry.target.offsetWidth > 0) {
const [cols, rows] = getColsAndRows(
entry.target.offsetWidth,
entry.target.offsetHeight,
term,
);
term.resize(cols, rows);
mediator.publish('ssh-xterm-resize', {
columns: cols,
rows: rows,
width: entry.target.offsetWidth,
height: entry.target.offsetHeight,
});
}
}
});
ro.observe(el);
return ro;
}
const TimeTicket = 30000;
// websockt
//
//socket term socket
//mediator id
export default ({ sshConfigData, sid }) => {
const [term, setTerm] = useState(null);
const { ws_url, password, port, secret } = sshConfigData;
const el = useRef();
const socket = useRef();
const isFirstConnected = useRef(false);
//term init
useEffect(() => {
if (el.current && ws_url) {
const term = new Terminal({ fontSize: 16, rendererType: 'dom' });
term.open(el.current);
term.onData(data => {
if (socket.current) {
if (socket.current.readyState === 1) {
socket.current.send(JSON.stringify({ tp: 'client', data: data }));
mediator.publish('on-operating-ssh'); //
} else {
//
// socket.current = null
// mediator.publish('create-socket', sid)
}
}
});
term.write('Connecting...');
setTerm(term);
const ro = onLayout(term, el.current);
return () => {
term.dispose();
ro.unobserve(el.current);
};
}
}, [ws_url, el.current]);
useEffect(() => {
if (term && ws_url) {
function createSocket() {
const socketInstance = new WebSocket(ws_url);
socket.current = socketInstance;
socketInstance.onopen = () => {
let container = term.element.parentElement;
if (container) {
let width = container.offsetWidth;
let height = container.offsetHeight;
console.log('init', {
tp: 'init',
data: {
...sshConfigData,
secret: secret,
width,
height,
rows: term.rows,
columns: term.cols,
},
});
socketInstance.send(
JSON.stringify({
tp: 'init',
data: {
...sshConfigData,
secret: secret,
width,
height,
rows: term.rows,
columns: term.cols,
},
}),
);
}
term.focus();
};
socketInstance.onerror = error => {
console.log(
'------in socket error----',
error,
socketInstance,
ws_url,
);
//
// mediator.publish('on-recreate-socket')
};
socketInstance.onmessage = event => {
if (!isFirstConnected.current) {
term.write('\r');
// term.focus()
setTimeout(() => {
// term.clear();
}, 1000);
}
isFirstConnected.current = true;
const data = Base64.decode(event.data.toString());
let w = term._core._renderService.dimensions.actualCellWidth || 9.5;
term.write(data);
};
socketInstance.onclose = evt => {
if (tid) {
clearInterval(tid);
}
term.write('\r\nconnection closed');
};
}
const tid = setInterval(() => {
if (socket.current) {
socket.current.send(JSON.stringify({ tp: 'h' }));
}
}, TimeTicket);
const unSubCreate = mediator.subscribe('create-socket', id => {
if (sid === id) {
if (socket.current && socket.current.readyState === 1) {
term.focus();
} else {
createSocket();
}
term.focus();
}
});
const unSubClose = mediator.subscribe('close-socket', id => {
if (sid === id) {
if (socket.current) {
socket.current.close();
isFirstConnected.current = false;
term.clear();
}
socket.current = null;
}
});
const unSubResize = mediator.subscribe('ssh-xterm-resize', option => {
if (socket.current && socket.current.readyState === 1) {
socket.current.send(
JSON.stringify({ tp: 'resize', data: { ...option } }),
);
}
});
const unSubAddTime = mediator.subscribe('ssh-add-connect-time', () => {
if (socket.current && socket.current.readyState === 1) {
socket.current.send(JSON.stringify({ tp: 'overtime' }));
}
});
return () => {
unSubClose();
unSubCreate();
unSubResize();
unSubAddTime();
if (socket.current) {
socket.current.close();
isFirstConnected.current = false;
}
};
}
}, [term, ws_url, port]);
return (
<div ref={el} className="xterm-panel" style={{height:"100%"}}>
{!ws_url ? <p style={{ color: '#fff' }}>正在连接命令行服务...</p> : null}
</div>
);
};

View File

@ -1,46 +0,0 @@
function Mediator(obj) {
const channels = {};
const mediator = {
subscribe: function(channel, cb) {
if (!channels[channel]) {
channels[channel] = [];
}
channels[channel].push(cb);
return this.unsubscribe.bind(null, channel, cb);
},
unsubscribe: function(channel, cb) {
let rs = channels[channel];
let index = -1;
if (rs) {
for (let i = 0; i < rs.length; i++) {
if (rs[i].name === cb.name) {
index = i;
break;
}
}
if (index >= 0) {
channels[channel].splice(index, 1);
return true;
}
}
return false;
},
publish: function(channel) {
if (!channels[channel]) {
return false;
}
const args = Array.prototype.slice.call(arguments, 1);
channels[channel].forEach(subscription => {
subscription.apply(null, args);
});
return this;
},
};
return obj ? Object.assign(obj, mediator) : mediator;
}
const mediator = new Mediator();
export default mediator;

View File

@ -41,15 +41,14 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
//
function onOk(){
validateFields((error,values)=>{
console.log(...values);
if(!error){
const url = `/${owner}/${repo}/applied_transfer_projects.json`;
Axios.post(url,{
...values
}).then(result=>{
if(result && result.data.id){
if(result){
onSuccess(result.data && result.data.owner);
}else{
onSuccess();
}
}).catch(error=>{})
}
@ -105,7 +104,7 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
</ul>
:
<ul className="descUl">
<li>仓库仅可以转移到您具有管理权限的组织中</li>
<li>仓库仅可以转移到您已经加入的组织中不可以转移到未加入的组织中</li>
<li>涉及到仓库改名操作请提前做好仓库备份并且在转移后对本地仓库的remote进行修改</li>
<li>转移仓库到组织后你和组织创建者/管理员同时拥有对该仓库的管理操作</li>
</ul>
@ -153,21 +152,20 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
</Form.Item>
}
<Form.Item label="仓库标识:" style={{marginBottom:"0px"}}>
<Form.Item label="仓库名称:">
{getFieldDecorator("identifier",
{
rules:[
{required:true,message:"请输入仓库标识!"},
{required:true,message:"请输入仓库名称"},
{
validator:checkIdentifier
}
]
}
)(
<Input placeholder="请输入仓库标识" autoComplete={"off"}/>
<Input placeholder="请输入仓库名称" autoComplete={"off"}/>
)}
</Form.Item>
<span className="color-grey-9" style={{marginLeft:"120px"}}>请输入当前项目的标识<span className="ml5 mr5 color-grey-3">{repo}</span>进行确认</span>
</Form>
</div>
</Modal>

View File

@ -1,12 +0,0 @@
.diverModal{
.descUl{
background-color: #fffae6;
border-radius: 4px;
padding:10px 15px;
color: #efc16b;
border:1px solid #efc16b;
}
.ant-form-item-required::before{
content: "";
}
}

View File

@ -1,85 +0,0 @@
import React, { useState , forwardRef, useEffect } from 'react';
import { Form , Modal , Input , Radio } from 'antd';
import Axios from 'axios';
import CheckProfile from '../Component/ProfileModal/Profile';
export default Form.create()(
forwardRef((props)=>{
const { getFieldDecorator, validateFields , setFieldsValue } = props && props.form;
const [ visible , setVisible ] = useState(false);
useEffect(()=>{
if(!visible){
setFieldsValue({
code:undefined,
role:"developer"
})
}
},[visible])
function onOk() {
validateFields((error,values)=>{
if(!error){
const url = `/applied_projects.json`;
Axios.post(url,{
applied_project:{
...values
}
}).then(result=>{
if(result && result.data){
setVisible(false);
props.showNotification("申请加入项目成功,等待审核!");
}
}).catch(error=>{})
}
})
}
function checkValue(rule, value, callback){
if(!value){
callback();
}
if(value.length < 6 || value.length > 6){
callback("请输入6位数的邀请码");
}
callback();
}
return(
<React.Fragment>
<Modal
title="加入项目"
width="480px"
visible={visible}
centered={true}
onOk={onOk}
onCancel={()=>setVisible(false)}
>
<Form layout={'inline'} className="inviteForm">
<Form.Item label="项目邀请码">
{getFieldDecorator("code",{
rules:[
{required:true,message:"请输入6位项目邀请码"},
{validator:checkValue}
]
})(
<Input placeholder="请输入6位项目邀请码" autoComplete={"off"} maxLength="6" style={{width:"300px"}}/>
)}
</Form.Item>
<Form.Item label="选择角色">
{getFieldDecorator("role",{
rules:[{required:true,message:"请选择角色"}]
})(
<Radio.Group defaultValue={"developer"}>
<Radio value="manager">管理员</Radio>
<Radio value="developer">开发者</Radio>
<Radio value="reporter">报告者</Radio>
</Radio.Group>
)}
</Form.Item>
</Form>
</Modal>
<CheckProfile {...props} sureFunc={()=>setVisible(true)}>加入项目</CheckProfile>
</React.Fragment>
)
})
)

View File

@ -1,108 +0,0 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Icon } from 'antd';
import _ from 'lodash';
import Nodata from '../Nodata';
class PullRefresh extends Component {
constructor(props) {
super(props);
this.state = {
}
this.pullRef = {};
//
this.onScrollList = _.throttle(this.handleScroll, 200, {
leading: false,
trailing: true,
});
}
componentDidMount() {
let dom = document.querySelector('.pull-refresh-wrap');
dom && dom.addEventListener('scroll', this.onScrollList);
}
componentWillUnmount() {
let dom = document.querySelector('.pull-refresh-wrap');
dom && dom.removeEventListener('scroll', this.onScrollList)
}
handleScroll = () => {
if (this.props.count < this.props.pageSize) return;
if (this.props.type === 1 || this.props.type === 2) return;
const wrap = this.pullRef;
const currentScroll = wrap.scrollTop + wrap.clientHeight
//
if (currentScroll >= (wrap.scrollHeight - 200)) {
this.loadData()
}
}
handleLoadClick = () => {
this.loadData();
}
loadData = () => {
this.props.onPullRefresh()
}
renderLoading() {
switch (this.props.type) {
case 0: //
return <div className='text-center' onClick={this.handleLoadClick}>显示更多</div>
case 1: //
return (
<div className='text-center'>
<Icon type="loading" />
<span className='text-center'>加载中...</span>
</div>
)
case 2: //
return <div className='text-center'>没有更多了</div>
default:
return <div className='text-center'>没有更多了</div>
}
}
render() {
const { className, count, children } = this.props;
return (
<div
className={`pull-refresh-wrap ${className}`}
ref={dom => { this.pullRef = dom }}
>
{children}
{
count < 1 && <Nodata _html="暂无未读消息"/>
}
{/* 大于分页数据才显示loading */}
{/* {this.props.count >= this.props.pageSize ? this.renderLoading() : null} */}
</div>
)
}
}
PullRefresh.propTypes = {
className: PropTypes.string,
children: PropTypes.any,
onPullRefresh: PropTypes.func.isRequired,
type: PropTypes.oneOf([0, 1, 2]),
count: PropTypes.number.isRequired,
pageSize: PropTypes.number.isRequired,
}
export default PullRefresh

View File

@ -19,7 +19,7 @@ function Footer(){
return(
<div>
<div style={{height:"543px"}}></div>
<div style={{height:"483px"}}></div>
<div className="newFooter edu-txt-center">
{value && showhtml(value)}
{/* <div className="footerInfos">

View File

@ -2,18 +2,15 @@ import React, { Component } from 'react';
import AccountProfile from "../../modules/user/AccountProfile";
import { getImageUrl } from 'educoder'
import axios from 'axios';
import { Input , notification , Dropdown ,Popover, Menu,Badge, Button } from 'antd';
import { Link } from 'react-router-dom';
import { Modal, Input, message, notification , Dropdown , Menu } from 'antd';
import LoginDialog from '../../modules/login/LoginDialog';
import HeadSearch from '../Component/HeadSearch';
import GotoQQgroup from '../../modal/GotoQQgroup'
import AddProjectModal from './AddProjectModal';
import '../../modules/tpm/TPMIndex.css';
import CheckProfile from '../Component/ProfileModal/Profile';
import logo from '../../modules/tpm/images/logo.png';
import './header.scss';
import NoticeContent from './NoticeContent';
const $ = window.$
// TODO 这部分脚本从公共脚本中直接调用
const { Search } = Input;
@ -36,9 +33,11 @@ class NewHeader extends Component {
Checkboxteachertype: false,
Checkboxteachingtype: false,
code_notice: false,
checked_notice: false,
RadioGroupvalue: undefined,
submitapplications: false,
isRender: false,
showSearchOpentype: false,
showTrial: false,
setevaluatinghides: false,
occupation: 0,
@ -46,12 +45,13 @@ class NewHeader extends Component {
headtypesonClickbool: false,
headtypess: "/",
settings: null,
goshowqqgtounp: false,
visiblemyss: false,
openSearch:false,
visible:false, //浮动消息框展示控制
}
}
componentDidMount() {
// this.getAppdata();
this.geturlsdata();
window._header_componentHandler = this;
@ -82,6 +82,36 @@ class NewHeader extends Component {
} catch (e) {}
}
SearchInput = (open,item)=>{
if(open){
return(
<div
onBlur={() => {
setTimeout(() => {
this.setState({
openSearch:false
})
}, 300)
}}
>
<Search placeholder="实践课程/教学课堂/实践项目/交流问答"
className={`search-input mr20`}
onSearch={(value)=>this.onGlobalSearch(value,item)}
autoFocus={true}
/>
</div>
)
}else{
return <i className="iconfont icon-sousuo font-18 color-white ml30" onClick={() => {
this.setState({openSearch:true})
}} />
}
}
onGlobalSearch=(value,item)=>{
window.location.href=`${item}?value=` + value;
}
openNotification = (messge) => {
notification.open({
message: "提示",
@ -90,12 +120,168 @@ class NewHeader extends Component {
});
};
componentWillReceiveProps(newProps, oldProps) {
this.setState({
user: newProps.user
})
if (newProps.Headertop !== undefined) {
old_url = newProps.Headertop.old_url
}
}
getCookie = (key) => {
var arr, reg = RegExp('(^| )' + key + '=([^;]+)(;|$)');
if (arr === document.cookie.match(reg))
return decodeURIComponent(arr[2]);
else
return null;
}
delCookie = (name) => {
var exp = new Date();
exp.setTime(exp.getTime() - 1);
var cval = this.getCookie(name);
if (cval != null) {
document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString();
}
}
onLogout = () => {
const url = `/accounts/logout.json`
this.delCookie("autologin_trustie")
axios.get(url, {
}).then((response) => {
if (response.data.status === 1) {
this.setState({
user: undefined
})
window.location.href = "/login"
message.success('退出成功');
}
});
}
tojoinclass = () => {
let { user } = this.state;
if (user === undefined) {
this.setState({
isRender: true
})
return
}
if (user && user.login === "") {
this.setState({
isRender: true
})
return;
}
if (user && user.profile_completed === false) {
this.setState({
AccountProfiletype: true
})
return;
}
this.setState({
Addcoursestypes: true,
})
}
tojoinitem = () => {
if (this.props.user && this.props.user.email === undefined || this.props.user && this.props.user.email === null || this.props.user && this.props.user.email === "") {
this.openNotification("请先绑定邮箱,谢谢");
return
}
let { user } = this.state;
if (user === undefined) {
this.setState({
isRender: true
})
return
}
if (user && user.login === "") {
this.setState({
isRender: true
})
return;
}
if (user && user.profile_completed === false) {
this.setState({
AccountProfiletype: true
})
return;
}
this.setState({
tojoinitemtype: true
})
}
submitstatevalue = (sum, value, data) => {
this.setState({
Addcoursestypes: false,
tojoinitemtype: false,
tojoinclasstitle: undefined,
rolearr: ["", ""],
Checkboxteacherchecked: false,
Checkboxstudentchecked: false,
Checkboxteachingchecked: false,
Checkboxteachertype: false,
Checkboxteachingtype: false,
code_notice: false,
checked_notice: false,
submitapplicationssum: sum,
submitapplications: true,
submitapplicationsvalue: value,
submitapplicationsvaluedata: data,
RadioGroupvalue: undefined
})
}
onChangeRadioGroup = (e) => {
this.setState({
RadioGroupvalue: e.target.value,
});
}
submitsubmitapplications = () => {
let {
submitapplicationssum,
submitapplicationsvaluedata
} = this.state;
this.setState({
submitapplications: false,
RadioGroupvalue: undefined
})
if (submitapplicationssum === 0) {
if (submitapplicationsvaluedata !== undefined) {
window.location.href = "/courses/" + submitapplicationsvaluedata;
}
} else if (submitapplicationssum === 1) {
if (submitapplicationsvaluedata !== undefined) {
window.location.href = "/projects/" + submitapplicationsvaluedata;
}
}
}
hidesubmitapplications = () => {
this.setState({
Addcoursestypes: false,
tojoinitemtype: false,
tojoinclasstitle: undefined,
rolearr: ["", ""],
Checkboxteacherchecked: false,
Checkboxstudentchecked: false,
Checkboxteachingchecked: false,
Checkboxteachertype: false,
Checkboxteachingtype: false,
code_notice: false,
checked_notice: false,
submitapplications: false,
RadioGroupvalue: undefined
})
}
educoderlogin = () => {
//登录账号
this.setState({
@ -120,6 +306,7 @@ class NewHeader extends Component {
})
};
HideAddcoursestypess = (i) => {
console.log("调用了");
this.setState({
Addcoursestypes: false,
mydisplay: true,
@ -132,11 +319,30 @@ class NewHeader extends Component {
})
};
hidetojoinclass = () => {
this.setState({
tojoinclasstype: false,
tojoinitemtype: false,
tojoinclasstitle: undefined,
rolearr: ["", ""],
Checkboxteacherchecked: false,
Checkboxstudentchecked: false,
Checkboxteachingchecked: false,
Checkboxteachertype: false,
Checkboxteachingtype: false,
code_notice: false,
checked_notice: false,
RadioGroupvalue: undefined
})
}
// 关闭
cancelModulationModels = () => {
this.setState({ isRenders: false })
}
setevaluatinghides = () => {
this.setState({
setevaluatinghides: true
@ -196,13 +402,39 @@ class NewHeader extends Component {
})
}
getAppdata = () => {
try {
var chromesettingArray = JSON.parse(localStorage.getItem('chromesetting'));
var chromesettingresponseArray = JSON.parse(localStorage.getItem('chromesettingresponse'));
this.setState({
settings: chromesettingArray
});
if (chromesettingArray.tab_logo_url) {
this.gettablogourldata(chromesettingresponseArray);
} else {
this.gettablogourlnull();
}
} catch (e) {
this.geturlsdata();
}
};
geturlsdata = () => {
let url = "/setting.json";
axios.get(url).then((response) => {
if (response && response.data) {
this.setState({ settings: response.data.setting });
localStorage.setItem('chromesetting', JSON.stringify(response.data.setting));
localStorage.setItem('chromesettingresponse', JSON.stringify(response));
// localStorage.setItem('chromesetting', JSON.stringify(response.data.setting));
// localStorage.setItem('chromesettingresponse', JSON.stringify(response));
try {
if (response.data.setting.tab_logo_url) {
this.gettablogourldata(response);
} else {
this.gettablogourlnull();
}
} catch (e) {
this.gettablogourlnull();
}
} else {
this.gettablogourlnull();
}
@ -221,14 +453,13 @@ class NewHeader extends Component {
}
}
}
checkProfile=(url)=>{
const { showCompeleteDialog , completeProfile } = this.props;
if(!completeProfile){
showCompeleteDialog && showCompeleteDialog();
}else{
window.location.href(url);
}
// 处理弹框
setgoshowqqgtounp = (bool) => {
this.setState({
goshowqqgtounp: bool
})
}
addMenu=(list)=>{
@ -239,56 +470,34 @@ class NewHeader extends Component {
{
list.map((item,key)=>{
return(
(item.name !=="加入课堂" && item.name !=="加入开发项目") &&
<Menu.Item key={item.name+key}>
<CheckProfile {...this.props} sureFunc={()=>{window.location.href=item.url}}>{item.name}</CheckProfile>
</Menu.Item>
(item.name !=="加入课堂" && item.name !=="加入开发项目") && <Menu.Item><a href={item.url}>{item.name}</a></Menu.Item>
)
})
}
<Menu.Item>
<AddProjectModal {...this.props} showNotification={this.props.showNotification}/>
</Menu.Item>
</Menu>
</div>
)
}
renderMenu=(personal)=>{
const { current_user } = this.props;
return(
<Menu className="currentMenu">
<Menu.Item>
<span className="currentName" title={current_user && current_user.username}>{current_user && current_user.username}</span>
</Menu.Item>
{
personal && personal.length > 0 && personal.map((item,key)=>{
return(
<li key={key}><a href={item.url} target="_blank">{item.name}</a></li>
)
})
}
{/* <li><Link to={`/settings/profile`}>设置</Link></li> */}
<Menu.Item><a onClick={() => this.educoderloginysl()}>退出</a></Menu.Item>
</Menu>
)
}
handleVisibleChange = visible => {
this.setState({ visible });
};
render() {
const { match ,resetUserInfo ,showNotification} = this.props;
const { match} = this.props;
let current_user = this.props.user;
let {
let { Addcoursestypes,
tojoinitemtype,
tojoinclasstitle,
code_notice,
checked_notice,
AccountProfiletype,
submitapplications,
submitapplicationsvalue,
user,
isRender,
showSearchOpentype,
headtypesonClickbool,
headtypess,
settings,
visible,
goshowqqgtounp,
openSearch,
} = this.state;
/*用户名称 用户头像url*/
let activeIndex = false;
@ -346,7 +555,7 @@ class NewHeader extends Component {
let shixun = "/shixuns";
let paths = "/paths";
let courses = "/courses";
this.props.mygetHelmetapi && this.props.mygetHelmetapi.navbar && this.props.mygetHelmetapi.navbar.map((item, key) => {
this.props.mygetHelmetapi.navbar.map((item, key) => {
var reg = RegExp(item.link);
if (shixun.match(reg)) {
if (item.hidden === true) {
@ -367,6 +576,7 @@ class NewHeader extends Component {
}
let search_url = settings && settings.common && settings.common.search;
let notice_url = settings && settings.common && settings.common.notice;
return (
<div className="newHeaders" id="nHeader">
<div className="headerContent">
@ -383,14 +593,19 @@ class NewHeader extends Component {
{...this.props}
{...this.state}
/> : ""}
{
settings && settings.nav_logo_url ?
<a href={settings && settings.new_course.default_url} className={"fl mr50"} style={{minWidth:"45px"}}>
<img alt="可控开源社区" className="logoimg" style={{ heigth: "40px" }} src={getImageUrl(`/${settings.nav_logo_url}`)}></img>
</a>
:
""
}
{
goshowqqgtounp === true ?
<GotoQQgroup {...this.state} {...this.props} setgoshowqqgtounp={(bool) => this.setgoshowqqgtounp(bool)}></GotoQQgroup>
:""
}
{
settings && settings.nav_logo_url ?
<a href={settings && settings.new_course.default_url} className={"fl mr30"} style={{minWidth:"45px"}}>
<img alt="可控开源社区" className="logoimg" style={{ heigth: "40px" }} src={getImageUrl(`/${settings.nav_logo_url}`)}></img>
</a>
:
""
}
<div className="head-nav pr" id={"head-navpre1"}>
{
settings && settings.navbar && settings.navbar.length > 0 ?
@ -398,21 +613,21 @@ class NewHeader extends Component {
{
settings.navbar && settings.navbar.map((item, key) => {
var new_link = item.link;
var user_login = current_user && current_user.login;
var user_login = this.props.user && this.props.user.login;
var is_hidden = item.hidden
if (new_link && (new_link.indexOf("courses") > -1 || new_link.indexOf("contests") > -1)) {
if (user_login) {
if (new_link.indexOf("courses") > -1) {
new_link = new_link.replace(/courses/g, user_login + "/courses")
new_link = new_link.replace(/courses/g, "users/" + user_login + "/courses")
} else if (new_link.indexOf("contests") > -1) {
new_link = new_link.replace(/contests/g, user_login + "/contests")
new_link = new_link.replace(/contests/g, "users/" + user_login + "/contests")
}
} else {
is_hidden = true
}
}
if (user_login && (new_link && new_link.indexOf("homes") > -1)) {
new_link = new_link.replace(/homes/g, user_login + "/user_activities")
new_link = new_link.replace(/homes/g, "users/" + user_login + "/user_activities")
}
var waiLian = (new_link && str.filter(item=>new_link.indexOf(item)>-1) );
@ -429,46 +644,80 @@ class NewHeader extends Component {
}
</div>
<div className="head-right">
{ search_url && <HeadSearch {...this.props}/>}
{search_url ? this.SearchInput(openSearch,search_url):""}
{
current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)?
<Dropdown overlay={this.addMenu(settings && settings.add)} placement="bottomRight">
<i className="iconfont icon-tianjiafangda color-grey-6 ml30 mr15"></i>
<i className="iconfont icon-tianjiafangda color-white ml30"></i>
</Dropdown>:""
}
{ (settings && settings.common && settings.common.notice) && (current_user && current_user.login)?
<Popover
overlayClassName="notice-popover"
placement={`bottomRight`}
content={<NoticeContent visible={visible} current_user={current_user} showNotification={showNotification} resetUserInfo={resetUserInfo}/>}
visible={visible}
onVisibleChange={this.handleVisibleChange}
destroyTooltipOnHide
>
<Link to={"/settings/notice"} className="message-icon">
{current_user && <Badge count={current_user.message_unread_total}>
<i className="iconfont icon-xiaoxilingdang color-grey-6 ml15 mr15"></i>
</Badge>}
</Link>
</Popover>
: ""
{this.props.user && this.props.user.login && notice_url ?
<div className="ml30 edu-menu-panel">
{user && user.login &&
<a href={`${notice_url}`} style={{ position: 'relative' }}>
<i className="iconfont icon-xiaoxilingdang color-white"></i>
<span className="newslight" style={{ display: this.props.Headertop === undefined ? "none" : this.props.Headertop.new_message === true ? "block" : "none" }}>
</span>
</a>
}
</div>:""
}
<Modal
keyboard={false}
title="提示"
visible={submitapplications}
closable={false}
footer={null}
>
<div className="task_popup_con ml30">
<div className="mr15">
<ul>
<div className="task-popup-content">
<p className="task-popup-text-center font-16">
{submitapplicationsvalue}
</p>
</div>
<li className="clearfix mt10 edu-txt-center">
<a className="task-btn mr10"
onClick={this.hidesubmitapplications}>取消</a>
<a
className="task-btn task-btn-orange ml20"
onClick={this.submitsubmitapplications}>确定</a>
</li>
</ul>
</div>
</div>
</Modal>
</div>
{!user || (user && !user.login) ?
<span className="font-15 ml30">
<a onClick={() => this.educoderlogin()} className="mr5 color-grey-6">登录</a>
<a onClick={() => this.educoderlogin()} className="mr5 color-white">登录</a>
{
settings && settings.common && settings.common.register &&
<span><em className="vertical-line"></em><a className="ml5 color-grey-6" href={`${settings.common.register}`} target="_blank"></a></span>
<span><em className="vertical-line"></em><a className="ml5 color-white" href={`${settings.common.register}`} target="_blank"></a></span>
}
</span>
:
<Dropdown placement={`bottomRight`} overlay={this.renderMenu(settings && settings.personal)}>
<a href={`/${this.props.current_user && this.props.current_user.login}`}>
<img alt="头像" src={getImageUrl(`/${user.image_url}`)} className="currentImg"></img>
<div className="ml30 edu-menu-panel" style={{ height: "70px", lineHeight: "70px" }}>
<a href={`/users/${this.props.current_user === undefined ? "" : this.props.current_user.login}/courses`}>
<img alt="头像" className="radius" height="34" id="nh_user_logo" name="avatar_image" src={getImageUrl(`/${user.image_url}`)} width="34">
</img>
</a>
</Dropdown>
<ul className="edu-menu-list" style={{ top: '60px', textAlign: 'center' }}>
<li className="bor-bottom-greyE" style={{cursor:"default",background:"#fff"}}>{this.props.current_user.username}</li>
{
settings && settings.personal && settings.personal.length > 0 && settings.personal.map((item,key)=>{
return(
<li key={key}><a href={item.url} target="_blank">{item.name}</a></li>
)
})
}
<li className="bor-top-greyE">
<a onClick={() => this.educoderloginysl()}>退出</a>
</li>
</ul>
</div>
}
</div>
</div>

View File

@ -1,262 +0,0 @@
import React, { useEffect, useState } from 'react';
import { Badge, Menu } from 'antd';
import { Link } from 'react-router-dom';
import axios from 'axios';
import AppPullRefresh from './AppPullRefresh';
import { noticeSourceType } from '../common/static';
import './header.scss';
import '../SecuritySetting/notice/manager/Index.scss';
import '../SecuritySetting/Index.scss';
import '../SecuritySetting/notice/myNotice/Index.scss';
function NoticeContent({ visible, showNotification, resetUserInfo, current_user: { login } }) {
const [initialize, setInitialize] = useState(true);
const [noticeType, setNoticeType] = useState("notification");
const [letterUnreadCount, setLetterUnreadCount] = useState(0);//
const [noticeUnreadCount, setNoticeUnreadCount] = useState(0);//
const [noticePage, setNoticePage] = useState(0);
const [noticeUnreadList, setNoticeUnreadList] = useState([]);//
const [atUnreadCount, setAtUnreadCount] = useState();//@
const [atPage, setAtPage] = useState(0);
const [atUnreadList, setAtUnreadList] = useState([]);//@
useEffect(() => {
resetUserInfo();
}, [noticeUnreadCount,atUnreadCount]);
useEffect(()=>{
setNoticePage(0);
setAtPage(0);
},[visible])
useEffect(() => {
const params = {
type: noticeType,
limit: 10,
page: noticeType === "notification" ? noticePage : noticeType === "atme" ? atPage : "",
status: 1,
}
getMessageList(params);
}, [noticePage, atPage]);
useEffect(() => {
const params = {
type: noticeType,
limit: 10,
page: 0,
status: 1,
};
if (initialize) {
params.type = "atme"
}
visible && getMessageList(params);
}, [visible]);
function getMessageList(params) {
axios.get(`/users/${login}/messages.json`, {
params: params,
}).then((response) => {
if (response && response.data) {
setNoticeUnreadCount(response.data.unread_notification);
setAtUnreadCount(response.data.unread_atme);
if (params.type === "notification") {
let list = response.data.messages;
if (params.page !== 0) {
list = [...noticeUnreadList, ...list];
}
setNoticeUnreadList(list);
if (initialize) {
// tab
setInitialize(false);
if (response.data.unread_notification === 0 && response.data.unread_atme !== 0) {
setNoticeType("atme");
}
}
} else if (params.type === "atme") {
let list = response.data.messages;
if (params.page !== 0) {
list = [...atUnreadList, ...list];
}
setAtUnreadList(list);
}
}
})
}
function readAll() {
axios.post(`/users/${login}/messages/read.json`, {
type: noticeType,
ids: [-1]
}).then((response) => {
let data = response.data;
if (!data) return;
if (data.status === 0) {
changeReadMarkAll(noticeType);
} else {
showNotification(data.message);
}
});
}
function changeReadMarkAll(noticeType) {
if (noticeType === "notification") {
let list = noticeUnreadList.slice();
list.forEach(item => {
item.status = 2;
})
setNoticeUnreadList(list);
setNoticeUnreadCount(0);
} else if (noticeType === "atme") {
let list = atUnreadList.slice();
list.forEach(item => {
item.status = 2;
})
setAtUnreadList(list);
setAtUnreadCount(0);
}
}
// const [letter_unread_list, setLetter_unread_list] = useState([
// {
// id: 122,
// read: 0, //01
// send_name: "", //
// send_login: "jiangYuHang", //login
// content: "", //
// create_time: "2019-03-04 18:08", //
// },
// ]);
function readItem(item) {
axios.post(`/users/${login}/messages/read.json`, {
type: noticeType,
ids: [item.id]
}).then((response) => {
let data = response.data;
if (!data) return;
if (data.status === 0) {
changeReadMark(item);
item.notification_url && window.open(item.notification_url);
} else {
showNotification(data.message);
}
});
}
function changeReadMark(item) {
if (item.type === "notification") {
let list = noticeUnreadList.slice();
let index = noticeUnreadList.indexOf(item);
list[index].status = 2;
setNoticeUnreadList(list);
if (noticeUnreadCount > 0) {
setNoticeUnreadCount(noticeUnreadCount - 1);
}
} else if (item.type === "atme") {
let list = atUnreadList.slice();
let index = atUnreadList.indexOf(item);
list[index].status = 2;
setAtUnreadList(list);
if (atUnreadCount > 0) {
setAtUnreadCount(atUnreadCount - 1);
}
}
}
return (
<div className="messageHoverDiv notice01">
<div className="sshHead hoverNotice-head">
<Menu mode="horizontal" selectedKeys={noticeType} onClick={(e) => setNoticeType(e.key)}>
<Menu.Item key="notification"><Badge count={noticeUnreadCount}>系统通知</Badge></Menu.Item>
{/* <Menu.Item key="1" id="item-private"><Badge count={letterUnreadCount}>私信</Badge></Menu.Item> */}
<Menu.Item key="atme"><Badge count={atUnreadCount}>@</Badge></Menu.Item>
</Menu>
</div>
{/* 系统通知 */}
{noticeType === "notification" && <AppPullRefresh
className='hoverNotice-body' // className
onPullRefresh={() => { setNoticePage(noticePage + 1); }} //ajaxfunction
// type={2} //
count={noticeUnreadList.length} //
pageSize={10} //
>
{
noticeUnreadList.map(item => {
return (
<div key={item.id + Math.random()} className="noticeCont-back" onClick={() => { readItem(item) }}>
<div className={`noticeCont ${item.notification_url?'pointer':''}`}>
<span style={{ visibility: item.status === 1 ? 'visible' : 'hidden' }}>
<Badge color="#FA2020" />
</span>
<i className={"iconfont " + noticeSourceType[item.source]}></i>
<div className="noticeCont-text">
<span className="content-span notice-cont-span" dangerouslySetInnerHTML={{ __html: item.content }}></span>
<span className="timeSpan">{item.time_ago}</span>
</div>
</div>
</div>
)
})
}
</AppPullRefresh>
}
{/* @我 */}
{noticeType === "atme" && <AppPullRefresh
className='hoverNotice-body' // className
onPullRefresh={() => { setAtPage(atPage + 1); }} //ajaxfunction
// type={1} //
count={atUnreadList.length} //
pageSize={10} //
>
{atUnreadList.map(item => {
return (
<div key={item.id + Math.random()} className="noticeCont-back" onClick={() => { readItem(item) }}>
<div className="noticeCont">
<span style={{ visibility: item.status === 1 ? 'visible' : 'hidden' }}>
<Badge color="#FA2020" />
</span>
<div className="noticeCont-text">
<span className="content-span atme-cont-span" dangerouslySetInnerHTML={{ __html: "<b>" + (item.sender ? item.sender.name : '') + "</b>&nbsp;&nbsp;&nbsp;" + item.content + " 中@我" }}></span>
<span className="timeSpan">{item.time_ago}</span>
</div>
</div>
</div>
)
})
}
</AppPullRefresh>
}
{/* 私信 */}
{/* {noticeType === "1" ? letter_unread_list.length > 0 ? letter_unread_list.map(item => {
return (
<div className="noticeCont-back">
<div className="noticeCont" style={{ height: item.content.length >= 30 && item.content.length <= 34 ? '65px' : "" }}>
<Badge color="#FA2020" />
<div className="noticeCont-text">
<span>{item.send_name}</span>
<span className="boldSpan" dangerouslySetInnerHTML={{ __html: item.content.length >= 50 ? item.content.substr(0, 50) + "..." : item.content }}></span>
<span className="timeSpan">{item.create_time ? timeAgo(item.create_time) : "刚刚"}</span>
</div>
</div>
</div>
)
}) : "暂无数据" : ""} */}
<div className="hoverNotice-buttom">
<Link to={{pathname:"/settings/notice",query:{noticeType:noticeType}}}>全部消息</Link>
{noticeUnreadCount > 0 && noticeType === "notification" && <a onClick={readAll}>所有系统消息一键已读</a>}
{atUnreadCount > 0 && noticeType === "atme" && <a onClick={readAll}>所有@我一键已读</a>}
</div>
</div>
)
}
export default NoticeContent;

View File

@ -1,6 +1,7 @@
.dropdownFlex{
display:flex;
padding:5px;
background:#fff;
border-radius: 3px;
.ant-menu-vertical > .ant-menu-item{
@ -8,65 +9,11 @@
height: 35px;
line-height: 35px;
margin:0px;
&.ant-menu-item-selected{
background-color: #fff;
a{color: rgba(0, 0, 0, 0.65)!important;}
}
&.ant-menu-item-active{
a{color: #4cacff!important;}
}
}
.ant-menu-vertical{
border:none;
}
}
.currentImg{
width: 34px;
height: 34px;
border-radius: 50%;
margin-left: 15px;
}
.currentMenu{
width: 120px;
text-align: center;
padding:0px;
.currentName{
padding:0px 8px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: block;
}
li{
height: 40px;
line-height: 40px;
padding:0px!important;
cursor: default;
&:hover{
background-color: #fff;
}
&:first-child{
border-bottom: 1px solid #eee;
}
&:last-child{
border-top: 1px solid #eee;
a{
border-radius: 0px 0px 4px 4px;
}
}
a{
padding:0px;
margin:0px;
display: block;
color: #666;
&:hover{
color: #fff;
background: #4CACFF;
}
}
}
}
.newFooter {
position: absolute;
@ -118,148 +65,4 @@
}
}
}
}
.inviteForm{
.ant-form-item{
margin-right: 0px;
}
.ant-form-item-label{
width: 110px;
text-align: right;
}
}
// 右上角小铃铛单独样式
.notice-popover{
//popover小尖尖
.ant-popover-arrow{
display: none;
}
//popover框
.ant-popover-inner-content {
width: 386px;
height: 446px;
box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5);
border-radius: 4px;
margin-top: -10px;
padding: 12px 1px 12px 0;
}
}
.messageHoverDiv .ant-menu-item{
margin-right: 24px !important;
}
.hoverNotice-head{
margin-left: 18px;
& .ant-badge{
font-size: 14px !important;
}
&>.ant-menu-horizontal {
border-bottom: 1px solid #e8e8e8 !important;
}
}
.hoverNotice-body{
height: 342px;
overflow-y: scroll;
& b{
font-weight: 400;
text-shadow: 0.5px 0 0 #333;
}
.none_panels{
height: 100%;
}
}
.message-icon{
position: relative;
.ant-scroll-number{
right:12px;
padding: 0 0px;
}
}
.hoverNotice-buttom{
display: flex;
justify-content: space-between;
padding: 12px 18px;
a{
color: #466AFF;
&:hover{
opacity:0.85;
}
}
}
.noticeCont-back{
.pointer{
cursor: pointer;
}
&:hover{
background: #F3F4F6;
}
}
.noticeCont{
display: flex;
margin: 0 16px 0 18px;
padding: 12px 0 10px 0;
line-height: 24px;
border-bottom: 1px solid #EEEEEE;
cursor: default;
i{
font-size: 14px !important;
margin-right: 6px;
color: #333333;
}
.boldSpan{
font-weight: 400;
text-shadow: 0.5px 0 0 #333;
}
.noticeCont-text{
display: flex;
color:#333333;
flex:auto;
justify-content: space-between;
& .content-span{
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
& .atme-cont-span{
width: 272px;
}
& .notice-cont-span{
width: 255px;
}
.timeSpan{
font-size: 12px;
color: #666666;
}
.at-name{
margin-right: 12px;
}
}
}
.text-center{
text-align: center;
}

View File

@ -12,9 +12,8 @@ import Loadable from "react-loadable";
import Loading from "../Loading";
import { ImageLayerOfCommentHOC } from "../modules/page/layers/ImageLayerOfCommentHOC";
const ProjectNew = Loadable({
loader: () => import("./New/Index"),
loader: () => import("./New/Index"),
loading: Loading,
});
const ProjectIndex = Loadable({
@ -22,23 +21,17 @@ const ProjectIndex = Loadable({
loading: Loading,
});
// 项目详情放在用户和组织下作为二级菜单存在
// const ProjectDetail = Loadable({
// loader: () => import("./Main/Detail"),
// loading: Loading,
// });
const ProjectDetail = Loadable({
loader: () => import("./Main/Detail"),
loading: Loading,
});
const Infos = Loadable({
loader: () => import("./users/Infos"),
loading: Loading,
});
class Index extends Component {
componentDidUpdate = () => {
this.props.history.listen(() => {
if (document.body.scrollTop || document.documentElement.scrollTop > 0) {
window.scrollTo(0, 0)
}
})
}
render() {
return (
<div className="newMain clearfix">
<Switch {...this.props}>
@ -55,27 +48,30 @@ class Index extends Component {
)}
></Route>
<Route
path="/projects/mirror/new"
path="/projects/new"
render={(props) => (
<ProjectNew {...this.props} {...props} />
)}
></Route>
{/* <Route
path="/:owner/:projectsId"
<Route
path="/projects/:owner/:projectsId"
render={(props) => (
<ProjectDetail {...this.props} {...props} />
)}
></Route> */}
></Route>
<Route
path="/explore"
path="/projects"
render={(props) => (
<ProjectIndex {...this.props} {...props} />
)}
></Route>
<Route
exact
path="/"
render={(props) => (
this.props.current_user && this.props.current_user.login ?
<Infos {...this.props} {...props} />
:
<ProjectIndex {...this.props} {...props} />
)}
></Route>
@ -90,10 +86,3 @@ export default withRouter(
parentSelector: ".newMain",
})(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(Index))))
);
// export default withRouter(
// ImageLayerOfCommentHOC({
// imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget",
// parentSelector: ".newMain",
// })(Index)
// );

View File

@ -1,9 +1,8 @@
import React , { useEffect , useState } from 'react';
import { WhiteBack , Box , LongWidth , ShortWidth , Gap , AlignCenter , FlexAJ } from '../Component/layout';
import { Dropdown , Menu , Divider , Spin, Button , Typography } from 'antd';
import { Dropdown , Menu , Divider , Spin, Button } from 'antd';
import { getImageUrl } from "educoder";
import { Link } from 'react-router-dom';
import { truncateCommitId } from "../common/util";
import CloneAddress from '../Branch/CloneAddress';
import SelectBranch from '../Branch/Select';
@ -20,30 +19,12 @@ import LanguagePower from '../Component/LanguagePower';
import DrawerPanel from '../Component/DrawerPanel';
import UpdateDescModal from './sub/UpdateDescModal';
import Nodata from '../Nodata';
import Invite from './sub/Invite';
import CheckProfile from '../Component/ProfileModal/Profile';
import RenderHtml from '../../components/render-html';
import Badge from "./sub/Badge";
/**
* projectDetail.type:0是托管项目1是镜像项目2是同步镜像项目(为2时不支持在线创建在线上传在线修改在线删除创建合并请求等功能)
*/
const { Paragraph } = Typography;
function turnbar(str){
if(str && str.length>0 && str.indexOf("/")>-1){
return str.replaceAll('/','%2F');
}
return str;
}
function returnbar(str){
if(str && str.length>0 && str.indexOf("%2F")>-1){
return str.replaceAll('%2F','/');
}
return str;
}
function CoderDepot(props){
const [ projectDetail , setProjectDetail ]= useState(undefined);
const [ inviteCode , setInviteCode ] = useState(undefined);
const [ treeValue , setTreeValue ] = useState(undefined);
const [ treeValuePath , setTreeValuePath ] = useState(undefined);
const [ lastCommit,setLastCommit ] = useState(undefined);
@ -64,53 +45,19 @@ function CoderDepot(props){
const [ desc , setDesc ] = useState(undefined);
const [ website , setWebsite ] = useState(undefined);
const [ lesson_url , setLessonUrl ] = useState(undefined);
const [ readme , setReadme ] = useState(undefined);
const [ defaultBranch , setDefaultBranch ] = useState(undefined);
const [ editReadme , setEditReadme ] = useState(false);
const [ pullsFlag , setPullsFlag ] = useState(true);
const [ issuesFlag , setIssuesFlag ] = useState(true);
const [ releaseVersions , setReleaseVersions] = useState(undefined);
const owner = props.match.params.owner;
const projectsId = props.match.params.projectsId;
let branchName = props.match.params.branchName;
branchName = returnbar(branchName);
const details = props.projectDetail;
const branchName = props.match.params.branchName;
let pathname = props.history.location.pathname;
//distribution
const distribution = details && details.type != 2 && (details.permission === "Admin" || details.permission === "Owner" || details.permission === "Manager");
const { bannerList } = props;
// test data
const badges = {badge:[{ "login": "many_stars", "image_url": "https://www.gitlink.org.cn/system/lets/letter_avatars/2/J/236_194_58/120.png", "description": "test description1"}, {"login": "many_stars", "image_url": "https://www.gitlink.org.cn/system/lets/letter_avatars/2/X/181_166_38/120.png", "description": "test description2"}], total_count: 3}
console.log(badges.badge)
console.log(badges.total_count)
useEffect(()=>{
if(bannerList && bannerList.length>0){
let a = bannerList.filter(i=>i.menu_name === "pulls");
let i = bannerList.filter(i=>i.menu_name === "issues");
if(a && a.length === 0){
setPullsFlag(false);
}
if(i && i.length === 0){
setIssuesFlag(false);
}
if(props.projectDetail){
setProjectDetail(props.projectDetail);
setDesc(props.projectDetail.description);
setWebsite(props.projectDetail.website);
setLessonUrl(props.projectDetail.lesson_url);
}
},[bannerList])
useEffect(()=>{
if(details){
setProjectDetail(details);
setDesc(details.description);
setWebsite(details.website);
setLessonUrl(details.lesson_url);
setDefaultBranch(details.default_branch);
setInviteCode(details.invite_code);
}
},[details])
},[props])
useEffect(()=>{
if(treeValue){
@ -120,61 +67,23 @@ function CoderDepot(props){
}
},[treeValue])
useEffect(()=>{
if (projectsId && owner && defaultBranch){
let b = turnbar(branchName) ;
if(pathname.indexOf(`/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${b}/`) > -1) {
let url = pathname.split(`/tree/${b}/`)[1];
if (pathname && projectDetail){
if(pathname.indexOf(`/projects/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${branchName}/`) > -1) {
let url = pathname.split(`/tree/${branchName}/`)[1];
setTreeValue(url);
getFileInfo(url,branchName);
setType("file");
// getReadmeInfo(url,branchName);
// setReadme(undefined);
}else{
setTreeValue(undefined);
getDirInfo(branchName || defaultBranch);
setType("dir");
// getReadmeInfo('', branchName || defaultBranch);
getDirInfo(branchName ||projectDetail.default_branch);
}
}
},[projectsId,owner,pathname,defaultBranch])
useEffect(()=>{
axios.get(`/${owner}/${projectsId}/releases.json`).then((result)=>{
if(result && result.data){
const release = {
"list":result.data.releases,
"total_count":result.data.releases.length
}
setReleaseVersions(release);
}
})
},[])
// readme
function getReadmeInfo(path, ref) {
axios.get(`/${owner}/${projectsId}/readme.json`, {
params:{
owner: owner,
repo: projectsId,
filepath:path,
ref:ref || branchName
}
}).then((result) => {
if (result) {
setReadme(result.data);
} else {
setReadme(undefined);
}
})
}
},[pathname,projectDetail])
//
function getDirInfo(branch){
setIsSpin(true);
const url = `/${owner}/${projectsId}/entries.json`;
axios.get(url, {
params: { ref: branch }
}).then((result) => {
@ -189,10 +98,6 @@ function CoderDepot(props){
setLastCommitAuthor(c && c.committer);
setMainFlag(true);
setReadOnly(true);
// setReadme(result.data.readme);
setEditReadme(false);
setHide(true);
getReadmeInfo('', branchName || defaultBranch);
}
setTimeout(function(){setIsSpin(false);},500);
}).catch(error=>{setIsSpin(false);})
@ -204,7 +109,7 @@ function CoderDepot(props){
let ele = document.getElementById("ptxt");
if(ele){
let h = ele.offsetHeight;
if( h > 35 ) setHideBtn(true);
if( h > 18 ) setHideBtn(true)
}
}
},[projectDetail,lastCommit])
@ -225,20 +130,16 @@ function CoderDepot(props){
setDirInfo(undefined);
setFileInfo(en);
setType(en.type);
setReadme(undefined);
}else{
setFileInfo(undefined);
setDirInfo(en);
setType("dir");
getReadmeInfo(path, branchName || defaultBranch);
}
let c = result.data.last_commit
setLastCommit(c && c.commit);
setLastCommitAuthor(c && c.committer);
setMainFlag(false);
setReadOnly(true);
setReadOnly(!editReadme);
setHide(true);
}
setTimeout(function(){setIsSpin(false);},500)
}).catch(error=>{setIsSpin(false);})
@ -246,26 +147,17 @@ function CoderDepot(props){
//
function changeBranch(value){
let checkvalue = turnbar(value);
let url = `/${owner}/${projectsId}${value && `/tree/${checkvalue}`}${treeValue ? `/${treeValue}`:""}`;
let url = `/projects/${owner}/${projectsId}${value && `/tree/${value}`}${treeValue ? `/${treeValue}`:""}`;
props.history.push(url);
}
//
function fileMenu(){
let b = branchName || defaultBranch;
let checkvalue = turnbar(b);
return (
<Menu className="fileMenu">
<Menu.Item>
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件</CheckProfile>
</Menu.Item>
<Menu.Item>
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件</CheckProfile>
</Menu.Item>
const fileMenu =(
<Menu>
<Menu.Item><a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/${branchName || (projectDetail && projectDetail.default_branch)}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件</a></Menu.Item>
<Menu.Item><a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/${branchName || (projectDetail && projectDetail.default_branch)}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件</a></Menu.Item>
</Menu>
)
}
)
function getPathUrl(array,index){
if(array && array.length>0 && index){
@ -279,36 +171,27 @@ function CoderDepot(props){
//
function returnMain(){
setTreeValue(undefined);
let branch = branchName || defaultBranch;
let checkvalue = turnbar(branch);
props.history.push(`/${owner}/${projectsId}/tree/${checkvalue}`);
let branch = branchName || (projectDetail && projectDetail.default_branch);
props.history.push(`/projects/${owner}/${projectsId}/tree/${branch}`);
};
//
function returnUlr(url){
let enBranch = turnbar(branchName);
props.history.push(`/${owner}/${projectsId}/tree${enBranch?`/${enBranch}`:""}/${url}`);
props.history.push(`/projects/${owner}/${projectsId}/tree${branchName?`/${branchName}`:""}/${url}`);
}
//
function goToSubRoot(path,type,filename){
if(type!=="submodule"){
let enBranch = branchName || defaultBranch;
let checkvalue = turnbar(enBranch);
setType(type);
props.history.push(`/${owner}/${projectsId}${`/tree/${checkvalue}`}${path?`/${path}`:""}`);
}
setType(type);
props.history.push(`/projects/${owner}/${projectsId}${`/tree/${branchName || (projectDetail && projectDetail.default_branch)}`}${path?`/${path}`:""}`);
}
function onEdit(readOnly){
setReadOnly(readOnly);
setEditReadme(false);
}
function ChangeFile(path, readOnly){
//
let enBranch = branchName || defaultBranch;
let checkvalue = turnbar(enBranch);
props.history.push(`/${owner}/${projectsId}/tree/${checkvalue}/${path}`);
props.history.push(`/projects/${owner}/${projectsId}/tree/${branchName || (projectDetail && projectDetail.default_branch)}/${path}`);
setType("file");
setEditReadme(true);
setReadOnly(readOnly);
};
function changeHide(hide){
@ -324,12 +207,17 @@ function CoderDepot(props){
}
const downloadMenu = (
<CloneAddress
http_url={projectDetail && projectDetail.clone_url}
ssh_url = {projectDetail && projectDetail.ssh_url}
zip_url={zip_url}
tar_url={tar_url}
showNotification={props.showNotification}/>
<div className="downMenu">
<div style={{padding:"20px",borderBottom:"1px solid #eee"}}>
<CloneAddress
http_url={projectDetail && projectDetail.clone_url}
showNotification={props.showNotification}/>
</div>
<Menu className="edu-txt-center">
<Menu.Item><a href={zip_url}>下载 ZIP</a></Menu.Item>
<Menu.Item><a href={tar_url}>下载 TAR.GZ</a></Menu.Item>
</Menu>
</div>
)
// website
function okUpdate(d,w,l){
@ -344,16 +232,11 @@ function CoderDepot(props){
}
})
}
let n = fileInfo && fileInfo.name;
const mdFlag = n && n.substring(n.length-3,n.length) === ".md";
const { current_user } = props;
const baseOper = current_user && current_user.login && issuesFlag;
const baseOperate = projectDetail && projectDetail.permission && projectDetail.permission !=="Reporter" && projectDetail.type !== 2 && pullsFlag;
const fileOperate = type === "dir" && projectDetail && projectDetail.type !== 2 && ((projectDetail.permission && projectDetail.permission !=="Reporter") || (current_user && current_user.admin));
return(
<WhiteBack>
<UpdateDescModal desc={desc} website={website} lesson_url={lesson_url} visible={openModal} onCancel={()=>setOpenModal(false)} onOk={okUpdate}/>
<Spin spinning={isSpin}>
@ -365,122 +248,98 @@ function CoderDepot(props){
owner={owner}
projectsId={projectsId}
name={projectDetail && projectDetail.name}
branch={branchName || defaultBranch}
branch={branchName || (projectDetail && projectDetail.default_branch)}
visible={visible}
onClose={()=>setVisible(false)}
list = {mainFlag ? dirInfo : undefined}
/>
<div className="drawerBtn" onClick={()=>setVisible(true)}>
<i className="iconfont icon-zuohuaicon font-14"></i>
<i className="iconfont icon-youjiantou font-16"></i>
<span>目录</span>
</div>
</React.Fragment>
}
<div style={{minHeight:"500px"}}>
{
{
projectDetail &&
<Box className="Panels">
<LongWidth>
<div className="panelmenu">
<FlexAJ>
<AlignCenter>
<div className="mr30">
<div className="mr20">
{
props && props.platform ?
<SelectBranch
repo_id={projectDetail && projectDetail.repo_id}
projectsId={projectsId}
branch={branchName || defaultBranch}
branch={branchName || (projectDetail && projectDetail.default_branch)}
changeBranch={changeBranch}
owner={owner}
history={props.history}
branchList={projectDetail && projectDetail.branches && projectDetail.branches.list}
></SelectBranch>
:
<span>分支<span className="color-grey-6">{branchName || defaultBranch}</span></span>
<span>分支<span className="color-grey-6">{branchName || (projectDetail && projectDetail.default_branch)}</span></span>
}
</div>
{
treeValuePath && treeValuePath.length > 0 ?
<Path
identifier={projectDetail && projectDetail.identifier}
treeValuePath={treeValuePath}
returnUlr={returnUlr}
returnMain={returnMain}
getPathUrl={getPathUrl}
/>
:
<React.Fragment>
<AlignCenter className="mr20">
<Link to={`/${owner}/${projectsId}/branches`} className="iconBtn">
<i className="iconfont icon-master_icon font-16"></i>
<span>分支</span>
<span>{projectDetail && projectDetail.branches_count}</span>
</Link>
</AlignCenter>
<AlignCenter className="mr20">
<Link to={`/${owner}/${projectsId}/tags`} className="iconBtn">
<i className="iconfont icon-biaoqianicon font-16"></i>
<span>标签</span>
<span>{projectDetail && projectDetail.tags_count}</span>
</Link>
</AlignCenter>
</React.Fragment>
}
<AlignCenter className="mr20">
<Link to={`/projects/${owner}/${projectsId}/branchs`} className="color-grey-9">
<i className="iconfont icon-fenzhi2 font-18 color-grey-9 mr3"></i>
<span className="color-grey-6 mr3">{projectDetail && projectDetail.branches && projectDetail.branches.total_count}</span>分支
</Link>
</AlignCenter>
<AlignCenter className="mr20">
<Link to={`/projects/${owner}/${projectsId}/tag`} className="color-grey-9">
<i className="iconfont icon-biaoqian3 font-16 color-grey-9 mr3"></i>
<span className="color-grey-6 mr3">{projectDetail && projectDetail.tags && projectDetail.tags.total_count}</span>标签
</Link>
</AlignCenter>
</AlignCenter>
<AlignCenter className="depotBtn">
{
(baseOperate || baseOper) &&
<div className="addOptionBtn">
{
baseOperate &&
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/compare/master...${branchName || defaultBranch}`)} >+ 合并请求</CheckProfile>
}
{
baseOper &&
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/issues/new`)} >+ 易修</CheckProfile>
}
</div>
}
{ fileOperate &&
<Dropdown
overlay={fileMenu()}
className="mr10"
trigger={['click']}
getPopupContainer={document.parentNode}
>
<a>文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-6 mr-5"></i></a>
<AlignCenter>
<div className="mr20 addOptionBtn">
{
projectDetail.type !== 2 &&
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/pulls/new`)} >+ 合并请求</a>
}
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/issues/new`)} >+ 任务</a>
</div>
{ type === "dir" && projectDetail.type !== 2 &&
<Dropdown overlay={fileMenu} className="mr20" trigger={['click']}>
<Button type="default">文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-9"></i></Button>
</Dropdown>
}
<Dropdown overlay={downloadMenu} placement="bottomRight" trigger={['click']}>
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white mr-3"></i></Button>
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white"></i></Button>
</Dropdown>
</AlignCenter>
</FlexAJ>
{
(dirInfo && dirInfo.length>0) || fileInfo ?
dirInfo || fileInfo ?
<div className="listtable">
{
lastCommit &&
<div className="listtablehead">
<User url={getImageUrl(`/${lastCommitAuthor && lastCommitAuthor.image_url}`)} name={lastCommitAuthor && lastCommitAuthor.name} id={lastCommitAuthor && lastCommitAuthor.id} login={lastCommitAuthor && lastCommitAuthor.login}/>
<div className={hideBtn && hide ? "ellipsistxt hidetxt" :"ellipsistxt"}>
<pre id="ptxt"><Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(lastCommit.sha)}`}><RenderHtml value={lastCommit.message}/></Link></pre>
</div>
<div className={hideBtn && hide ? "ellipsistxt hide" :"ellipsistxt"}><pre id="ptxt">{lastCommit && lastCommit.message}</pre></div>
{ hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> }
<span className="ml20 color-grey-6 font-12 mt3">{lastCommit.time_from_now}</span>
{
commitCount ?
<Link to={`/${owner}/${projectsId}/commits/branch/${turnbar(branchName || defaultBranch)}`} className="ml20 color-grey-3"style={{height:"28px",lineHeight:"28px"}}>
<i className="iconfont icon-tijiaoicon mr3 font-16"></i><span style={{fontWeight:"500"}}>{commitCount}次提交</span>
</Link>:""
}
<span className="ml12 color-grey-9 mt3">{lastCommit && lastCommit.time_from_now}</span>
{ commitCount ? <Link to={`/projects/${owner}/${projectsId}/commits`} className="ml12 color-grey-9"><i className="iconfont icon-tijiao mr3 font-17 color-grey-9"></i>{commitCount}次提交</Link>:"" }
</div>
}
<ul className="listtablebody">
{
treeValuePath && treeValuePath.length > 0 &&
<Path
identifier={projectDetail && projectDetail.identifier}
treeValuePath={treeValuePath}
returnUlr={returnUlr}
returnMain={returnMain}
getPathUrl={getPathUrl}
/>
}
{
dirInfo && dirInfo.length > 0 &&
dirInfo.map((item,key)=>{
@ -502,7 +361,7 @@ function CoderDepot(props){
readOnly={readOnly}
md={mdFlag}
onEdit={onEdit}
currentBranch={branchName || defaultBranch}
currentBranch={branchName || (projectDetail && projectDetail.default_branch)}
type={projectDetail.type}
></CoderRootFileDetail>
}
@ -511,93 +370,64 @@ function CoderDepot(props){
: ""
}
{
(dirInfo && dirInfo.length === 0) && !fileInfo ? <Nodata _html="暂未发现文件"/> :""
(dirInfo && dirInfo.length === 0) && (fileInfo && fileInfo.length === 0) ? <Nodata _html="暂未发现文件"/> :""
}
{/* readme文件显示(显示文件详情时不显示readme文件) */}
{ (readme && readme.content) ? <ReadMe ChangeFile={ChangeFile} readme={readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
{ dirInfo && (projectDetail && projectDetail.readme) ? <ReadMe ChangeFile={ChangeFile} readme={projectDetail && projectDetail.readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
</div>
</LongWidth>
{
(!(treeValuePath && treeValuePath.length > 0) && !fileInfo) &&
!fileInfo &&
<ShortWidth>
<Gap style={{paddingLeft:"30px"}}>
<div className="panelmenu">
<FlexAJ className="font-18 color-ooo mb20" style={{lineHeight:"28px"}}>关于
{
projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner" || projectDetail.permission==="Manager") &&
<i onClick={()=>setOpenModal(true)} className="iconfont icon-a-shezhi color-grey-9 font-15"></i>
}
<FlexAJ className="font-18 color-grey-6 mb20" style={{lineHeight:"28px"}}>简介
{projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner") && <i onClick={()=>setOpenModal(true)} className="iconfont icon-anquanshezhi color-grey-9 font-15"></i>}
</FlexAJ>
{desc && <p className="font-14 color-grey-3 mb15 task-hide-2" style={{lineHeight:"24px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}}>{desc}</p>}
{desc && <p className="font-14 color-grey-9 mb15 task-hide-2" style={{lineHeight:"22px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}}>{desc}</p>}
{
website &&
<div className="color-grey-6 df pinfos mb5">
<i className="iconfont icon-lianjie2 font-15 mr10"></i>
<p className="color-grey-6 df">
<i className="iconfont icon-lianjie2 font-15 mr10 color-grey-9"></i>
<a href={website} target="_blank" style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px",textDecoration:"underline"}}>{website}</a>
</div>
</p>
}
<div className="pinfos mb5">
<i className="iconfont icon-zishuwenjian_icon font-15 mr10"></i>
<a href="#readme">README.md</a>
</div>
<div className="color-grey-6 mb5">
<i className="iconfont icon-neicunicon font-15 mr10"></i>
<p>
<i className="iconfont icon-wenjian4 font-15 mr10 color-grey-9"></i>
<a href="#readme" className="color-grey-6">README.md</a>
</p>
<p className="color-grey-6">
<i className="iconfont icon-dataBase font-15 mr10 color-grey-9"></i>
<span>{projectDetail && projectDetail.size}</span>
</div>
</p>
{
projectDetail && projectDetail.license_name &&
<div className="pinfos">
<i className="iconfont icon-xieyiicon font-16 mr10"></i>
<Link to={`/${owner}/${projectsId}/tree/${branchName || defaultBranch}/LICENSE`} className="color-grey-6">{projectDetail.license_name}</Link>
</div>
<p className="color-grey-6">
<i className="iconfont icon-tianping font-16 mr10 color-grey-9"></i>
<span>{projectDetail.license_name}</span>
</p>
}
</div>
{
inviteCode &&
<div>
<Divider />
<Invite code={inviteCode}/>
</div>
}
{/*{*/}
{/* inviteCode &&*/}
{/* <div>*/}
{/* <Badge code={inviteCode}/>*/}
{/* </div>*/}
{/*}*/}
{/* 徽章 */}
{
badges && badges.total_count >0 &&
<Badge badges={badges} owner={owner} />
}
{
lesson_url &&
<div>
<Divider />
<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>
<p className="font-16 color-grey-6">实践课程</p>
<a href={lesson_url} target="_blank" className="color-grey-6" style={{textDecoration:"underline"}}>{lesson_url}</a>
</div>
}
{/* 发布 */}
{
releaseVersions &&
projectDetail && projectDetail.release_versions &&
<React.Fragment>
<Divider />
<Releases
owner={owner}
projectsId={projectsId}
releaseVersions={releaseVersions}
history={props.history}
distribution={distribution}
/>
<Releases owner={owner} projectsId={projectsId} releaseVersions={projectDetail.release_versions} history={props.history}/>
</React.Fragment>
}
{/* 贡献者 */}
{
projectDetail && projectDetail.contributors && projectDetail.contributors.total_count >0 &&
<Contributors contributors={projectDetail.contributors} owner={owner} projectsId={projectsId} />
projectDetail && projectDetail.contributors &&
<Contributors contributors={projectDetail && projectDetail.contributors} owner={owner} projectsId={projectsId} />
}
{/* 语言 */}
{ projectDetail && projectDetail.languages &&

View File

@ -2,26 +2,20 @@ import React from 'react';
import { Link } from 'react-router-dom';
import { truncateCommitId } from '../common/util';
const typeIco = {
"submodule":"icon-file-submodule font-17",
"file":'icon-wenjian6 font-15 color-blue-file',
"dir":"icon-wenjianjia4 font-15 color-blue_4C"
}
function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
return(
<li>
<span>
<a onClick={()=>goToSubRoot(item.path,item.type,item.name)} className={item.type === "submodule" && "submoduleStyle"}>
<i className={`iconfont ${typeIco[`${item.type}`]} mr8`}></i>{item.name}
<a onClick={()=>goToSubRoot(item.path,item.type,item.name)}>
<i className={item.type === 'dir' ? "iconfont icon-wenjianjia1 color-green-file font-15 mr5":"iconfont icon-wenjia color-green-file font-15 mr5"}></i>{item.name}
</a>
</span>
<span title="init project">
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.commit && item.commit.sha}`)}`} title={item.commit && item.commit.message}>
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.commit && item.commit.sha}`)}`} title={item.commit && item.commit.message}>
{item.commit && item.commit.message}
</Link>
</span>
<span title={item.commit && item.commit.created_at}>{item.commit && item.commit.time_from_now}</span>
<span>{item.commit && item.commit.time_from_now}</span>
</li>
)
}

Some files were not shown because too many files have changed in this diff Show More