资助激励功能合并 #1
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"presets": [
|
||||
"es2015",
|
||||
"react",
|
||||
"stage-2"
|
||||
],
|
||||
"plugins": [[
|
||||
"transform-runtime",
|
||||
{
|
||||
"helpers": false,
|
||||
"polyfill": false,
|
||||
"regenerator": true,
|
||||
"moduleName": "babel-runtime"
|
||||
}
|
||||
]]
|
||||
}
|
||||
|
|
@ -86,3 +86,4 @@ typings/
|
|||
|
||||
.DS_Store
|
||||
.idea/*
|
||||
.forgeplus-react.sublime-workspace
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -0,0 +1,317 @@
|
|||
{
|
||||
"auto_complete":
|
||||
{
|
||||
"selected_items":
|
||||
[
|
||||
[
|
||||
"samp",
|
||||
"samp2_method"
|
||||
],
|
||||
[
|
||||
"modu",
|
||||
"module_method"
|
||||
],
|
||||
[
|
||||
"cu",
|
||||
"currentTerm"
|
||||
],
|
||||
[
|
||||
"req",
|
||||
"requestVote"
|
||||
],
|
||||
[
|
||||
"reque",
|
||||
"RequestVote"
|
||||
],
|
||||
[
|
||||
"App",
|
||||
"AppendEntries"
|
||||
],
|
||||
[
|
||||
"hea",
|
||||
"heartBeatInterval"
|
||||
],
|
||||
[
|
||||
"time",
|
||||
"timeOut"
|
||||
],
|
||||
[
|
||||
"ele",
|
||||
"electionTimeout"
|
||||
],
|
||||
[
|
||||
"R",
|
||||
"Raft"
|
||||
],
|
||||
[
|
||||
"vote",
|
||||
"votedFor"
|
||||
],
|
||||
[
|
||||
"Ra",
|
||||
"RaftState"
|
||||
],
|
||||
[
|
||||
"is",
|
||||
"isleader"
|
||||
]
|
||||
]
|
||||
},
|
||||
"buffers":
|
||||
[
|
||||
{
|
||||
"file": "src/redux/actions/actionTypes.js",
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 5688,
|
||||
"encoding": "UTF-8",
|
||||
"line_ending": "Unix"
|
||||
}
|
||||
}
|
||||
],
|
||||
"build_system": "",
|
||||
"build_system_choices":
|
||||
[
|
||||
],
|
||||
"build_varint": "",
|
||||
"command_palette":
|
||||
{
|
||||
"height": 0.0,
|
||||
"last_filter": "",
|
||||
"selected_items":
|
||||
[
|
||||
],
|
||||
"width": 0.0
|
||||
},
|
||||
"console":
|
||||
{
|
||||
"height": 171.0,
|
||||
"history":
|
||||
[
|
||||
"ls"
|
||||
]
|
||||
},
|
||||
"distraction_free":
|
||||
{
|
||||
"menu_visible": true,
|
||||
"show_minimap": false,
|
||||
"show_open_files": false,
|
||||
"show_tabs": false,
|
||||
"side_bar_visible": false,
|
||||
"status_bar_visible": false
|
||||
},
|
||||
"expanded_folders":
|
||||
[
|
||||
"/home/qyzh/new_trustie/forgeplus-react"
|
||||
],
|
||||
"file_history":
|
||||
[
|
||||
"/home/qyzh/OSS/forgeplus/app/models/user.rb",
|
||||
"/home/qyzh/OSS/forgeplus/db/structure.sql",
|
||||
"/home/qyzh/OSS/forgeplus/app/controllers/settings_controller.rb",
|
||||
"/home/qyzh/OSS/forgeplus/app/controllers/application_controller.rb",
|
||||
"/home/qyzh/OSS/Trustie/app/controllers/projects_controller.rb",
|
||||
"/home/qyzh/temp.sh",
|
||||
"/home/qyzh/OSS/Trustie/Gemfile",
|
||||
"/home/qyzh/.npm/_logs/2020-06-07T02_42_06_886Z-debug.log",
|
||||
"/home/qyzh/OSS/forgeplus/app/controllers/users_controller.rb",
|
||||
"/home/qyzh/OSS/forgeplus/app/controllers/accounts_controller.rb",
|
||||
"/home/qyzh/custom/conf/app.ini",
|
||||
"/home/qyzh/OSS/Trustie_old/Gemfile.lock",
|
||||
"/home/qyzh/OSS/Trustie/Gemfile.lock",
|
||||
"/home/qyzh/ruby_study/test.rb",
|
||||
"/home/qyzh/RubymineProjects/myblog/app/controller/users_controller.rb",
|
||||
"/home/qyzh/OSS/forgeplus/app/libs/limit_forbid_control.rb",
|
||||
"/home/qyzh/OSS/forgeplus/log/development.log",
|
||||
"/home/qyzh/NJU-DisSys-2017/src/raft/raft.go",
|
||||
"/home/qyzh/OSS/forgeplus/config/application.rb",
|
||||
"/home/qyzh/RubymineProjects/demo/app/helpers/welcome_helper.rb",
|
||||
"/home/qyzh/RubymineProjects/demo/app/controllers/welcome_controller.rb",
|
||||
"/home/qyzh/RubymineProjects/demo/config/routes.rb",
|
||||
"/home/qyzh/RubymineProjects/demo/app/views/welcome/index.html.erb",
|
||||
"/home/qyzh/trustie/Gemfile",
|
||||
"/home/qyzh/trustie/Gemfile.lock",
|
||||
"/home/qyzh/ruby_study/test",
|
||||
"/home/qyzh/NJU-DisSys-2017/src/labrpc/test_test.go",
|
||||
"/home/qyzh/NJU-DisSys-2017/src/labrpc/labrpc.go",
|
||||
"/home/qyzh/NJU-DisSys-2017/src/raft/test_test.go",
|
||||
"/home/qyzh/NJU-DisSys-2017/src/raft/persister.go",
|
||||
"/home/qyzh/NJU-DisSys-2017/src/raft/util.go",
|
||||
"/home/qyzh/NJU-DisSys-2017/src/raft/config.go"
|
||||
],
|
||||
"find":
|
||||
{
|
||||
"height": 29.0
|
||||
},
|
||||
"find_in_files":
|
||||
{
|
||||
"height": 0.0,
|
||||
"where_history":
|
||||
[
|
||||
]
|
||||
},
|
||||
"find_state":
|
||||
{
|
||||
"case_sensitive": true,
|
||||
"find_history":
|
||||
[
|
||||
"current_user",
|
||||
"user_set",
|
||||
"login",
|
||||
"platform",
|
||||
"Platform不包含于列表中",
|
||||
"find_by_",
|
||||
"find_by",
|
||||
"3.2.22",
|
||||
"bug",
|
||||
"persister",
|
||||
"currentTerm",
|
||||
"currentTern",
|
||||
"term",
|
||||
"your",
|
||||
"electionInterval",
|
||||
"your",
|
||||
"if",
|
||||
"your",
|
||||
"Persister",
|
||||
"make",
|
||||
"Your code here",
|
||||
"Call",
|
||||
"labrpc",
|
||||
"main"
|
||||
],
|
||||
"highlight": true,
|
||||
"in_selection": false,
|
||||
"preserve_case": false,
|
||||
"regex": false,
|
||||
"replace_history":
|
||||
[
|
||||
],
|
||||
"reverse": false,
|
||||
"show_context": true,
|
||||
"use_buffer2": true,
|
||||
"whole_word": false,
|
||||
"wrap": true
|
||||
},
|
||||
"groups":
|
||||
[
|
||||
{
|
||||
"selected": 0,
|
||||
"sheets":
|
||||
[
|
||||
{
|
||||
"buffer": 0,
|
||||
"file": "src/redux/actions/actionTypes.js",
|
||||
"semi_transient": false,
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 5688,
|
||||
"regions":
|
||||
{
|
||||
},
|
||||
"selection":
|
||||
[
|
||||
[
|
||||
0,
|
||||
0
|
||||
]
|
||||
],
|
||||
"settings":
|
||||
{
|
||||
"syntax": "Packages/JavaScript/JavaScript.sublime-syntax",
|
||||
"tab_size": 2,
|
||||
"translate_tabs_to_spaces": true
|
||||
},
|
||||
"translation.x": 0.0,
|
||||
"translation.y": 0.0,
|
||||
"zoom_level": 1.0
|
||||
},
|
||||
"stack_index": 0,
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"incremental_find":
|
||||
{
|
||||
"height": 29.0
|
||||
},
|
||||
"input":
|
||||
{
|
||||
"height": 0.0
|
||||
},
|
||||
"layout":
|
||||
{
|
||||
"cells":
|
||||
[
|
||||
[
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1
|
||||
]
|
||||
],
|
||||
"cols":
|
||||
[
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
"rows":
|
||||
[
|
||||
0.0,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
"menu_visible": true,
|
||||
"output.find_results":
|
||||
{
|
||||
"height": 0.0
|
||||
},
|
||||
"pinned_build_system": "",
|
||||
"project": "forgeplus-react.sublime-project",
|
||||
"replace":
|
||||
{
|
||||
"height": 54.0
|
||||
},
|
||||
"save_all_on_build": true,
|
||||
"select_file":
|
||||
{
|
||||
"height": 0.0,
|
||||
"last_filter": "",
|
||||
"selected_items":
|
||||
[
|
||||
],
|
||||
"width": 0.0
|
||||
},
|
||||
"select_project":
|
||||
{
|
||||
"height": 0.0,
|
||||
"last_filter": "",
|
||||
"selected_items":
|
||||
[
|
||||
],
|
||||
"width": 0.0
|
||||
},
|
||||
"select_symbol":
|
||||
{
|
||||
"height": 0.0,
|
||||
"last_filter": "",
|
||||
"selected_items":
|
||||
[
|
||||
],
|
||||
"width": 0.0
|
||||
},
|
||||
"selected_group": 0,
|
||||
"settings":
|
||||
{
|
||||
},
|
||||
"show_minimap": true,
|
||||
"show_open_files": false,
|
||||
"show_tabs": true,
|
||||
"side_bar_visible": true,
|
||||
"side_bar_width": 288.0,
|
||||
"status_bar_visible": true,
|
||||
"template_settings":
|
||||
{
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
|
|
@ -9,8 +9,7 @@
|
|||
"antd": "^3.26.15",
|
||||
"array-flatten": "^2.1.2",
|
||||
"autoprefixer": "7.1.6",
|
||||
"axios": "^0.18.1",
|
||||
"babel-core": "6.26.0",
|
||||
"axios": "^0.21.1",
|
||||
"babel-eslint": "7.2.3",
|
||||
"babel-jest": "20.0.3",
|
||||
"babel-loader": "7.1.2",
|
||||
|
|
@ -24,7 +23,7 @@
|
|||
"classnames": "^2.2.5",
|
||||
"clipboard": "^2.0.6",
|
||||
"code-prettify": "^0.1.0",
|
||||
"codemirror": "^5.53.0",
|
||||
"codemirror": "^5.61.0",
|
||||
"connected-react-router": "4.4.1",
|
||||
"css-loader": "^3.5.2",
|
||||
"dotenv": "4.0.0",
|
||||
|
|
@ -47,7 +46,7 @@
|
|||
"jest": "20.0.4",
|
||||
"js-base64": "^2.5.2",
|
||||
"katex": "^0.11.1",
|
||||
"lodash": "^4.17.15",
|
||||
"lodash": "^4.17.21",
|
||||
"loglevel": "^1.6.8",
|
||||
"marked": "^1.0.0",
|
||||
"material-ui": "^1.0.0-beta.40",
|
||||
|
|
@ -75,6 +74,7 @@
|
|||
"rc-upload": "^2.9.4",
|
||||
"react": "^16.13.1",
|
||||
"react-beautiful-dnd": "^10.0.4",
|
||||
"react-charts": "^2.0.0-beta.7",
|
||||
"react-codemirror": "^1.0.0",
|
||||
"react-codemirror2": "^6.0.1",
|
||||
"react-color": "^2.18.0",
|
||||
|
|
@ -94,6 +94,7 @@
|
|||
"react-router-dom": "^4.2.2",
|
||||
"react-split-pane": "^0.1.91",
|
||||
"react-url-query": "^1.5.0",
|
||||
"react-vis": "^1.11.7",
|
||||
"react-zmage": "^0.8.5-beta.31",
|
||||
"redux": "^4.0.5",
|
||||
"redux-thunk": "2.3.0",
|
||||
|
|
@ -108,7 +109,7 @@
|
|||
"sw-precache-webpack-plugin": "0.11.4",
|
||||
"url-loader": "0.6.2",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.10.3",
|
||||
"webpack-dev-server": "^3.11.0",
|
||||
"webpack-manifest-plugin": "^2.2.0",
|
||||
"whatwg-fetch": "2.0.3",
|
||||
"wrap-md-editor": "^0.2.20"
|
||||
|
|
@ -182,7 +183,13 @@
|
|||
"port": "3007",
|
||||
"devDependencies": {
|
||||
"@babel/runtime": "7.0.0-beta.51",
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-plugin-import": "^1.13.0",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babel-preset-stage-2": "^6.24.1",
|
||||
"compression-webpack-plugin": "^1.1.12",
|
||||
"concat": "^1.0.3",
|
||||
"happypack": "^5.0.1",
|
||||
|
|
|
|||
|
|
@ -2325,6 +2325,9 @@ input::-ms-clear {
|
|||
background-color: #F5F5F5;
|
||||
}
|
||||
|
||||
.ant-modal-close{
|
||||
top:8px!important;
|
||||
}
|
||||
|
||||
.newContainer {
|
||||
min-height: 100%;
|
||||
|
|
@ -2658,7 +2661,7 @@ a.color-green:hover {
|
|||
|
||||
/*百分比宽度*/
|
||||
.width100 {
|
||||
width: 100%;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.width89 {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,111 @@
|
|||
|
||||
.CodeMirror-merge {
|
||||
position: relative;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.CodeMirror-merge, .CodeMirror-merge .CodeMirror {
|
||||
min-height:50px;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 48%; }
|
||||
.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 4%; }
|
||||
.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; }
|
||||
.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; }
|
||||
|
||||
.CodeMirror-merge-pane {
|
||||
display: inline-block;
|
||||
white-space: normal;
|
||||
vertical-align: top;
|
||||
}
|
||||
.CodeMirror-merge-pane-rightmost {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-gap {
|
||||
z-index: 2;
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: #515151;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-scrolllock-wrap {
|
||||
position: absolute;
|
||||
bottom: 0; left: 50%;
|
||||
}
|
||||
.CodeMirror-merge-scrolllock {
|
||||
position: relative;
|
||||
left: -50%;
|
||||
cursor: pointer;
|
||||
color: #d8d8d8;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right {
|
||||
position: absolute;
|
||||
left: 0; top: 0;
|
||||
right: 0; bottom: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-copy {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
color: #ce374b;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-copy-reverse {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
color: #44c;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; }
|
||||
.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; }
|
||||
|
||||
.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==);
|
||||
background-position: bottom left;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==);
|
||||
background-position: bottom left;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-r-chunk { background: #9a6868; }
|
||||
.CodeMirror-merge-r-chunk-start { /*border-top: 1px solid #ee8; */}
|
||||
.CodeMirror-merge-r-chunk-end {/* border-bottom: 1px solid #ee8; */}
|
||||
.CodeMirror-merge-r-connect { fill:#9a6868;}
|
||||
|
||||
.CodeMirror-merge-l-chunk { background: #eef; }
|
||||
.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; }
|
||||
.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; }
|
||||
.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; }
|
||||
|
||||
.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; }
|
||||
.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; }
|
||||
.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; }
|
||||
|
||||
.CodeMirror-merge-collapsed-widget:before {
|
||||
content: "(...)";
|
||||
}
|
||||
.CodeMirror-merge-collapsed-widget {
|
||||
cursor: pointer;
|
||||
color: #88b;
|
||||
background: #eef;
|
||||
border: 1px solid #ddf;
|
||||
font-size: 90%;
|
||||
padding: 0 3px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; }
|
||||
|
|
@ -8,18 +8,9 @@
|
|||
<meta name=”Description” Content=”持续构建协同、共享、可信的软件创建生态开源创作与软件生产相结合,支持大规模群体开展软件协同创新活动”>
|
||||
<meta name="theme-color" content="#000000">
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<!-- <script type="text/javascript">
|
||||
window.__isR = true;
|
||||
if (
|
||||
(navigator.userAgent.indexOf('MSIE 9') != -1
|
||||
|| navigator.userAgent.indexOf('MSIE 10') != -1)
|
||||
&&
|
||||
location.pathname.indexOf("/compatibility") == -1) {
|
||||
location.href = '/compatibility.html'
|
||||
}
|
||||
</script> -->
|
||||
<link rel=" stylesheet" type="text/css" href="%PUBLIC_URL%css/iconfont.css">
|
||||
<link rel=" stylesheet" type="text/css" href="%PUBLIC_URL%css/edu-purge.css">
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/iconfont.css">
|
||||
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/edu-purge.css">
|
||||
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/editormd.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/merge.css">
|
||||
<%= htmlWebpackPlugin.tags.headTags %>
|
||||
|
|
@ -30,6 +21,7 @@
|
|||
<div id="root" class="page -layout-v -fit widthunit"></div>
|
||||
<div id="picture_display" style="display: none;"></div>
|
||||
<script src="%PUBLIC_URL%js/jquery-1.8.3.min.js"></script>
|
||||
<script src="%PUBLIC_URL%js/js_min_all.js"></script>
|
||||
<script src="%PUBLIC_URL%js/codemirror/codemirror.js"></script>
|
||||
<script src="%PUBLIC_URL%js/editormd/editormd.min.js"></script>
|
||||
<script src="%PUBLIC_URL%js/codemirror/merge/merge.js"></script>
|
||||
|
|
|
|||
53
src/App.js
53
src/App.js
|
|
@ -9,13 +9,7 @@ import {
|
|||
} from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
import LoginDialog from './modules/login/LoginDialog';
|
||||
import Notcompletedysl from './modules/user/Notcompletedysl';
|
||||
import Trialapplicationysl from './modules/login/Trialapplicationysl';
|
||||
import Trialapplicationreview from './modules/user/Trialapplicationreview';
|
||||
import AccountProfile from "./modules/user/AccountProfile";
|
||||
import Accountnewprofile from './modules/user/Accountnewprofile';
|
||||
import Certifiedprofessional from './modules/modals/Certifiedprofessional';
|
||||
|
||||
import 'babel-polyfill';
|
||||
import Loading from './Loading'
|
||||
|
||||
import Loadable from 'react-loadable';
|
||||
|
|
@ -30,6 +24,7 @@ import { SnackbarHOC } from 'educoder'
|
|||
import { initAxiosInterceptors } from './AppConfig'
|
||||
import { Provider } from 'react-redux';
|
||||
import configureStore from './redux/stores/configureStore';
|
||||
import { load } from 'react-cookies';
|
||||
const store = configureStore();
|
||||
window.marked = marked;
|
||||
const theme = createMuiTheme({
|
||||
|
|
@ -76,6 +71,20 @@ const OrganizeIndex = Loadable({
|
|||
loader: () => import('./forge/Team/Index'),
|
||||
loading: Loading,
|
||||
})
|
||||
// Sponsor
|
||||
const Sponsor = Loadable({
|
||||
loader: () => import('./forge/sponsor/Sponsor'),
|
||||
loading: Loading,
|
||||
})
|
||||
// Sponsor Confirmation
|
||||
const SponsorConfirmation = Loadable({
|
||||
loader: () => import('./forge/sponsor/SponsorConfirmation'),
|
||||
loading: Loading,
|
||||
})
|
||||
const EducoderLogin = Loadable({
|
||||
loader: () => import('./modules/login/EducoderLogin'),
|
||||
loading: Loading,
|
||||
})
|
||||
|
||||
class App extends Component {
|
||||
constructor(props) {
|
||||
|
|
@ -213,18 +222,12 @@ class App extends Component {
|
|||
<Provider store={store}>
|
||||
<ConfigProvider locale={zhCN}>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
{/* <Accountnewprofile {...this.props}{...this.state} /> */}
|
||||
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
|
||||
{/* <Notcompletedysl {...this.props} {...this.state}></Notcompletedysl> */}
|
||||
{/* <Trialapplicationysl {...this.props} {...this.state}></Trialapplicationysl> */}
|
||||
{/* <Trialapplicationreview {...this.props} {...this.state}></Trialapplicationreview> */}
|
||||
{/* <AccountProfile {...this.props} {...this.state} /> */}
|
||||
{/* <Certifiedprofessional {...this.props} {...this.state} ModalCancelsy={this.ModalCancelsy} ModalshowCancelsy={this.ModalshowCancelsy} /> */}
|
||||
<Router>
|
||||
<Switch>
|
||||
{/*项目*/}
|
||||
<Route
|
||||
path={"/projects/:projectId/ops/:opsId/detail"}
|
||||
path={"/projects/:owner/:projectId/devops/:opsId/detail"}
|
||||
render={
|
||||
(props) => {
|
||||
return (<OpsDetail {...this.props} {...props} {...this.state} />)
|
||||
|
|
@ -240,7 +243,15 @@ class App extends Component {
|
|||
}
|
||||
}>
|
||||
</Route>
|
||||
|
||||
<Route
|
||||
path="/register"
|
||||
render={
|
||||
(props) => {
|
||||
|
||||
return (<EducoderLogin {...this.props} {...props} {...this.state} />)
|
||||
}
|
||||
}
|
||||
/>
|
||||
{/*403*/}
|
||||
<Route path="/403" component={Shixunauthority} />
|
||||
|
||||
|
|
@ -260,7 +271,17 @@ class App extends Component {
|
|||
(props) => {
|
||||
return (<InfosIndex {...this.props} {...this.state} />)
|
||||
}
|
||||
}></Route>
|
||||
}></Route>
|
||||
<Route exact path="/sponsor_confirmation/:username/:tier_id"
|
||||
render={
|
||||
(props) => (<SponsorConfirmation {...this.props}{...this.state}></SponsorConfirmation>)
|
||||
}>
|
||||
</Route>
|
||||
<Route exact path="/sponsor/:username"
|
||||
render={
|
||||
(props) => (<Sponsor {...this.props}{...this.state}></Sponsor>)
|
||||
}>
|
||||
</Route>
|
||||
<Route exact path="/"
|
||||
render={
|
||||
(props) => (
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ if (isDev) {
|
|||
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'
|
||||
}
|
||||
}
|
||||
function clearAllCookie() {
|
||||
cookie.remove('_educoder_session', { path: '/' });
|
||||
cookie.remove('autologin_trustie', { path: '/' });
|
||||
|
|
@ -38,7 +38,6 @@ clearAllCookie();
|
|||
function setpostcookie() {
|
||||
const str = window.location.pathname;
|
||||
if (str.indexOf("/wxcode") !== -1) {
|
||||
console.log("123")
|
||||
cookie.remove('_educoder_session', { path: '/' });
|
||||
cookie.remove('autologin_trustie', { path: '/' });
|
||||
const _params = window.location.search;
|
||||
|
|
@ -57,9 +56,10 @@ window._debugType = debugType;
|
|||
export function initAxiosInterceptors(props) {
|
||||
initOnlineOfflineListener()
|
||||
// TODO 避免重复的请求 https://github.com/axios/axios#cancellation
|
||||
var
|
||||
proxy = "http://localhost:3000"
|
||||
proxy = "https://testforgeplus.trustie.net"
|
||||
var
|
||||
// proxy = "http://172.27.144.138:3000/"
|
||||
proxy = "http://localhost:3000"
|
||||
// proxy = "https://testforgeplus.trustie.net"
|
||||
|
||||
const requestMap = {};
|
||||
window.setfalseInRequestMap = function (keyName) {
|
||||
|
|
@ -71,7 +71,7 @@ export function initAxiosInterceptors(props) {
|
|||
setpostcookie()
|
||||
clearAllCookie()
|
||||
|
||||
if (config.url.indexOf(proxy) !== -1 || config.url.indexOf(':') !== -1) {
|
||||
if (config.url.indexOf(proxy) !== -1) {
|
||||
return config
|
||||
}
|
||||
requestProxy(config)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
|
||||
|
||||
import { Spin } from 'antd';
|
||||
|
||||
class Loading extends Component {
|
||||
|
|
@ -12,7 +9,6 @@ class Loading extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
// Loading
|
||||
return (
|
||||
<div className="App" style={{ minHeight: '800px', width: "100%" }}>
|
||||
<style>
|
||||
|
|
|
|||
|
|
@ -11,15 +11,11 @@ export function getImageUrl(path) {
|
|||
// https://www.educoder.net
|
||||
// https://testbdweb.trustie.net
|
||||
// const local = 'http://localhost:3000'
|
||||
const local = 'https://testforgeplus.trustie.net/';
|
||||
if(path.indexOf("http://")===-1){
|
||||
if (isDev) {
|
||||
return `${local}/${path}`
|
||||
}
|
||||
return `/${path}`;
|
||||
}else{
|
||||
return path;
|
||||
const local = 'https://testforgeplus.trustie.net';
|
||||
if (isDev) {
|
||||
return `${local}/${path}`
|
||||
}
|
||||
return `/${path}`;
|
||||
}
|
||||
|
||||
export function getImage(path) {
|
||||
|
|
|
|||
|
|
@ -38,13 +38,11 @@ export const formatDelta = (deltas) => {
|
|||
alt="${alt}"
|
||||
/>
|
||||
`;
|
||||
// text = "<img src="+url+" width='60px' height='30px' onclick='' alt="+alt+"/>";
|
||||
}
|
||||
}
|
||||
|
||||
formatted.push(text);
|
||||
});
|
||||
console.log(formatted);
|
||||
return formatted.join('');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ function Index(props){
|
|||
<div className="aboutContent">
|
||||
<AlignCenterBetween style={{padding:"14px 0px"}}>
|
||||
<span className="font-16"><i className="iconfont icon-xiangmujianjie mr5 font-16 color-blue"></i>项目简介</span>
|
||||
{ editOpration && <a onClick={editContent} className="color-blue">编辑</a> }
|
||||
{ editOpration && !edit && <a onClick={editContent} className="color-blue">编辑</a> }
|
||||
</AlignCenterBetween>
|
||||
{
|
||||
edit ?
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ class Activity extends Component{
|
|||
}
|
||||
</div>
|
||||
:
|
||||
<NoneData _html="暂时还没有相关数据哦!" />
|
||||
<NoneData _html="暂时还没有相关数据!" />
|
||||
}
|
||||
</Spin>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import './branch.css';
|
|||
import { getBranch , getTag } from '../GetData/getData';
|
||||
|
||||
|
||||
export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
|
||||
export default (({ projectsId , branch , owner , history , changeBranch })=>{
|
||||
const [ showValue , setShowValue ] = useState(branch);
|
||||
const [ inputValue , setInputValue] = useState(undefined);
|
||||
const [ nav , setNav ] = useState(0);
|
||||
|
|
@ -17,10 +17,11 @@ export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
|
|||
useEffect(()=>{
|
||||
setShowValue(branch);
|
||||
},[branch])
|
||||
|
||||
useEffect(()=>{
|
||||
document.body.addEventListener('click', e => {
|
||||
let name = e.target.className;
|
||||
let turn = name == "ant-input OptionsInput" || name == "navli active"|| name == "navli" || name == "padding10 bor-bottom-greyE";
|
||||
let turn = name === "ant-input OptionsInput" || name === "navli active"|| name === "navli" || name === "padding10 bor-bottom-greyE";
|
||||
if(turn){
|
||||
return;
|
||||
}else{
|
||||
|
|
@ -31,7 +32,7 @@ export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
|
|||
|
||||
useEffect(()=>{
|
||||
getBranchs(projectsId,owner);
|
||||
},[projectsId])
|
||||
},[owner])
|
||||
|
||||
|
||||
async function getBranchs(id,owner){
|
||||
|
|
@ -63,7 +64,7 @@ export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
|
|||
}
|
||||
}
|
||||
function chooseitem(value){
|
||||
setShowValue(value);
|
||||
// setShowValue(value);
|
||||
changeBranch(value);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
width: 240px;
|
||||
min-width: 240px;
|
||||
}
|
||||
.branch-tagBox-list .ant-popover-arrow{
|
||||
display: none;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ li.ant-menu-item{
|
|||
margin:0px!important;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.flags{
|
||||
border: 1px solid red;
|
||||
border-radius: 5px;
|
||||
}
|
||||
// Cards
|
||||
.cards{
|
||||
display: flex;
|
||||
|
|
@ -72,6 +76,7 @@ li.ant-menu-item{
|
|||
border-radius:11px;
|
||||
color: #fff;
|
||||
margin-left: 5px;
|
||||
font-size: 12px;
|
||||
&.running{
|
||||
background:#5091FF;
|
||||
color: #F1F8FF;
|
||||
|
|
@ -88,6 +93,10 @@ li.ant-menu-item{
|
|||
background:#F73030;
|
||||
color:#FCEEEE ;
|
||||
}
|
||||
&.killed{
|
||||
background:#eee;
|
||||
color:#999 ;
|
||||
}
|
||||
}
|
||||
.handleBox{
|
||||
position: fixed;
|
||||
|
|
@ -95,6 +104,7 @@ li.ant-menu-item{
|
|||
right:240px;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1800px){
|
||||
.handleBox{
|
||||
right:190px;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
|
||||
|
||||
export default ({title , value , className})=>{
|
||||
const Keys = styled.span`
|
||||
display:flex;
|
||||
align-item:center;
|
||||
align-items:center;
|
||||
& span{
|
||||
display:block;
|
||||
height:20px;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import React from 'react';
|
||||
import { Modal , Button } from 'antd';
|
||||
import './Component.scss';
|
||||
|
||||
function Modals({visible,title,content,onOk,onCancel}){
|
||||
return(
|
||||
<Modal
|
||||
className="modalsStyle"
|
||||
visible={visible}
|
||||
title={title}
|
||||
onCancel={onCancel}
|
||||
closable={true}
|
||||
footer={
|
||||
<div>
|
||||
<Button onClick={onCancel}>取消</Button>
|
||||
<Button type={"primary"} style={{marginLeft:"20px"}} onClick={onOk}>确定</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div style={{fontSize:"16px"}}>{content}</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export default Modals;
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import React , { useState , useEffect } from 'react';
|
||||
import { Select } from 'antd';
|
||||
import { getUrl } from 'educoder';
|
||||
|
||||
import axios from 'axios';
|
||||
const Option = Select.Option;
|
||||
|
||||
export default (({ language , select_language })=>{
|
||||
const [ six , setSix ] = useState(undefined);
|
||||
const [ languages , setLanguage ] = useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
const url = '/ci/languages.json';
|
||||
axios.get(url).then(result=>{
|
||||
if(result){
|
||||
setLanguage(result.data);
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
},[])
|
||||
|
||||
function changelanguage(value){
|
||||
let array = value ? languages.filter(item=>item.name === value) :undefined;
|
||||
select_language(value,array && array[0]);
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
const url = '/ci/languages/common.json';
|
||||
axios.get(url).then(result=>{
|
||||
if(result){
|
||||
setSix(result.data);
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
},[])
|
||||
|
||||
return(
|
||||
<React.Fragment>
|
||||
{
|
||||
six &&
|
||||
<ul className="language">
|
||||
{
|
||||
six.map((item,key)=>{
|
||||
return(
|
||||
key < 6 ? <li className={language ===item.name ? "active":""} onClick={()=>changelanguage(item.name)}><img alt="" src={item.cover_url && getUrl(item.cover_url)} /></li> : ""
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
<Select showSearch={true} placeholder={"请选择文本语言"} style={{ width: 200 }} value={language} onChange={changelanguage}>
|
||||
<Option value={undefined}>请选择文本语言</Option>
|
||||
{languages && languages.map((item, key) => {
|
||||
return <Option value={item.name}>{item.name}</Option>;
|
||||
})}
|
||||
</Select>
|
||||
</React.Fragment>
|
||||
)
|
||||
})
|
||||
|
|
@ -3,42 +3,54 @@ import './Component.scss';
|
|||
|
||||
export const Tags = (status)=>{
|
||||
switch(status){
|
||||
case 1:
|
||||
case "running":
|
||||
return(
|
||||
<span className="statusColor running">运行中</span>
|
||||
);
|
||||
case 2:
|
||||
case "failure":case"error":
|
||||
return (
|
||||
<span className="statusColor failed">未通过</span>
|
||||
);
|
||||
case 3:
|
||||
case "success":
|
||||
return (
|
||||
<span className="statusColor pass">已通过</span>
|
||||
);
|
||||
default:
|
||||
case "pending":
|
||||
return (
|
||||
<span className="statusColor Preparing">准备中</span>
|
||||
);
|
||||
case 'killed':
|
||||
return (
|
||||
<span className="statusColor killed">已撤销</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const TagsLine = (status)=>{
|
||||
switch(status){
|
||||
case 1:
|
||||
case "running":
|
||||
return(
|
||||
<span className="statuslineColor running">运行中</span>
|
||||
);
|
||||
case 2:
|
||||
case "failure":case "error":
|
||||
return (
|
||||
<span className="statuslineColor failed">未通过</span>
|
||||
);
|
||||
case 3:
|
||||
case "success":
|
||||
return (
|
||||
<span className="statuslineColor pass">已通过</span>
|
||||
);
|
||||
default:
|
||||
case "pending":
|
||||
return (
|
||||
<span className="statuslineColor Preparing">准备中</span>
|
||||
);
|
||||
case 'killed':
|
||||
return (
|
||||
<span className="statuslineColor killed">已撤销</span>
|
||||
);
|
||||
case 'skipped':
|
||||
return (
|
||||
<span className="statuslineColor skipped">已跳过</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import React ,{ useState } from 'react';
|
||||
import { Modal , Input , Spin } from 'antd';
|
||||
import { AlignCenter } from "./layout";
|
||||
import axios from 'axios';
|
||||
import './Component.scss';
|
||||
|
||||
function PasswordAuthority({ authorityValBox , successFunc , cancelFunc }){
|
||||
const [ authorityVal , setAuthorityVal ] = useState(undefined);
|
||||
const [ authorityValFlag , setAuthorityValFlag ] = useState(false);
|
||||
const [ isSpin , setIsSpin ] = useState(false);
|
||||
|
||||
// 取消授权-登录密码的输入
|
||||
function cancelAuthority(){
|
||||
cancelFunc();
|
||||
}
|
||||
// 确认授权
|
||||
function okAuthority(){
|
||||
if(!authorityVal){
|
||||
setAuthorityValFlag(true);
|
||||
return;
|
||||
}
|
||||
setIsSpin(true);
|
||||
const url = `/users/ci/oauth_grant.json`;
|
||||
axios.get(url,{
|
||||
params:{password:authorityVal}
|
||||
}).then(result=>{
|
||||
setIsSpin(false);
|
||||
if(result){
|
||||
successFunc(result.data.step);
|
||||
}
|
||||
}).catch(error=>{setIsSpin(false);});
|
||||
}
|
||||
return(
|
||||
<Modal visible={authorityValBox} centered={true} title="授权" onCancel={cancelAuthority} onOk={okAuthority}>
|
||||
<Spin spinning={isSpin}>
|
||||
<p style={{textAlign:"center"}}>请输入您的登录密码,确认授权DevOps应用</p>
|
||||
<AlignCenter style={{justifyContent:"center",marginTop:"20px"}}>
|
||||
<span>密码:</span>
|
||||
<Input.Password value={authorityVal} className={authorityValFlag===true && "flags"} onChange={(e)=>setAuthorityVal(e.target.value)} style={{width:"220px"}}></Input.Password>
|
||||
</AlignCenter>
|
||||
</Spin>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export default PasswordAuthority;
|
||||
|
|
@ -1,27 +1,66 @@
|
|||
import React , { forwardRef , useCallback } from 'react';
|
||||
import activate from '../Images/activate.png';
|
||||
import { Blueback } from '../Component/layout';
|
||||
import styled from 'styled-components';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Form , Input } from 'antd';
|
||||
import axios from 'axios';
|
||||
import React, { forwardRef, useCallback, useState , useEffect } from "react";
|
||||
import activate from "../Images/activate.png";
|
||||
import { Blueback , AlignCenter } from "../Component/layout";
|
||||
import PasswordAuthority from "../Component/PasswordAuthority";
|
||||
import styled from "styled-components";
|
||||
import { Form, Input , Spin , Modal } from "antd";
|
||||
import axios from "axios";
|
||||
|
||||
const P = styled.p`{
|
||||
width:200px;
|
||||
line-height:30px;
|
||||
font-size:16px;
|
||||
color:#333;
|
||||
text-align:center;
|
||||
margin-top:30px;
|
||||
margin-bottom:30px!important;
|
||||
}`;
|
||||
function About( props , ref){
|
||||
const { form: { getFieldDecorator , validateFields } } = props;
|
||||
const P = styled.p`
|
||||
{
|
||||
width: 230px;
|
||||
line-height: 30px;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px !important;
|
||||
}
|
||||
`;
|
||||
function About(props, ref) {
|
||||
const { form: { getFieldDecorator, validateFields , setFieldsValue } } = props;
|
||||
const [isSpining, setIsSpining] = useState(true);
|
||||
const [ authorityValBox , setAuthorityValBox ] = useState(false);
|
||||
const [ authorityVal , setAuthorityVal ] = useState(undefined);
|
||||
const [ authorityValFlag , setAuthorityValFlag ] = useState(false);
|
||||
//0: 标识未开启devops
|
||||
//1: 标识用户已填写了云服务器相关信息,但并未开启认证
|
||||
const [step, setStep] = useState(undefined);
|
||||
// step大于1时:为true,不能再修改服务器信息
|
||||
const owner = props.match.params.owner;
|
||||
const projectsId = props.match.params.projectsId;
|
||||
|
||||
|
||||
const AuthorLogin = props.author && props.author.login;
|
||||
const CurrentLogin = props.current_user && props.current_user.login;
|
||||
useEffect(()=>{
|
||||
if(CurrentLogin === AuthorLogin){
|
||||
auth('get');
|
||||
}else{
|
||||
setIsSpining(false);
|
||||
}
|
||||
},[AuthorLogin,CurrentLogin])
|
||||
|
||||
function auth(type){
|
||||
const url = `/${owner}/${projectsId}/ci_authorize.json`;
|
||||
axios({
|
||||
method:`${type}`,
|
||||
url
|
||||
}).then(result=>{
|
||||
if(result && result.data ){
|
||||
setIsSpining(false);
|
||||
setStep(result.data.step);
|
||||
setFieldsValue({...result.data.cloud_account});
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget, isRequired) => (
|
||||
<React.Fragment>
|
||||
<span className={isRequired?"required":""}>{label}</span>
|
||||
<span className={isRequired ? "required" : ""}>{label}</span>
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
</Form.Item>
|
||||
|
|
@ -29,52 +68,122 @@ function About( props , ref){
|
|||
),
|
||||
[]
|
||||
);
|
||||
|
||||
function startActive(){
|
||||
let projectsId = props.match.params.projectsId;
|
||||
validateFields((error,values)=>{
|
||||
if(!error){
|
||||
const url = `/dev_ops/cloud_accounts.json`;
|
||||
axios.post(url,{
|
||||
...values,
|
||||
project_id:projectsId
|
||||
}).then(result=>{
|
||||
if(result && result.data.redirect_url){
|
||||
window.location.href = result.data.redirect_url;
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
// 下一步
|
||||
function goStep() {
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
if(step > 0){
|
||||
setAuthorityValBox(true);
|
||||
}else{
|
||||
setIsSpining(true);
|
||||
const url = `/${owner}/${projectsId}/cloud_accounts.json`;
|
||||
axios.post(url, {...values,ip_num:values.ip}).then((result) => {
|
||||
setIsSpining(false);
|
||||
if (result && result.data.redirect_url) {
|
||||
props.showNotification("服务器信息配置完成!");
|
||||
setStep(1);
|
||||
setAuthorityValBox(true);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
setIsSpining(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 开始激活
|
||||
function startActive(){
|
||||
setIsSpining(true);
|
||||
const url = `/${owner}/${projectsId}/activate.json`;
|
||||
axios.post(url).then(result=>{
|
||||
setIsSpining(false);
|
||||
if(result && result.data.status === 0){
|
||||
props.history.push(`/projects/${owner}/${projectsId}/devops/dispose`);
|
||||
// 需要将顶部的open_devops修改
|
||||
let { changeOpenDevops } = props;
|
||||
changeOpenDevops && changeOpenDevops(true);
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
setIsSpining(false);
|
||||
})
|
||||
}
|
||||
return(
|
||||
<div className="activatePanel">
|
||||
<img src={activate} alt="" width="250px"/>
|
||||
<P>定义DevOps工作流,帮助您检测bug、发布代码…</P>
|
||||
<Link to={""} style={{color:"#5091FF",marginBottom:"20px"}}>了解什么是DevOps?</Link>
|
||||
<Form>
|
||||
{helper(
|
||||
"服务器IP地址:",
|
||||
"ip_num",
|
||||
[{ required: true, message: "请输入服务器IP地址" }],
|
||||
<Input placeholder="请输入服务器IP地址" style={{width:"368px"}} size="large" />,true
|
||||
)}
|
||||
{helper(
|
||||
"服务器用户名:",
|
||||
"account",
|
||||
[{ required: true, message: "请输入服务器用户名" }],
|
||||
<Input placeholder="请输入服务器用户名" size="large" />,true
|
||||
)}
|
||||
{helper(
|
||||
"服务器密码:",
|
||||
"secret",
|
||||
[{ required: true, message: "请输入服务器密码" }],
|
||||
<Input.Password placeholder="请输入服务器密码" size="large" />,true
|
||||
)}
|
||||
</Form>
|
||||
<Blueback onClick={startActive}>开始激活</Blueback>
|
||||
</div>
|
||||
)
|
||||
// 取消授权-登录密码的输入
|
||||
function cancelAuthority(){
|
||||
setAuthorityValBox(false);
|
||||
}
|
||||
// 确认授权
|
||||
function okAuthority(step){
|
||||
setAuthorityValBox(false);
|
||||
setStep(step);
|
||||
}
|
||||
return (
|
||||
<Spin spinning={isSpining}>
|
||||
<PasswordAuthority authorityValBox={authorityValBox} successFunc={okAuthority} cancelFunc={cancelAuthority}></PasswordAuthority>
|
||||
<div className="activatePanel">
|
||||
<img src={activate} alt="" width="250px" />
|
||||
<P>定义DevOps工作流,帮助您检测bug、发布代码…</P>
|
||||
{
|
||||
CurrentLogin !== AuthorLogin && (step === undefined || (step && step < 1)) &&
|
||||
<div className="noOperation">DevOps开启功能暂未对项目创建者以外的角色开放,可以联系项目创建者进行开启,开启后便可查看构建信息。</div>
|
||||
}
|
||||
<a href={"https://forum.trustie.net/forums/3080/detail"} target="_blank" style={{ color: "#5091FF"}}>
|
||||
了解什么是DevOps?
|
||||
</a>
|
||||
<a href={"https://forum.trustie.net/forums/3110/detail"} target="_blank" style={{ color: "#5091FF"}}>
|
||||
如何使用DevOps?
|
||||
</a>
|
||||
{
|
||||
AuthorLogin === CurrentLogin ?
|
||||
<React.Fragment>
|
||||
{ step <=1 ?
|
||||
<React.Fragment>
|
||||
<Input.Password style={{display:'none'}} size="large" />
|
||||
<Form style={{marginTop:"20px"}}>
|
||||
<p className="mb20" style={{width:"370px"}}>请仔细核对您的服务器信息,一旦确认提交将无法修改</p>
|
||||
{helper(
|
||||
"服务器IP地址:",
|
||||
"ip",
|
||||
[{ required: true, message: "请输入服务器IP地址" }],
|
||||
<Input
|
||||
placeholder="请输入服务器IP地址"
|
||||
style={{ width: "368px" }}
|
||||
size="large"
|
||||
disabled={step > 0}
|
||||
/>,
|
||||
true
|
||||
)}
|
||||
{helper(
|
||||
"服务器用户名:",
|
||||
"account",
|
||||
[{ required: true, message: "请输入服务器用户名" }],
|
||||
<Input placeholder="请输入服务器用户名" size="large" disabled={step > 0}/>,
|
||||
true
|
||||
)}
|
||||
{helper(
|
||||
"服务器密码:",
|
||||
"secret",
|
||||
[{ required: true, message: "请输入服务器密码" }],
|
||||
<Input.Password placeholder="请输入服务器密码" size="large" disabled={step > 0}/>,
|
||||
true
|
||||
)}
|
||||
</Form>
|
||||
<Blueback onClick={goStep}>下一步</Blueback>
|
||||
</React.Fragment>
|
||||
:""}
|
||||
{step > 1 &&
|
||||
<div style={{textAlign:'center',marginTop:"20px"}}>
|
||||
<Blueback onClick={startActive} className="mt20">开始激活</Blueback>
|
||||
</div>
|
||||
}
|
||||
</React.Fragment>
|
||||
:""
|
||||
}
|
||||
</div>
|
||||
</Spin>
|
||||
);
|
||||
}
|
||||
export default Form.create()(forwardRef(About));
|
||||
export default Form.create()(forwardRef(About));
|
||||
|
|
|
|||
|
|
@ -1,53 +1,45 @@
|
|||
import React , { useState , useEffect } from 'react';
|
||||
import { Spin } from 'antd';
|
||||
import { Blueback } from '../Component/layout';
|
||||
import Editor from "react-monaco-editor";
|
||||
import Modals from './DisposeModal';
|
||||
import FileLanguage from '../Component/FileLanguage';
|
||||
import FileLanguage from '../Component/OpsFileLanguage';
|
||||
import axios from 'axios';
|
||||
|
||||
|
||||
function Dispose(props){
|
||||
const [ info , setInfo ] = useState(undefined);
|
||||
const [ spining , setSpining ] = useState(true);
|
||||
const [ info , setInfo ] = useState('.trustie-pipeline.yml');
|
||||
const [ visible , setVisible ] = useState(false);
|
||||
const [ ymlValue , setYmlValue ] = useState("");
|
||||
const [ six , setSix ] = useState(undefined);
|
||||
const [ sha , setSha ] = useState(undefined);
|
||||
const [ fileLanguage , setFileLanguage ] = useState(undefined);
|
||||
const [ first , setFirst ] = useState(false);
|
||||
|
||||
let projectsId = props.match.params.projectsId;
|
||||
let owner = props.match.params.owner;
|
||||
|
||||
useEffect(()=>{
|
||||
if(projectsId){
|
||||
const url = '/dev_ops/builds/get_trustie_pipeline.json';
|
||||
const url = `/${owner}/${projectsId}/get_trustie_pipeline.json`;
|
||||
axios.get(url,{
|
||||
params:{
|
||||
project_id:projectsId
|
||||
}
|
||||
}).then(result=>{
|
||||
if(result && result.data.content){
|
||||
setInfo(result.data);
|
||||
setInfo(result.data.name);
|
||||
setYmlValue(result.data.content);
|
||||
setFirst(true);
|
||||
setSha(result.data.sha);
|
||||
}else{
|
||||
setFirst(false);
|
||||
}
|
||||
setSpining(false);
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
},[])
|
||||
|
||||
useEffect(()=>{
|
||||
const url = '/dev_ops/languages/common.json';
|
||||
axios.get(url).then(result=>{
|
||||
if(result){
|
||||
setSix(result.data);
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
},[])
|
||||
},[projectsId])
|
||||
|
||||
// 修改文件内容
|
||||
function changeEditor(value){
|
||||
|
|
@ -57,25 +49,25 @@ function Dispose(props){
|
|||
// 切换语言
|
||||
function select_language(value,array){
|
||||
setFileLanguage(value);
|
||||
// console.log(array);
|
||||
setYmlValue( array && array.content);
|
||||
}
|
||||
|
||||
// 确定提交
|
||||
function submit(){
|
||||
let url = '';
|
||||
const { defaultBranch } = props;
|
||||
let params = {
|
||||
branch: "master",
|
||||
branch: defaultBranch,
|
||||
content:ymlValue,
|
||||
filepath:info && info.name,
|
||||
filepath:info,
|
||||
message:''
|
||||
}
|
||||
if(first){
|
||||
// 为true,则是编辑否则是新建
|
||||
url = `/${owner}/${projectsId}/update_file.json`;
|
||||
url = `/${owner}/${projectsId}/update_trustie_pipeline.json`;
|
||||
axios.put(url,{
|
||||
...params,
|
||||
sha:info && info.sha
|
||||
sha
|
||||
}).then(result=>{
|
||||
if(result){
|
||||
setVisible(true);
|
||||
|
|
@ -95,37 +87,24 @@ function Dispose(props){
|
|||
}
|
||||
}
|
||||
function suresubmit(){
|
||||
props.history.push(`/projects/${owner}/${projectsId}/ops/list`);
|
||||
setVisible(false);
|
||||
props.history.push(`/projects/${owner}/${projectsId}/devops/list`);
|
||||
}
|
||||
|
||||
return(
|
||||
<React.Fragment>
|
||||
<Spin spinning={spining}>
|
||||
<Modals visible={visible} closeFunc={(flag)=>setVisible(flag)} sureFunc={suresubmit}></Modals>
|
||||
<p>编程语言:</p>
|
||||
{
|
||||
six &&
|
||||
<ul className="language">
|
||||
{
|
||||
six && six.map((item,key)=>{
|
||||
return(
|
||||
key < 6 ? <li><img alt="" src={item.cover_url} /></li> : ""
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
|
||||
<div className="mt20 mb20">
|
||||
<FileLanguage language={fileLanguage} select_language={select_language}/>
|
||||
</div>
|
||||
<p>配置脚本:</p>
|
||||
<div className="editorBody">
|
||||
<p className="editorHead">
|
||||
<span>{info && info.name}</span>
|
||||
<a><i className="iconfont icon-bianji6 font-14"></i></a>
|
||||
</p>
|
||||
<p className="editorHead">{info}</p>
|
||||
<Editor
|
||||
height="300px"
|
||||
language={"java"}
|
||||
language={"yml"}
|
||||
theme={"vs-grey"}
|
||||
defaultValue="请输入内容"
|
||||
value={ymlValue}
|
||||
|
|
@ -134,7 +113,7 @@ function Dispose(props){
|
|||
></Editor>
|
||||
</div>
|
||||
<Blueback onClick={submit}>确定提交</Blueback>
|
||||
</React.Fragment>
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
export default Dispose;
|
||||
|
|
@ -8,7 +8,7 @@ const Div = styled.div`{
|
|||
text-align:center;
|
||||
color:#333;
|
||||
}`
|
||||
export default (({visible , closeFunc , suresubmit})=>{
|
||||
export default (({visible , closeFunc , sureFunc})=>{
|
||||
return(
|
||||
<Modal
|
||||
title="提示"
|
||||
|
|
@ -17,7 +17,7 @@ export default (({visible , closeFunc , suresubmit})=>{
|
|||
footer={
|
||||
<div>
|
||||
<Button onClick={()=>closeFunc(false)}>取消</Button>
|
||||
<Button type={"primary"} onClick={suresubmit} style={{marginLeft:"20px"}}>确定</Button>
|
||||
<Button type={"primary"} onClick={()=>sureFunc()} style={{marginLeft:"20px"}}>确定</Button>
|
||||
</div>
|
||||
}
|
||||
onCancel={()=>closeFunc(false)}
|
||||
|
|
|
|||
|
|
@ -18,17 +18,17 @@ export default ((props)=>{
|
|||
return(
|
||||
<WhiteBack className="opsPanel">
|
||||
<Switch {...props}>
|
||||
<Route path="/projects/:projectsId/ops/dispose"
|
||||
<Route path="/projects/:owner/:projectsId/devops/dispose"
|
||||
render={
|
||||
() => (<Infos {...props} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/projects/:projectsId/ops/list"
|
||||
<Route path="/projects/:owner/:projectsId/devops/list"
|
||||
render={
|
||||
() => (<Infos {...props} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/projects/:projectsId/ops"
|
||||
<Route path="/projects/:owner/:projectsId/devops"
|
||||
render={
|
||||
() => (<About {...props} />)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React , { useEffect , useState } from 'react';
|
||||
import React , { useEffect , useState , useRef } from 'react';
|
||||
import { Banner } from '../Component/layout';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
|
|
@ -11,27 +11,46 @@ const Div = styled.div`{
|
|||
padding:24px 30px;
|
||||
}`;
|
||||
export default ((props)=>{
|
||||
const [ menu , setMenu ] = useState(undefined);
|
||||
const [ menu , setMenu ] = useState(false);
|
||||
const [ permission , setPermission ] = useState("");
|
||||
const childRef = useRef();
|
||||
|
||||
const path = props.location.pathname;
|
||||
const owner = props.match.params.owner;
|
||||
const projectsId = props.match.params.projectsId;
|
||||
|
||||
const projectDetail = props.projectDetail;
|
||||
useEffect(()=>{
|
||||
// console.log(props.match.params.projectsId)
|
||||
if(path === `/projects/${props.match.params.projectsId}/ops/list`){
|
||||
if(path === `/projects/${owner}/${projectsId}/devops/list`){
|
||||
setMenu(true);
|
||||
}else{
|
||||
setMenu(false);
|
||||
}
|
||||
},[path])
|
||||
|
||||
useEffect(()=>{
|
||||
if(projectDetail){
|
||||
setPermission(props.projectDetail.permission);
|
||||
}
|
||||
},[projectDetail])
|
||||
|
||||
const updateChildState = () => {
|
||||
// changeVal就是子组件暴露给父组件的方法
|
||||
if (childRef.current) {
|
||||
childRef.current.changeVal();
|
||||
}
|
||||
}
|
||||
|
||||
return(
|
||||
<div className="disposePanel">
|
||||
<Banner>
|
||||
<Link to={`/projects/${props.match.params.projectsId}/ops/dispose`}>工作流配置</Link>
|
||||
{ menu ? <Link to={`/projects/${props.match.params.projectsId}/ops/list`} style={{ marginLeft:"66px",color:"#5091FF" }}>构建列表</Link>:""}
|
||||
{ permission !=="Reporter" && <Link to={`/projects/${owner}/${props.match.params.projectsId}/devops/dispose`} className={menu===false && "color-blue"} style={{ marginRight:"66px"}}>工作流配置</Link>}
|
||||
<Link to={`/projects/${owner}/${props.match.params.projectsId}/devops/list`}className={menu===true && "color-blue"}>构建列表</Link>
|
||||
{ menu===true && <a onClick={updateChildState} style={{float:"right",fontSize:"14px",color:"#FF6E21",marginTop:"5px"}}>刷新</a>}
|
||||
</Banner>
|
||||
<Div>
|
||||
{ menu && menu === true && <Structure {...props}/> }
|
||||
{ menu && menu === false && <Dispost {...props}/> }
|
||||
{ menu === true && <Structure {...props} wrappedComponentRef={(form) => childRef.current = form} ref={childRef}/> }
|
||||
{ menu === false && permission !=="Reporter" && <Dispost {...props}/> }
|
||||
</Div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,42 +1,127 @@
|
|||
import React from 'react';
|
||||
import { FlexAJ , Blueline , AlignCenter } from '../Component/layout';
|
||||
import styled from 'styled-components';
|
||||
import { Menu } from 'antd';
|
||||
import { TagsLine } from '../Component/OpsStatus';
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { FlexAJ, Blueline, AlignCenter } from "../Component/layout";
|
||||
import styled from "styled-components";
|
||||
import { Menu, Popconfirm } from "antd";
|
||||
import { TagsLine } from "../Component/OpsStatus";
|
||||
import { Time } from "../Utils/Time";
|
||||
import { truncateCommitId } from "../common/util";
|
||||
import { getUrl } from 'educoder';
|
||||
|
||||
const SubMenu = Menu.SubMenu;
|
||||
const Img = styled.img`{
|
||||
width:25px;
|
||||
height:25px;
|
||||
border-radius:50%;
|
||||
margin-right:10px;
|
||||
}`
|
||||
export default (()=>{
|
||||
return(
|
||||
const Img = styled.img`
|
||||
{
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border-radius: 50%;
|
||||
margin-right: 10px;
|
||||
}
|
||||
`;
|
||||
export default ({ data, repeatSet , chooseSteps }) => {
|
||||
const [tamp, setTamp] = useState(undefined);
|
||||
const [sha, setSha] = useState(undefined);
|
||||
useEffect(() => {
|
||||
if (data && data.started) {
|
||||
let t = parseInt(data.started) * 1000;
|
||||
let time = Time(t);
|
||||
setTamp(time);
|
||||
}
|
||||
if (data && data.after) {
|
||||
setSha(truncateCommitId(data.after));
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
function renderStatusBtn() {
|
||||
let status = data && data.status;
|
||||
let number = data && data.number;
|
||||
if (status === "failure" || status === "error" || status === "success") {
|
||||
return "";
|
||||
}else if(status === "killed"){
|
||||
return(
|
||||
<Popconfirm
|
||||
title="确认重新构建?"
|
||||
onConfirm={(e) => repeatSet(e,'repeat',number)}
|
||||
onCancel={(e)=>{e.stopPropagation()}}
|
||||
cancelText="取消"
|
||||
okText="确定"
|
||||
>
|
||||
<Blueline onClick={(e)=>{e.stopPropagation()}}>重新构建</Blueline>
|
||||
</Popconfirm>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Popconfirm
|
||||
title="确认撤销构建?"
|
||||
onConfirm={(e) => repeatSet(e,'cancel',number)}
|
||||
onCancel={(e)=>{e.stopPropagation()}}
|
||||
cancelText="取消"
|
||||
okText="确定"
|
||||
>
|
||||
<Blueline onClick={(e)=>{e.stopPropagation()}}>撤销构建</Blueline>
|
||||
</Popconfirm>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function clickSub(e,stageN,stepN){
|
||||
chooseSteps(stageN,stepN);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<FlexAJ className="leftheader">
|
||||
<AlignCenter>
|
||||
<Img src="https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2091711702,2468700162&fm=111&gp=0.jpg"/>
|
||||
<span className="nest">开始时间:<span>2020.07.10 15:30</span></span>
|
||||
<span className="nest">运行时间:<span>20s</span></span>
|
||||
<Img src={getUrl(`/images/${data && data.author && data.author.image_url}`)} />
|
||||
{data && data.started &&
|
||||
<span className="nest">
|
||||
开始时间:<span> {data.started}</span>
|
||||
</span>
|
||||
}
|
||||
{
|
||||
data && data.duration_time &&
|
||||
<span className="nest">
|
||||
运行时间:<span>{data.duration_time}</span>
|
||||
</span>
|
||||
}
|
||||
</AlignCenter>
|
||||
<Blueline>重新创建</Blueline>
|
||||
{renderStatusBtn()}
|
||||
</FlexAJ>
|
||||
<div className="leftMainContent">
|
||||
<AlignCenter className="contentBranch">
|
||||
<i className="iconfont icon-fenzhi1"></i>
|
||||
<span>分支:</span>
|
||||
<span className="branchname">master</span>
|
||||
<span className="branchsha">8b3476f5</span>
|
||||
<span className="branchname">{data && data.branch_target}</span>
|
||||
<span className="branchsha">{data && truncateCommitId(data.build_after_sha)}</span>
|
||||
</AlignCenter>
|
||||
</div>
|
||||
<Menu mode='inline' className="leftMenu">
|
||||
<SubMenu title={<div><i className="iconfont icon-gongzuoliu font-14 mr4"></i><span>CI</span></div>}>
|
||||
<Menu.Item>
|
||||
<FlexAJ><span>Build setup 01 {TagsLine(1)}</span><span>20s</span></FlexAJ>
|
||||
</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu mode="inline" className="leftMenu" defaultOpenKeys={[`0`]} defaultSelectedKeys={[`0`]}>
|
||||
{data && data.stages ? data.stages.map((item, key) => {
|
||||
return item.steps && item.steps.length > 0 ?
|
||||
<SubMenu
|
||||
title={
|
||||
<div>
|
||||
<i className="iconfont icon-gongzuoliu font-14 mr4"></i>
|
||||
<span>{item.name}</span>
|
||||
</div>
|
||||
}
|
||||
key={`${key}`}
|
||||
>
|
||||
{item.steps.map((i, k) => {
|
||||
return (
|
||||
<Menu.Item key={`${k}`} onClick={(e)=>clickSub(e,item.number,i.id)}>
|
||||
<FlexAJ>
|
||||
<span>
|
||||
{i.name} {i.status ? TagsLine(i.status) : ""}
|
||||
</span>
|
||||
<span>{i.duration_time}</span>
|
||||
</FlexAJ>
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</SubMenu>
|
||||
: "";
|
||||
})
|
||||
: ""}
|
||||
</Menu>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,21 +1,107 @@
|
|||
import React from 'react';
|
||||
import { FlexAJ , AlignCenter } from '../Component/layout';
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Spin } from "antd";
|
||||
import { FlexAJ, AlignCenter } from "../Component/layout";
|
||||
import axios from "axios";
|
||||
|
||||
export default (()=>{
|
||||
return(
|
||||
<div className="rightMainContent">
|
||||
<div>
|
||||
<FlexAJ className="items">
|
||||
<span>Build setup 01</span>
|
||||
<AlignCenter>20<i className="iconfont icon-triangle"></i></AlignCenter>
|
||||
</FlexAJ>
|
||||
export default ({
|
||||
data,
|
||||
stepN,
|
||||
stageN,
|
||||
projectId,
|
||||
owner,
|
||||
opsId,
|
||||
rightSpin,
|
||||
}) => {
|
||||
const [coders, setCoders] = useState(undefined);
|
||||
const [empty, setEmpty] = useState(false);
|
||||
const [spining, setSpining] = useState(true);
|
||||
const [stage, setStage] = useState(undefined);
|
||||
const [step, setStep] = useState(undefined);
|
||||
useEffect(() => {
|
||||
setSpining(rightSpin);
|
||||
}, [rightSpin]);
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
let stages = data.stages;
|
||||
if (stages && stages.length > 0) {
|
||||
let pre = stageN
|
||||
? stages.filter((item) => item.number === stageN)[0]
|
||||
: stages[0];
|
||||
setStage(pre);
|
||||
let p = pre && pre.steps;
|
||||
let sub = stepN
|
||||
? p && p.length > 0 && p.filter((item) => item.id === stepN)[0]
|
||||
: p[0];
|
||||
|
||||
setStep(sub);
|
||||
if (sub && sub.status !== "skipped") {
|
||||
getStep(pre.number, sub.number);
|
||||
}
|
||||
// 如果状态是skipped就不用去调用接口查询对应的out信息了
|
||||
if(sub.status === "skipped"){
|
||||
setCoders(undefined);
|
||||
setEmpty(true);
|
||||
setSpining(false);
|
||||
}
|
||||
} else {
|
||||
setSpining(false);
|
||||
}
|
||||
}
|
||||
}, [data, stageN, stepN]);
|
||||
|
||||
function getStep(stageN, stepN) {
|
||||
if (stageN && stepN) {
|
||||
const url = `/${owner}/${projectId}/builds/${opsId}/logs/${stageN}/${stepN}.json`;
|
||||
axios.get(url).then((result) => {
|
||||
if (result) {
|
||||
setCoders(result.data);
|
||||
setSpining(false);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
return (
|
||||
<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 ? (
|
||||
<div className="opsDetailOut">
|
||||
<span>1</span>
|
||||
<p>
|
||||
{stage && stage.name} – {step && step.name}: Skipped
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ color: "red" }}>error:{data && data.error}</div>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<FlexAJ className="items"></FlexAJ>
|
||||
</div>
|
||||
<div>
|
||||
<FlexAJ className="items"></FlexAJ>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
</Spin>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,240 +1,320 @@
|
|||
import React , { useState , useEffect } from 'react';
|
||||
import { FlexAJ , AlignCenter , Blueback } from '../Component/layout';
|
||||
import { Table , Pagination } from 'antd';
|
||||
import { truncateCommitId } from '../common/util';
|
||||
import styled from 'styled-components';
|
||||
import axios from 'axios';
|
||||
import React, { useState, useEffect , useImperativeHandle ,forwardRef } from "react";
|
||||
import { FlexAJ, AlignCenter } from "../Component/layout";
|
||||
import { Table, Pagination, Popconfirm } from "antd";
|
||||
import { truncateCommitId } from "../common/util";
|
||||
import {getUrl} from 'educoder';
|
||||
import axios from "axios";
|
||||
|
||||
const STATUS = [
|
||||
{name:"所有",value:"1"},
|
||||
{name:"准备中",value:"2"},
|
||||
{name:"运行中",value:"3"},
|
||||
{name:"已完成",value:"4"}
|
||||
]
|
||||
const LIMIT = 15;
|
||||
const datasource = [
|
||||
{
|
||||
status:2,
|
||||
author:"caishi",
|
||||
message:{
|
||||
branch:"master",
|
||||
sha:"8b3476f5",
|
||||
image:"https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2034740944,4251903193&fm=26&gp=0.jpg",
|
||||
message:"将分支“ 221063-improve-buy-ci-minutes-link”"
|
||||
},
|
||||
begin:"2020-07-08",
|
||||
run:"20s"
|
||||
},
|
||||
{
|
||||
status:1,
|
||||
author:"caishi",
|
||||
message:{
|
||||
branch:"master",
|
||||
sha:"8b3476f5",
|
||||
image:"https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2034740944,4251903193&fm=26&gp=0.jpg",
|
||||
message:"将分支“ 221063-improve-buy-ci-minutes-link”"
|
||||
},
|
||||
begin:"2020-07-08",
|
||||
run:""
|
||||
}
|
||||
{ name: "所有"},
|
||||
{ name: "运行中", value: "running" },
|
||||
{ name: "已撤销", value: "killed" },
|
||||
{ name: "构建失败", value: "failure" },
|
||||
{ name: "已完成", value: "success" },
|
||||
];
|
||||
const LIMIT = 15;
|
||||
function Structure(props,ref){
|
||||
const [status, setStatus] = useState(undefined);
|
||||
const [page, setPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [data, setData] = useState(undefined);
|
||||
const [tableLoading, setTableLoading] = useState(true);
|
||||
|
||||
const Img = styled.img`{
|
||||
border-radius:50%;
|
||||
margin-rigth:10px;
|
||||
width:25px;
|
||||
height:25px;
|
||||
}`
|
||||
export default ((props)=>{
|
||||
const [ status ,setStatus ] = useState("1");
|
||||
const [ page ,setPage ] = useState(1);
|
||||
const [ total ,setTotal ] = useState(10);
|
||||
const [ data , setData ] = useState(undefined);
|
||||
let projectsId = props.match.params.projectsId;
|
||||
let owner = props.match.params.owner;
|
||||
const permission = props.projectDetail && props.projectDetail.permission;
|
||||
|
||||
let projectsId = props.match.params.projectsId;
|
||||
|
||||
useEffect(()=>{
|
||||
if(projectsId){
|
||||
const url ='/dev_ops/builds.json';
|
||||
axios.get(url,{
|
||||
params:{
|
||||
project_id:projectsId
|
||||
}
|
||||
}).then(result=>{
|
||||
if(result){
|
||||
let list = result.data && result.data.map((item,key)=>{
|
||||
return {
|
||||
status:item.status,
|
||||
author:item.sender,
|
||||
message:{
|
||||
branch:item.source,
|
||||
image:item.author_avatar,
|
||||
message:item.message,
|
||||
sha:truncateCommitId(item.after)
|
||||
},
|
||||
started:item.started,
|
||||
timestamp:item.timestamp
|
||||
}
|
||||
})
|
||||
setData(list);
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
useImperativeHandle(ref, () => ({
|
||||
changeVal: () => {
|
||||
setTableLoading(true);
|
||||
Init();
|
||||
}
|
||||
},[])
|
||||
}))
|
||||
|
||||
function ChangeStatus(value){
|
||||
setStatus(value)
|
||||
useEffect(() => {
|
||||
if (projectsId) {
|
||||
Init();
|
||||
}
|
||||
}, [page]);
|
||||
|
||||
let current_user = props.current_user;
|
||||
function Init(status) {
|
||||
const url = `/${owner}/${projectsId}/builds.json`;
|
||||
axios.get(url,{
|
||||
params:{
|
||||
search:status,
|
||||
page,limit:LIMIT
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result && result.data) {
|
||||
let list = result.data.builds && result.data.builds.map((item, key) => {
|
||||
return {
|
||||
...item,
|
||||
author:item.author && item.author.name,
|
||||
message: {
|
||||
branch: item.branch_target,
|
||||
message: item.message,
|
||||
sha: truncateCommitId(item.build_after_sha),
|
||||
},
|
||||
started: item.started || "--"
|
||||
};
|
||||
});
|
||||
setTotal(result.data.total_count);
|
||||
setData(list);
|
||||
setTableLoading(false);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
function ChangeStatus(value) {
|
||||
setStatus(value);
|
||||
Init(value);
|
||||
}
|
||||
// 切换分页
|
||||
function ChangePage(page){
|
||||
setPage(page)
|
||||
function ChangePage(page) {
|
||||
setPage(page);
|
||||
}
|
||||
function renderStatus() {
|
||||
return(
|
||||
return (
|
||||
<ul className="listNav">
|
||||
{
|
||||
STATUS.map((item,key)=>{
|
||||
return <li onClick={()=>ChangeStatus(item.value)} className={ status === item.value ? "active":""}>{item.name}</li>
|
||||
})
|
||||
}
|
||||
{STATUS.map((item, key) => {
|
||||
return (
|
||||
<li
|
||||
onClick={() => ChangeStatus(item.value)}
|
||||
className={status === item.value ? "active" : ""}
|
||||
>
|
||||
{item.name}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
)
|
||||
);
|
||||
}
|
||||
function renderStatusBtn(status){
|
||||
if(status === "failure" || status ==="success"){
|
||||
function renderStatusBtn(status, number) {
|
||||
if (status === "error" || status === "success") {
|
||||
return "";
|
||||
}else if(status === "killed" || status === "failure"){
|
||||
return(
|
||||
<a className="color-blue">重新构建</a>
|
||||
)
|
||||
}else{
|
||||
return(
|
||||
<a className="color-red">撤销构建</a>
|
||||
)
|
||||
<Popconfirm
|
||||
title="确认重新构建?"
|
||||
onConfirm={(e) => repeatSet(e,number)}
|
||||
onCancel={(e)=>{e.stopPropagation()}}
|
||||
cancelText="取消"
|
||||
okText="确定"
|
||||
>
|
||||
<a className="color-blue" onClick={(e)=>{e.stopPropagation()}}>重新构建</a>
|
||||
</Popconfirm>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Popconfirm
|
||||
title="确认撤销构建?"
|
||||
onConfirm={(e) => cancelSet(e,number)}
|
||||
onCancel={(e)=>{e.stopPropagation()}}
|
||||
cancelText="取消"
|
||||
okText="确定"
|
||||
>
|
||||
<a className="color-red" onClick={(e)=>{e.stopPropagation()}}>撤销构建</a>
|
||||
</Popconfirm>
|
||||
);
|
||||
}
|
||||
}
|
||||
function renderTableStatus (status){
|
||||
switch (status){
|
||||
// 重新构建
|
||||
function repeatSet(e,number) {
|
||||
e.stopPropagation();
|
||||
setTableLoading(true);
|
||||
const url = `/${owner}/${projectsId}/builds/${number}/restart.json`;
|
||||
axios.post(url).then((result) => {
|
||||
if (result) {
|
||||
props.showNotification("工作流正在重新构建!");
|
||||
Init();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
// 撤销构建
|
||||
function cancelSet(e,number) {
|
||||
e.stopPropagation();
|
||||
setTableLoading(true);
|
||||
const url = `/${owner}/${projectsId}/builds/${number}/stop.json`;
|
||||
axios.delete(url).then((result) => {
|
||||
if (result) {
|
||||
props.showNotification("撤销构建成功!");
|
||||
Init(projectsId);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
function renderTableStatus(status) {
|
||||
switch (status) {
|
||||
case "running":
|
||||
return(
|
||||
<span className="statusTag running"><i className="iconfont icon-yunhangzhong"></i>运行中</span>
|
||||
);
|
||||
case "failure":
|
||||
return (
|
||||
<span className="statusTag failed"><i className="iconfont icon-weitongguo"></i>未通过</span>
|
||||
<span className="statusTag running">
|
||||
<i className="iconfont icon-yunhangzhong"></i>运行中
|
||||
</span>
|
||||
);
|
||||
case "failure": case 'error':
|
||||
return (
|
||||
<span className="statusTag failed">
|
||||
<i className="iconfont icon-weitongguo"></i>未通过
|
||||
</span>
|
||||
);
|
||||
case "success":
|
||||
return (
|
||||
<span className="statusTag pass"><i className="iconfont icon-yitongguo"></i>已通过</span>
|
||||
<span className="statusTag pass">
|
||||
<i className="iconfont icon-yitongguo"></i>已通过
|
||||
</span>
|
||||
);
|
||||
default:
|
||||
case 'killed':
|
||||
return (
|
||||
<span className="statusTag Preparing"><i className="iconfont icon-zhunbeizhong"></i>准备中</span>
|
||||
<span className="statusTag killed">
|
||||
<i className="iconfont icon-weitongguo"></i>已撤销
|
||||
</span>
|
||||
);
|
||||
case 'pending':
|
||||
return (
|
||||
<span className="statusTag Preparing">
|
||||
<i className="iconfont icon-zhunbeizhong"></i>准备中
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function clickRows(event,e){
|
||||
props.history.push(`/projects/${owner}/${projectsId}/devops/${e.number}/detail`);
|
||||
}
|
||||
const column = [
|
||||
{
|
||||
title:'序号',
|
||||
dataIndex:"No",
|
||||
key:"No",
|
||||
width:"8%",
|
||||
render:(item,value,key)=>{
|
||||
return(
|
||||
<span>#{key+1}</span>
|
||||
)
|
||||
}
|
||||
title: "序号",
|
||||
dataIndex: "number",
|
||||
key: "number",
|
||||
width: "8%",
|
||||
render: ( value, item, key) => {
|
||||
return <span>#{value}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title:'状态',
|
||||
dataIndex:"status",
|
||||
key:"status",
|
||||
width:"12%",
|
||||
render:(value,item,key)=>{
|
||||
return(renderTableStatus(value))
|
||||
}
|
||||
title: "状态",
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
width: "12%",
|
||||
render: (value, item, key) => {
|
||||
return renderTableStatus(value);
|
||||
},
|
||||
},
|
||||
{
|
||||
title:'构建人',
|
||||
dataIndex:"author",
|
||||
key:"author",
|
||||
width:"12%",
|
||||
align:"center"
|
||||
title: "构建人",
|
||||
dataIndex: "author",
|
||||
key: "author",
|
||||
width: "12%",
|
||||
align: "center",
|
||||
},
|
||||
{
|
||||
title:'提交信息',
|
||||
dataIndex:"message",
|
||||
key:"message",
|
||||
width:"30%",
|
||||
render:(value,item,key)=>{
|
||||
title: "提交信息",
|
||||
dataIndex: "message",
|
||||
key: "message",
|
||||
width: "30%",
|
||||
render: (value, item, key) => {
|
||||
let meg = item.message;
|
||||
return (
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div>
|
||||
{ meg.branch && <span className="mr10 color-grey-8"><i className="iconfont icon-fenzhi1 font-16 mr5"></i>分支{meg.branch}</span>}
|
||||
{ meg.sha && <span className="color-orange">{meg.sha}</span>}
|
||||
{meg.branch && (
|
||||
<span className="mr10 color-grey-8">
|
||||
<i className="iconfont icon-fenzhi1 font-16 mr5"></i>分支
|
||||
{meg.branch}
|
||||
</span>
|
||||
)}
|
||||
{meg.sha && <span className="color-orange">{meg.sha}</span>}
|
||||
</div>
|
||||
<AlignCenter>
|
||||
<Img src={meg.image} />
|
||||
<div className="task-hide ml5" style={{maxWidth:"300px"}}>{meg.message}</div>
|
||||
<img style={{borderRadius:"50%",marginRight:"10px",width:"25px",height:"25px"}} src={`${current_user && getUrl(`/images/${current_user.image_url}`)}`} />
|
||||
<div className="task-hide ml5" style={{ maxWidth: "300px" }}>
|
||||
{meg.message}
|
||||
</div>
|
||||
</AlignCenter>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title:'开始时间',
|
||||
dataIndex:"started",
|
||||
key:"started",
|
||||
width:"15%",
|
||||
render:(value,item,key)=>{
|
||||
return (
|
||||
<span>{value || "--"}</span>
|
||||
)
|
||||
}
|
||||
title: "开始时间",
|
||||
dataIndex: "started",
|
||||
key: "started",
|
||||
width: "15%",
|
||||
render: (value, item, key) => {
|
||||
return <span>{value || "--"}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title:'运行时间',
|
||||
dataIndex:"timestamp",
|
||||
key:"timestamp",
|
||||
width:"15%",
|
||||
render:(value,item,key)=>{
|
||||
return (
|
||||
<span>{value || value === 0 ? `${value}s` : "--"}</span>
|
||||
)
|
||||
}
|
||||
title: "运行时间",
|
||||
dataIndex: "duration_time",
|
||||
key: "duration_time",
|
||||
width: "15%",
|
||||
render: (value, item, key) => {
|
||||
return <span>{value || "--"}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title:'操作',
|
||||
dataIndex:"operation",
|
||||
key:"operation",
|
||||
render:(value,item,key)=>{
|
||||
return(renderStatusBtn(item.status));
|
||||
}
|
||||
}
|
||||
]
|
||||
return(
|
||||
title: "操作",
|
||||
dataIndex: "operation",
|
||||
key: "operation",
|
||||
render: (value, item, key) => {
|
||||
if(permission === "Admin" || permission === "Owner"){
|
||||
return renderStatusBtn(item.status, item.number);
|
||||
}else{
|
||||
return "--";
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div className="listPart">
|
||||
<FlexAJ>
|
||||
{renderStatus()}
|
||||
<span>
|
||||
<Blueback className="mr30">手动创建</Blueback>
|
||||
<span className="mr30"><i className="iconfont icon-fenzhi1 font-16 mr5 color-blue"></i>分支</span>
|
||||
<span><i className="iconfont icon-biaoqian3 font-16 mr5 color-blue"></i>标签</span>
|
||||
</span>
|
||||
{/* <Blueback>手动创建</Blueback> */}
|
||||
{/* <span className="mr30">
|
||||
<i className="iconfont icon-fenzhi1 font-16 mr5 color-blue"></i>分支
|
||||
</span>
|
||||
<span>
|
||||
<i className="iconfont icon-biaoqian3 font-16 mr5 color-blue"></i>
|
||||
标签
|
||||
</span> */}
|
||||
</FlexAJ>
|
||||
<Table
|
||||
onRow={(record,index)=>{
|
||||
return{
|
||||
onClick:(event)=>clickRows(event,record)
|
||||
}
|
||||
}}
|
||||
columns={column}
|
||||
className="normalTable"
|
||||
dataSource={data}
|
||||
pagination={false}
|
||||
loading={tableLoading}
|
||||
></Table>
|
||||
{
|
||||
total > LIMIT ?
|
||||
<div style={{textAlign:'center',margin:"30px 50px"}}>
|
||||
<Pagination showQuickJumper defaultCurrent={page} total={total} pageSize={LIMIT} onChange={ChangePage}></Pagination>
|
||||
</div>:""
|
||||
}
|
||||
{total > LIMIT ?
|
||||
<div style={{ textAlign: "center", margin: "30px 50px" }}>
|
||||
<Pagination
|
||||
showQuickJumper
|
||||
defaultCurrent={page}
|
||||
total={total}
|
||||
pageSize={LIMIT}
|
||||
onChange={ChangePage}
|
||||
></Pagination>
|
||||
</div>
|
||||
:
|
||||
"" }
|
||||
</div>
|
||||
)
|
||||
})
|
||||
);
|
||||
};
|
||||
export default forwardRef(Structure);
|
||||
|
|
|
|||
|
|
@ -12,8 +12,14 @@
|
|||
.disposePanel{
|
||||
.language{
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
li{
|
||||
margin-right: 20px;
|
||||
cursor: pointer;
|
||||
border:1px solid #fff;
|
||||
&.active{
|
||||
border:1px solid #5091FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
.editorBody{
|
||||
|
|
@ -36,6 +42,7 @@
|
|||
top:7px;
|
||||
}
|
||||
.listPart{
|
||||
min-height: 400px;
|
||||
.listNav{
|
||||
display: flex;
|
||||
li{
|
||||
|
|
@ -63,6 +70,7 @@
|
|||
.ant-table-thead > tr > th, .ant-table-tbody > tr > td{
|
||||
padding:10px 5px;
|
||||
color:#333;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ant-table-thead{
|
||||
border:1px solid rgba(238,238,238,1)
|
||||
|
|
@ -70,6 +78,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.ant-modal-close{
|
||||
top:7px;
|
||||
}
|
||||
// 列表
|
||||
.listPart{
|
||||
.statusTag{
|
||||
|
|
@ -103,8 +114,13 @@
|
|||
border:1px solid #F73030;
|
||||
color:#F73030 ;
|
||||
}
|
||||
&.killed{
|
||||
background:#eee;
|
||||
border:1px solid #999;
|
||||
color:#999 ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -205,6 +221,14 @@
|
|||
border:1px solid rgba(255,110,33,1);
|
||||
color:rgba(255,110,33,1);
|
||||
}
|
||||
&.killed{
|
||||
border:1px solid #999;
|
||||
color:#999;
|
||||
}
|
||||
&.skipped{
|
||||
border:1px solid #d4d9de;
|
||||
color:#798390;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.rightSection{
|
||||
|
|
@ -212,6 +236,8 @@
|
|||
background-color: #081930;
|
||||
.rightMainContent{
|
||||
padding:24px 30px;
|
||||
height:100vh;
|
||||
overflow-y: auto;
|
||||
& > div{
|
||||
margin-bottom: 12px;
|
||||
.items{
|
||||
|
|
@ -264,4 +290,27 @@
|
|||
cursor: col-resize;
|
||||
}
|
||||
}
|
||||
}
|
||||
.opsDetailOut{
|
||||
display: flex;
|
||||
color: #fff;
|
||||
line-height: 22px;
|
||||
align-items: flex-start;
|
||||
margin-top: 5px;
|
||||
&>span{
|
||||
margin-right: 10px;
|
||||
min-width: 20px;
|
||||
text-align: left;
|
||||
padding-left: 3px;
|
||||
}
|
||||
&>p{
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
.noOperation{
|
||||
margin-bottom:20px;
|
||||
width:380px;
|
||||
text-align:center;
|
||||
line-height:22px;
|
||||
color:#666;
|
||||
}
|
||||
|
|
@ -1,33 +1,114 @@
|
|||
import React from 'react';
|
||||
import './ops.scss';
|
||||
import { FlexAJ, AlignCenter } from '../Component/layout';
|
||||
import { Tags } from '../Component/OpsStatus';
|
||||
import SplitPane from 'react-split-pane';
|
||||
import LeftPanel from './OpsDetailLeftpanel';
|
||||
import RightPanel from './OpsDetailRightpanel';
|
||||
import React, { useEffect, useState, useRef, useContext } from "react";
|
||||
import "./ops.scss";
|
||||
import { FlexAJ, AlignCenter } from "../Component/layout";
|
||||
import { Tags } from "../Component/OpsStatus";
|
||||
import SplitPane from "react-split-pane";
|
||||
import LeftPanel from "./OpsDetailLeftpanel";
|
||||
import RightPanel from "./OpsDetailRightpanel";
|
||||
import axios from "axios";
|
||||
import { Spin } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export default (props) => {
|
||||
const [data, setData] = useState(undefined);
|
||||
const [stageN, setStageN] = useState(undefined);
|
||||
const [stepN, setStepN] = useState(undefined);
|
||||
const [rightSpin, setRightSpin] = useState(false);
|
||||
const [spinning, setSpinning] = useState(true);
|
||||
|
||||
export default (()=>{
|
||||
return(
|
||||
<div className="opsDetailPanel">
|
||||
<FlexAJ className="opsInfos">
|
||||
<AlignCenter>
|
||||
<span>#1</span>
|
||||
<span className="ml10">将分支“221063-improve-buy-ci-minutes-link”合并到“221063-improve-buy-ci-minutes-link"</span>
|
||||
{Tags(1)}
|
||||
</AlignCenter>
|
||||
<a style={{color:"#ddd"}}><i className="iconfont icon-yiguanbi font-15 mr5"></i>退出</a>
|
||||
</FlexAJ>
|
||||
<div className="opsSection">
|
||||
<SplitPane className="outer-split-pane" split="vertical" minSize={468} maxSize={-350} defaultSize="40%">
|
||||
<section className="leftSection">
|
||||
<LeftPanel />
|
||||
</section>
|
||||
<section className="rightSection">
|
||||
<RightPanel />
|
||||
</section>
|
||||
</SplitPane>
|
||||
let projectId = props.match.params.projectId;
|
||||
let owner = props.match.params.owner;
|
||||
let opsId = props.match.params.opsId;
|
||||
|
||||
useEffect(() => {
|
||||
if (opsId && projectId) {
|
||||
Init();
|
||||
}
|
||||
}, [opsId]);
|
||||
|
||||
function Init() {
|
||||
const url = `/${owner}/${projectId}/builds/${opsId}.json`;
|
||||
axios.get(url).then((result) => {
|
||||
if (result && result.data) {
|
||||
setSpinning(false);
|
||||
setData(result.data);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
setSpinning(false);
|
||||
});
|
||||
}
|
||||
|
||||
// 重新构建
|
||||
function repeatSet(e,type,number) {
|
||||
if(type==="repeat"){
|
||||
// 重新构建
|
||||
const url = `/${owner}/${projectId}/builds/${number}/restart.json`;
|
||||
axios.post(url).then((result) => {
|
||||
if (result && result.data) {
|
||||
props.showNotification("工作流正在重新构建!");
|
||||
props.history.push(`/projects/${owner}/${projectId}/devops/${result.data.number}/detail`);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}else{
|
||||
// 撤销构建
|
||||
const url = `/${owner}/${projectId}/builds/${number}/stop.json`;
|
||||
axios.delete(url).then((result) => {
|
||||
if (result) {
|
||||
props.showNotification("撤销构建成功!");
|
||||
Init();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function chooseSteps(pre,sub){
|
||||
if(pre && sub){
|
||||
setStepN(sub);
|
||||
setStageN(pre);
|
||||
setRightSpin(true);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Spin spinning={spinning}>
|
||||
<div className="opsDetailPanel">
|
||||
<FlexAJ className="opsInfos">
|
||||
<AlignCenter>
|
||||
<span>#{data && data.number}</span>
|
||||
<span className="ml10">{data && data.message}</span>
|
||||
{Tags(`${data && data.status}`)}
|
||||
</AlignCenter>
|
||||
<Link
|
||||
style={{ color: "#ddd" }}
|
||||
to={`/projects/${owner}/${projectId}/devops/list`}
|
||||
>
|
||||
<i className="iconfont icon-yiguanbi font-15 mr5"></i>退出
|
||||
</Link>
|
||||
</FlexAJ>
|
||||
<div className="opsSection">
|
||||
<SplitPane
|
||||
className="outer-split-pane"
|
||||
split="vertical"
|
||||
minSize={468}
|
||||
maxSize={-350}
|
||||
defaultSize="40%"
|
||||
>
|
||||
<section className="leftSection">
|
||||
<LeftPanel data={data} repeatSet={repeatSet} chooseSteps={chooseSteps} />
|
||||
</section>
|
||||
<section className="rightSection">
|
||||
<RightPanel data={data} rightSpin={rightSpin} stepN={stepN} stageN={stageN} owner={owner} projectId={projectId} opsId={opsId} />
|
||||
</section>
|
||||
</SplitPane>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
});
|
||||
</Spin>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 590 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
|
|
@ -32,9 +32,9 @@ export default ((props)=>{
|
|||
return(
|
||||
<li key={key}>
|
||||
<div>
|
||||
<Link to={`/projects/${owner}/${projectsId}?branch=${item.name}`} className="color-blue font-15" style={{"maxWidth":"100px"}}>{item.name}</Link>
|
||||
<Link to={`/projects/${owner}/${projectsId}/branch/${item.name}`} className="color-blue font-15" style={{"maxWidth":"100px"}}>{item.name}</Link>
|
||||
<p className="f-wrap-alignCenter mt15">
|
||||
<span className="mr5 commitKey" style={{marginLeft:0}}>{item.last_commit && truncateCommitId(item.last_commit.sha)}</span>
|
||||
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.last_commit.sha}`)}`} className="mr5 commitKey" style={{marginLeft:0}}>{item.last_commit && truncateCommitId(item.last_commit.sha)}</Link>
|
||||
<span className="color-grey-3 hide-1 messages leftPoint">{item.last_commit && item.last_commit.message}</span>
|
||||
<span className="color-grey-8 ml30">最后更新于{item.last_commit && item.last_commit.time_from_now}</span>
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React , { Component } from 'react';
|
||||
import { Spin , Pagination } from 'antd';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import { truncateCommitId } from '../common/util'
|
||||
import { truncateCommitId } from '../common/util';
|
||||
import SelectBranch from '../Branch/Select';
|
||||
import Nodata from '../Nodata';
|
||||
|
||||
|
|
@ -12,7 +12,6 @@ class CoderRootCommit extends Component{
|
|||
constructor(props){
|
||||
super(props)
|
||||
this.state={
|
||||
branch:"master",
|
||||
commitDatas:undefined,
|
||||
dataCount:undefined,
|
||||
limit:20,
|
||||
|
|
@ -22,11 +21,23 @@ class CoderRootCommit extends Component{
|
|||
}
|
||||
|
||||
componentDidMount=()=>{
|
||||
const { branch , page , limit } = this.state;
|
||||
this.Init();
|
||||
}
|
||||
|
||||
componentDidUpdate=(prevProps)=>{
|
||||
const { location } = this.props;
|
||||
const prevlocation = prevProps && prevProps.location;
|
||||
if (location !== prevlocation) {
|
||||
this.Init();
|
||||
}
|
||||
}
|
||||
Init =()=>{
|
||||
const { branchName } = this.props.match.params;
|
||||
const { page , limit } = this.state;
|
||||
this.setState({
|
||||
isSpining:true
|
||||
})
|
||||
this.getCommitList( branch , page , limit );
|
||||
this.getCommitList( branchName , page , limit );
|
||||
}
|
||||
|
||||
getCommitList=(branch , page , limit)=>{
|
||||
|
|
@ -68,26 +79,28 @@ class CoderRootCommit extends Component{
|
|||
|
||||
// 切换分支 search:tag为根据标签搜索
|
||||
changeBranch=(value)=>{
|
||||
const { page , limit } = this.state;
|
||||
const { getTopCount } = this.props;
|
||||
this.setState({
|
||||
isSpining:true,
|
||||
branch:value,
|
||||
})
|
||||
this.getCommitList(value , page , limit);
|
||||
getTopCount && getTopCount(value);
|
||||
// const { page , limit } = this.state;
|
||||
// const { getTopCount } = this.props;
|
||||
// this.setState({
|
||||
// isSpining:true,
|
||||
// branch:value,
|
||||
// })
|
||||
// this.getCommitList(value , page , limit);
|
||||
// getTopCount && getTopCount(value);
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
this.props.history.push(`/projects/${owner}/${projectsId}/commits/branch/${value}`);
|
||||
}
|
||||
|
||||
ChangePage=(page)=>{
|
||||
|
||||
const { branch , limit } = this.state;
|
||||
this.getCommitList(branch , page , limit);
|
||||
const { branchName } = this.props.match.params;
|
||||
const { limit } = this.state;
|
||||
this.getCommitList(branchName , page , limit);
|
||||
}
|
||||
render(){
|
||||
const { branch , commitDatas , dataCount , limit , page , isSpining } = this.state;
|
||||
const { branchs , projectDetail, commit_class } = this.props;
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
|
||||
const { commitDatas , dataCount , limit , page , isSpining } = this.state;
|
||||
const { projectDetail, commit_class , defaultBranch } = this.props;
|
||||
const { projectsId , owner , branchName } = this.props.match.params;
|
||||
let branch = branchName || defaultBranch;
|
||||
return(
|
||||
<React.Fragment>
|
||||
<div className={commit_class}>
|
||||
|
|
@ -98,6 +111,7 @@ class CoderRootCommit extends Component{
|
|||
branch={branch}
|
||||
changeBranch={this.changeBranch}
|
||||
owner={owner}
|
||||
history={this.props.history}
|
||||
></SelectBranch>
|
||||
</div>
|
||||
<Spin spinning={isSpining}>
|
||||
|
|
@ -113,8 +127,8 @@ class CoderRootCommit extends Component{
|
|||
return(
|
||||
<div key={k}>
|
||||
<p className="f-wrap-alignCenter">
|
||||
<span className="commitKey" style={{marginLeft:0}}>{truncateCommitId(`${item.sha}`)}</span>
|
||||
<span className="flex1 ml20 font-16 color-grey-3">{item.message}</span>
|
||||
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="commitKey" style={{marginLeft:0}}>{truncateCommitId(`${item.sha}`)}</Link>
|
||||
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="flex1 ml20 font-16 color-grey-3">{item.message}</Link>
|
||||
</p>
|
||||
<p className="f-wrap-alignCenter mt15">
|
||||
<Link to={`/users/${item.login}`} className="show-user-link">
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import Nodata from '../Nodata';
|
|||
import axios from "axios";
|
||||
/**
|
||||
* address:http和SSH,http_url(对应git地址)
|
||||
* branch:当前分支
|
||||
* filePath:点击目录时当前目录的路径
|
||||
* subfileType:保存当前点击目录的文件类型(显示目录列表时才显示新建文件,如果点击的是文件就不显示新建文件按钮)
|
||||
* readMeContent:根目录下面的readme文件内容
|
||||
|
|
@ -34,7 +33,6 @@ class CoderRootDirectory extends Component {
|
|||
super(props);
|
||||
this.state = {
|
||||
address: "http",
|
||||
branch: "master",
|
||||
filePath: undefined,
|
||||
subFileType: undefined,
|
||||
readMeContent: undefined,
|
||||
|
|
@ -79,32 +77,27 @@ class CoderRootDirectory extends Component {
|
|||
|
||||
Init = () => {
|
||||
let { search } = this.props.history.location;
|
||||
let branchName = undefined;
|
||||
if (search && search.indexOf("?branch=") > -1) {
|
||||
branchName = search.split("?branch=")[1];
|
||||
this.setState({
|
||||
branch: branchName,
|
||||
});
|
||||
}
|
||||
if (search && search.indexOf("?url=") > -1) {
|
||||
let url = search.split("?url=")[1];
|
||||
this.setState({
|
||||
filePath: decodeURI(url),
|
||||
});
|
||||
this.getFileDetail(decodeURI(url));
|
||||
const { branchName } = this.props.match.params;
|
||||
const { defaultBranch } = this.props;
|
||||
let branch = branchName || defaultBranch;
|
||||
if (search && (search.indexOf("?url=") > -1 || search.indexOf("&url=") > -1)) {
|
||||
let url = search.split("url=")[1];
|
||||
if(url && decodeURI(url).indexOf("&")){
|
||||
url=decodeURI(url).split("&")[0];
|
||||
}
|
||||
this.getFileDetail(decodeURI(url),branch);
|
||||
} else {
|
||||
const { branch } = this.state;
|
||||
this.getProjectRoot(branchName || branch);
|
||||
this.getProjectRoot(branch);
|
||||
}
|
||||
};
|
||||
|
||||
// 页面地址返回到主目录
|
||||
returnMain = (branch) => {
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
const { projectsId , owner , branchName } = this.props.match.params;
|
||||
this.setState({
|
||||
readOnly:true
|
||||
})
|
||||
this.props.history.push(`/projects/${owner}/${projectsId}`);
|
||||
this.props.history.push(`/projects/${owner}/${projectsId}${branchName?`/branch/${branchName}`:""}`);
|
||||
this.getProjectRoot(branch);
|
||||
};
|
||||
|
||||
|
|
@ -182,48 +175,55 @@ class CoderRootDirectory extends Component {
|
|||
|
||||
// 获取子目录
|
||||
getFileDetail = (path, ref) => {
|
||||
const { projectsId ,owner } = this.props.match.params;
|
||||
const { branch } = this.state;
|
||||
this.setState({
|
||||
filePath: decodeURI(path),
|
||||
});
|
||||
const { projectsId , owner , branchName } = this.props.match.params;
|
||||
const { chooseType } = this.state;
|
||||
const url = `/${owner}/${projectsId}/sub_entries.json`;
|
||||
|
||||
axios.get(url,{
|
||||
params:{
|
||||
filepath:path,
|
||||
ref:ref || branch
|
||||
ref:ref || branchName,
|
||||
type:chooseType
|
||||
}
|
||||
}).then((result)=>{
|
||||
let entries = result.data && result.data.entries;
|
||||
this.setState({
|
||||
isSpin:false
|
||||
})
|
||||
if( entries && entries.length > 0){
|
||||
let { chooseType } = this.state;
|
||||
// 当前返回的子目录只有一条数据,且这条数据返回的是文件类型
|
||||
if(entries.length === 1 && entries[0].type === "file" && chooseType ==="file"){
|
||||
this.setState({
|
||||
fileDetail:entries,
|
||||
rootList:undefined,
|
||||
subFileType:false
|
||||
})
|
||||
if(result){
|
||||
if(entries){
|
||||
// 返回对象entries.type则是文件类型,否则是文件夹
|
||||
if(entries.type){
|
||||
this.setState({
|
||||
fileDetail:[entries],
|
||||
rootList:undefined,
|
||||
subFileType:false
|
||||
})
|
||||
}else{
|
||||
this.setState({
|
||||
fileDetail:undefined,
|
||||
rootList:entries,
|
||||
branchLastCommit:result.data.last_commit && result.data.last_commit.commit,
|
||||
lastCommitAuthor:result.data.last_commit && (result.data.last_commit.author || (result.data.last_commit.commit && result.data.last_commit.commit.author))
|
||||
})
|
||||
this.renderData(entries);
|
||||
}
|
||||
}else{
|
||||
this.setState({
|
||||
fileDetail:undefined,
|
||||
rootList:entries,
|
||||
branchLastCommit:result.data.last_commit && result.data.last_commit.commit,
|
||||
lastCommitAuthor:result.data.last_commit && (result.data.last_commit.author || (result.data.last_commit.commit && result.data.last_commit.commit.author))
|
||||
rootList:undefined,
|
||||
isSpin:false,
|
||||
subFileType:false
|
||||
})
|
||||
this.renderData(entries);
|
||||
}
|
||||
}else{
|
||||
this.setState({
|
||||
fileDetail:undefined,
|
||||
rootList:undefined,
|
||||
isSpin:false,
|
||||
subFileType:false
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({
|
||||
isSpin:false
|
||||
})
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
|
@ -255,8 +255,8 @@ class CoderRootDirectory extends Component {
|
|||
this.setState({
|
||||
chooseType:type
|
||||
})
|
||||
const { projectsId, owner } = this.props.match.params;
|
||||
this.props.history.push(`/projects/${owner}/${projectsId}?url=${path}`);
|
||||
const { projectsId, owner , branchName } = this.props.match.params;
|
||||
this.props.history.push(`/projects/${owner}/${projectsId}${branchName?`/branch/${branchName}`:""}?url=${path}`);
|
||||
if(filename.substring(filename.length - 3) === ".md"){
|
||||
this.setState({
|
||||
md:true
|
||||
|
|
@ -309,24 +309,18 @@ class CoderRootDirectory extends Component {
|
|||
|
||||
// 选择分支
|
||||
changeBranch = (value) => {
|
||||
this.setState({
|
||||
branch: value,
|
||||
isSpin: true,
|
||||
readOnly:true
|
||||
});
|
||||
const { getTopCount } = this.props;
|
||||
getTopCount && getTopCount(value);
|
||||
|
||||
let { search } = this.props.history.location;
|
||||
if (search && search.indexOf("?url=") > -1) {
|
||||
let url = search.split("?url=")[1];
|
||||
this.setState({
|
||||
filePath: decodeURI(url),
|
||||
});
|
||||
this.getFileDetail(decodeURI(url), value);
|
||||
} else {
|
||||
this.getProjectRoot(value);
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
|
||||
let url = `/projects/${owner}/${projectsId}${value && `/branch/${value}`}`;
|
||||
if (search && (search.indexOf("?url=") > -1 || search.indexOf("&url=") > -1)) {
|
||||
let u = search.split("url=")[1];
|
||||
if(u && decodeURI(u).indexOf("&")){
|
||||
u=decodeURI(u).split("&")[0];
|
||||
}
|
||||
url += `?url=${u}`;
|
||||
}
|
||||
this.props.history.push(url);
|
||||
}
|
||||
|
||||
// 子目录路径返回链接
|
||||
|
|
@ -364,6 +358,7 @@ class CoderRootDirectory extends Component {
|
|||
|
||||
title = (branchLastCommit,lastCommitAuthor) => {
|
||||
if (branchLastCommit) {
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
return (
|
||||
<div className="f-wrap-alignCenter">
|
||||
{lastCommitAuthor ? (
|
||||
|
|
@ -389,13 +384,13 @@ class CoderRootDirectory extends Component {
|
|||
) : (
|
||||
""
|
||||
)}
|
||||
<span className="color-blue flex-1 hide-1">
|
||||
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${branchLastCommit.sha}`)}`} className="color-blue flex-1 hide-1">
|
||||
{branchLastCommit.message}
|
||||
</span>
|
||||
</Link>
|
||||
<span>{branchLastCommit.time_from_now}</span>
|
||||
<span className="commitKey">
|
||||
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${branchLastCommit.sha}`)}`} className="commitKey">
|
||||
{truncateCommitId(branchLastCommit.sha)}
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}else{
|
||||
|
|
@ -404,31 +399,36 @@ class CoderRootDirectory extends Component {
|
|||
}
|
||||
|
||||
render(){
|
||||
const { branchLastCommit , lastCommitAuthor , rootList , branch ,filePath , fileDetail , subFileType , readMeContent, isSpin , zip_url , tar_url} = this.state;
|
||||
const { isManager , isDeveloper , projectDetail } = this.props;
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
const { branchLastCommit , lastCommitAuthor , rootList ,filePath , fileDetail , subFileType , readMeContent, isSpin , zip_url , tar_url} = this.state;
|
||||
const { isManager , isDeveloper , projectDetail , platform , defaultBranch } = this.props;
|
||||
|
||||
const { projectsId , owner , branchName } = this.props.match.params;
|
||||
let branch = branchName || defaultBranch;
|
||||
const columns = [
|
||||
{
|
||||
key:"name",
|
||||
dataIndex: 'name',
|
||||
width:"30%",
|
||||
render: (text,item) => (
|
||||
<a onClick={()=>this.goToSubRoot(item.path,item.type,text)} className="ml12 task-hide" style={{ display: "block", maxWidth: "345px" }}>
|
||||
<i className={ item.type === "file" ? "iconfont icon-wenjia font-15 color-green-file mr5":"iconfont icon-wenjianjia1 color-green-file font-15 mr5"}></i>{text}
|
||||
<i className={ item.type === "file" ? "iconfont icon-wenjia font-15 color-green-file mr5" : "iconfont icon-wenjianjia1 color-green-file font-15 mr5"}></i>{text}
|
||||
</a>
|
||||
),
|
||||
},
|
||||
{
|
||||
dataIndex: "commit",
|
||||
key:"message",
|
||||
dataIndex: "message",
|
||||
width: "60%",
|
||||
render: (text, item) =>
|
||||
item.commit && item.commit.message ?
|
||||
<span title={item.commit.message} className="task-hide" style={{ display: "block", maxWidth: "670px" }} >
|
||||
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.commit.sha}`)}`} title={item.commit.message} className="task-hide" style={{ display: "block", maxWidth: "670px" }} >
|
||||
{item.commit.message}
|
||||
</span>
|
||||
</Link>
|
||||
: ""
|
||||
},
|
||||
{
|
||||
dataIndex: "commit",
|
||||
key:"time_from_now",
|
||||
dataIndex: "time_from_now",
|
||||
width: "10%",
|
||||
className: "edu-txt-right",
|
||||
render: (text, item) =>
|
||||
|
|
@ -447,13 +447,20 @@ class CoderRootDirectory extends Component {
|
|||
<div className="main">
|
||||
<div className="f-wrap-between mb20">
|
||||
<div className="f-wrap-alignCenter">
|
||||
<SelectBranch
|
||||
repo_id={projectDetail && projectDetail.repo_id}
|
||||
projectsId={projectsId}
|
||||
branch={branch}
|
||||
changeBranch={this.changeBranch}
|
||||
owner={owner}
|
||||
></SelectBranch>
|
||||
{
|
||||
platform ?
|
||||
<SelectBranch
|
||||
repo_id={projectDetail && projectDetail.repo_id}
|
||||
projectsId={projectsId}
|
||||
branch={branch}
|
||||
changeBranch={this.changeBranch}
|
||||
owner={owner}
|
||||
history={this.props.history}
|
||||
></SelectBranch>
|
||||
:
|
||||
<span>分支:<span className="color-grey-6">master</span></span>
|
||||
}
|
||||
|
||||
|
||||
{filePath && (
|
||||
<span className="ml20 font-16">
|
||||
|
|
@ -480,7 +487,7 @@ class CoderRootDirectory extends Component {
|
|||
)}
|
||||
</div>
|
||||
<div className="f-wrap-alignCenter">
|
||||
{subFileType && (projectDetail && parseInt(projectDetail.type)) !== 2 && (isManager || isDeveloper) && (
|
||||
{subFileType && (projectDetail && parseInt(projectDetail.type)) !== 2 && (isManager || isDeveloper) && platform && (
|
||||
<div>
|
||||
<span>
|
||||
<Link to={`/projects/${owner}/${projectsId}/${branch}/uploadfile${urlRoot}`} >
|
||||
|
|
@ -527,7 +534,6 @@ class CoderRootDirectory extends Component {
|
|||
{
|
||||
!rootList && !fileDetail && <Nodata _html="暂未发现当前文件!"/>
|
||||
}
|
||||
{/* readme.txt (isManager || isDeveloper)*/}
|
||||
{ rootList && this.renderReadMeContent(readMeContent, isManager || isDeveloper)}
|
||||
</div>
|
||||
</Spin>
|
||||
|
|
|
|||
|
|
@ -165,12 +165,12 @@ class CoderRootFileDetail extends Component {
|
|||
isManager,
|
||||
isDeveloper,
|
||||
md,
|
||||
currentBranch
|
||||
currentBranch,
|
||||
platform
|
||||
} = this.props;
|
||||
const { language, languages, description } = this.state;
|
||||
let flag = current_user && current_user.login && (isManager || isDeveloper);
|
||||
const Option = Select.Option;
|
||||
|
||||
return (
|
||||
<div className="mb20">
|
||||
<div className="grid-item branchTitle">
|
||||
|
|
@ -180,7 +180,7 @@ class CoderRootFileDetail extends Component {
|
|||
</span>
|
||||
</div>
|
||||
<p className="text-right">
|
||||
{flag && (
|
||||
{flag && platform && (
|
||||
<div>
|
||||
{readOnly ? (
|
||||
<span>
|
||||
|
|
|
|||
|
|
@ -55,12 +55,20 @@ class CoderRootIndex extends Component{
|
|||
}
|
||||
|
||||
componentDidMount=()=>{
|
||||
let { search } = this.props.history.location;
|
||||
let branchName = undefined;
|
||||
if (search && search.indexOf("?branch=") > -1) {
|
||||
branchName = search.split("?branch=")[1];
|
||||
this.Init();
|
||||
}
|
||||
componentDidUpdate=(prevProps)=>{
|
||||
const { location } = this.props;
|
||||
const prevlocation = prevProps && prevProps.location;
|
||||
if (location !== prevlocation) {
|
||||
this.Init();
|
||||
}
|
||||
this.getTopCount(branchName);
|
||||
}
|
||||
|
||||
Init=()=>{
|
||||
const { branchName } = this.props.match.params;
|
||||
const { defaultBranch } = this.props;
|
||||
this.getTopCount(branchName || defaultBranch);
|
||||
}
|
||||
|
||||
getTopCount=(branch)=>{
|
||||
|
|
@ -97,17 +105,23 @@ class CoderRootIndex extends Component{
|
|||
(props) => (<FileNew {...this.props} {...props} {...this.state} getTopCount={this.getTopCount} />)
|
||||
}
|
||||
></Route>
|
||||
|
||||
{/* diff */}
|
||||
<Route path="/projects/:owner/:projectsId/commits/branch/:branchName"
|
||||
render={
|
||||
(props) => (<CoderRootCommit {...this.props} {...props} {...this.state} commit_class="main" getTopCount={this.getTopCount} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/projects/:owner/:projectsId/commits/:sha"
|
||||
render={
|
||||
(props) => (<Diff {...this.props} {...props} {...this.state}/>)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/projects/:owner/:projectsId/commits"
|
||||
render={
|
||||
() => (<CoderRootCommit {...this.props} {...this.state} commit_class="main" getTopCount={this.getTopCount} />)
|
||||
}
|
||||
></Route>
|
||||
{/* diff */}
|
||||
<Route path="/projects/:owner/:projectsId/diff/:sha"
|
||||
render={
|
||||
() => (<Diff {...this.props} {...this.state}/>)
|
||||
}
|
||||
></Route>
|
||||
|
||||
<Route path="/projects/:owner/:projectsId/releases/:versionId/update"
|
||||
render={
|
||||
|
|
@ -125,12 +139,18 @@ class CoderRootIndex extends Component{
|
|||
() => (<CoderRootVersion {...this.props} {...this.state} />)
|
||||
}
|
||||
></Route>
|
||||
|
||||
<Route path="/projects/:owner/:projectsId/tag"
|
||||
render={
|
||||
() => (<CoderRootTag {...this.props} {...this.state} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/projects/:owner/:projectsId/branch"
|
||||
<Route path="/projects/:owner/:projectsId/branch/:branchName"
|
||||
render={
|
||||
(props) => (<CoderRootDirectory {...this.props} {...this.state} getTopCount={this.getTopCount} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/projects/:owner/:projectsId/branchs"
|
||||
render={
|
||||
() => (<CoderRootBranch {...this.props} {...this.state} />)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,12 @@ import axios from 'axios';
|
|||
import { Spin } from 'antd';
|
||||
import { truncateCommitId } from '../common/util';
|
||||
import Nodata from '../Nodata';
|
||||
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
export default (( props, { projectDetail }) => {
|
||||
const [isSpin, setSpin] = useState(true);
|
||||
const [data, setData] = useState(undefined);
|
||||
|
||||
const repo_id = projectDetail && projectDetail.repo_id;
|
||||
const { projectsId , owner } = props.match.params;
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -49,7 +48,7 @@ export default (( props, { projectDetail }) => {
|
|||
<span className="font-16">{item.name}</span>
|
||||
</span>
|
||||
<span className="ul_tbody_third">
|
||||
<span className="commitKey" style={{ "marginLeft": 0 }}>{truncateCommitId(`${item.id}`)}</span>
|
||||
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.id}`)}`} className="commitKey" style={{ "marginLeft": 0 }}>{truncateCommitId(`${item.id}`)}</Link>
|
||||
</span>
|
||||
<span className="ul_tbody_forth">
|
||||
<a href={item.tarball_url} style={{ color: "#4CC1DA" }} className="mr30"><i className="iconfont icon-TAR font-18 mr5"></i>TAR</a>
|
||||
|
|
|
|||
|
|
@ -140,6 +140,8 @@ function checkPathname(pathname){
|
|||
name="activity"
|
||||
}else if(pathname.indexOf("/setting")>-1){
|
||||
name="setting"
|
||||
}else if(pathname.indexOf("/devops")>-1){
|
||||
name="devops"
|
||||
}
|
||||
}
|
||||
return name;
|
||||
|
|
@ -165,6 +167,12 @@ class Detail extends Component {
|
|||
project: null,
|
||||
firstSync:false,
|
||||
secondSync:false,
|
||||
open_devops:false,
|
||||
// 默认分支
|
||||
defaultBranch:undefined,
|
||||
|
||||
// 非本平台项目
|
||||
platform:false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -186,8 +194,22 @@ class Detail extends Component {
|
|||
axios.get(url).then((result) => {
|
||||
if (result && result.data) {
|
||||
this.setState({
|
||||
project: result.data
|
||||
project: result.data,
|
||||
open_devops:result.data.open_devops,
|
||||
platform:result.data.platform && result.data.platform !== 'educoder'
|
||||
})
|
||||
|
||||
// 工作流:两种状态进入的链接不同
|
||||
const pathname = this.props.history.location.pathname;
|
||||
let p = checkPathname(pathname);
|
||||
if(p==="devops"){
|
||||
if(result.data.open_devops && pathname === `/projects/${owner}/${projectsId}/devops`){
|
||||
this.props.history.push(`/projects/${owner}/${projectsId}/devops/list`);
|
||||
}else if(result.data.open_devops===false && pathname !== `/projects/${owner}/${projectsId}/devops`){
|
||||
this.props.history.push(`/projects/${owner}/${projectsId}/devops`);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.data.type !== 0 && result.data.mirror_status === 1) {
|
||||
console.log("--------start channel --------");
|
||||
// 是镜像项目,且未完成迁移
|
||||
|
|
@ -213,6 +235,13 @@ class Detail extends Component {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 工作流激活后修改状态
|
||||
changeOpenDevops=(flag)=>{
|
||||
this.setState({
|
||||
open_devops:flag
|
||||
})
|
||||
}
|
||||
canvasChannel = () => {
|
||||
const name = window.location.hostname === "localhost" ? "testforgeplus.trustie.net" : window.location.hostname;
|
||||
const actioncable = require("actioncable");
|
||||
|
|
@ -240,11 +269,11 @@ class Detail extends Component {
|
|||
const { projectsId , owner } = this.props.match.params;
|
||||
const url = `/${owner}/${projectsId}.json`;
|
||||
axios.get(url).then((result) => {
|
||||
if (result) {
|
||||
if (result && result.data) {
|
||||
this.setState({
|
||||
projectDetail: result.data,
|
||||
project_id: result.data.project_id,
|
||||
isManager: result.data.permission && (result.data.permission === "Manager"|| result.data.permission === "Admin" || result.data.permission === "Owner"),
|
||||
isManager: result.data.permission && (result.data.permission === "Manager" || result.data.permission === "Admin" || result.data.permission === "Owner"),
|
||||
isReporter: result.data.permission && result.data.permission === "Reporter",
|
||||
isDeveloper: result.data.permission && result.data.permission === "Developer",
|
||||
http_url: result.data.clone_url,
|
||||
|
|
@ -254,6 +283,7 @@ class Detail extends Component {
|
|||
watchers_count: result.data.watchers_count,
|
||||
praises_count: result.data.praises_count,
|
||||
forked_count: result.data.forked_count,
|
||||
defaultBranch:result.data.default_branch
|
||||
})
|
||||
}
|
||||
}).catch((error) => { })
|
||||
|
|
@ -261,8 +291,10 @@ class Detail extends Component {
|
|||
|
||||
// 关注和取消关注
|
||||
focusFunc = (flag) => {
|
||||
const { project_id } = this.state;
|
||||
const { platform } = this.state;
|
||||
if(!platform)return;
|
||||
|
||||
const { project_id } = this.state;
|
||||
axios({
|
||||
method: flag ? 'delete' : 'post',
|
||||
url: `/watchers/${flag ? 'unfollow' : 'follow'}.json`,
|
||||
|
|
@ -282,6 +314,8 @@ class Detail extends Component {
|
|||
|
||||
// 点赞和取消点赞
|
||||
pariseFunc = (flag) => {
|
||||
const { platform } = this.state;
|
||||
if(!platform)return;
|
||||
const { project_id } = this.state;
|
||||
axios({
|
||||
method: flag ? 'delete' : 'post',
|
||||
|
|
@ -312,6 +346,8 @@ class Detail extends Component {
|
|||
|
||||
// fork项目
|
||||
forkFunc = () => {
|
||||
const { platform } = this.state;
|
||||
if(!platform)return;
|
||||
const { current_user } = this.props
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
const url = `/${owner}/${projectsId}/forks.json`;
|
||||
|
|
@ -327,6 +363,8 @@ class Detail extends Component {
|
|||
|
||||
// 同步镜像
|
||||
synchronismMirror = () => {
|
||||
const { platform } = this.state;
|
||||
if(!platform)return;
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
const url = `/${owner}/${projectsId}/sync_mirror.json`;
|
||||
axios.post(url).then(result => {
|
||||
|
|
@ -343,7 +381,10 @@ class Detail extends Component {
|
|||
|
||||
|
||||
render() {
|
||||
const { projectDetail, watchers_count, praises_count, forked_count, firstSync , secondSync , isManager, watched, praised, project } = this.state;
|
||||
const { projectDetail, watchers_count, praises_count,
|
||||
forked_count, firstSync , secondSync ,
|
||||
isManager, watched, praised,
|
||||
project , open_devops , platform , defaultBranch } = this.state;
|
||||
const url = this.props.history.location.pathname;
|
||||
const urlArr = url.split("/");
|
||||
const urlFlag = (urlArr.length === 3);
|
||||
|
|
@ -352,8 +393,6 @@ class Detail extends Component {
|
|||
const { projectsId , owner } = this.props.match.params;
|
||||
|
||||
const { state } = this.props.history.location;
|
||||
const { current_user } = this.props;
|
||||
const checkLogin = current_user && current_user.login;
|
||||
|
||||
const text = (
|
||||
projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ?
|
||||
|
|
@ -365,9 +404,10 @@ class Detail extends Component {
|
|||
</React.Fragment> : ""
|
||||
);
|
||||
|
||||
|
||||
const common = {
|
||||
getDetail: this.getDetail
|
||||
getDetail: this.getDetail,
|
||||
changeOpenDevops:this.changeOpenDevops,
|
||||
defaultBranch
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
|
|
@ -397,10 +437,11 @@ class Detail extends Component {
|
|||
projectDetail.type === 2 ?
|
||||
<Tooltip title={"镜像自: " + projectDetail.mirror_url} className="ml5" placement={'right'}>
|
||||
<i className="iconfont icon-banbenku font-18 mt6" style={{ color: "#8D90E3" }}/>
|
||||
</Tooltip>:
|
||||
</Tooltip>
|
||||
:
|
||||
<Tooltip title={"镜像自: " + projectDetail.mirror_url} className="ml5" placement={'right'}>
|
||||
<i className="iconfont icon-jingxiang font-18 color-green mt6" />
|
||||
</Tooltip>
|
||||
<i className="iconfont icon-jingxiang font-18 color-green mt6" />
|
||||
</Tooltip>
|
||||
:""
|
||||
}
|
||||
</span>
|
||||
|
|
@ -413,30 +454,45 @@ class Detail extends Component {
|
|||
<a className="synchronism ml30" onClick={this.synchronismMirror}>同步镜像</a> : ""
|
||||
}
|
||||
<span className="detail_tag_btn">
|
||||
<a className="detail_tag_btn_name" onClick={() => this.focusFunc(watched)}>
|
||||
<a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={() => this.focusFunc(watched)}>
|
||||
<i className={watched ? "iconfont icon-shixing color-orange font-16 mr3":"iconfont icon-kongxing color-grey-9 font-16 mr3"}></i>
|
||||
<span>{watched ? '取消关注' : '关注'}</span>
|
||||
</a>
|
||||
<Link className="detail_tag_btn_count" style={{color:`${watched?"#2878FF":"#666"}`}} to={{ pathname: `/projects/${owner}/${projectsId}/watchers`, state }}>
|
||||
{watchers_count}
|
||||
</Link>
|
||||
{
|
||||
platform ?
|
||||
<Link className="detail_tag_btn_count" style={{color:`${watched?"#2878FF":"#666"}`}} to={platform?{ pathname: `/projects/${owner}/${projectsId}/watchers`, state }:""}>
|
||||
{watchers_count}
|
||||
</Link>
|
||||
:
|
||||
<span className="detail_tag_btn_count">{watchers_count}</span>
|
||||
}
|
||||
|
||||
</span>
|
||||
<span className="detail_tag_btn">
|
||||
<a className="detail_tag_btn_name" onClick={() => this.pariseFunc(praised)}>
|
||||
<a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={() => this.pariseFunc(praised)}>
|
||||
<i className={praised ? "iconfont icon-weibiaoti105 color-orange font-14 mr3":"iconfont icon-guanzhu color-grey-9 font-14 mr3"}></i>
|
||||
<span>{praised ? '取消点赞' : '点赞'}</span>
|
||||
</a>
|
||||
<Link className="detail_tag_btn_count" style={{color:`${praised?"#2878FF":"#666"}`}} to={{ pathname: `/projects/${owner}/${projectsId}/stargazers`, state }}>
|
||||
{praises_count}
|
||||
</Link>
|
||||
{
|
||||
platform ?
|
||||
<Link className="detail_tag_btn_count" style={{color:`${praised?"#2878FF":"#666"}`}} to={{ pathname: `/projects/${owner}/${projectsId}/stargazers`, state }}>
|
||||
{praises_count}
|
||||
</Link>:
|
||||
<span className="detail_tag_btn_count">{praises_count}</span>
|
||||
}
|
||||
</span>
|
||||
<span className="detail_tag_btn">
|
||||
<a className="detail_tag_btn_name" onClick={this.forkFunc}>
|
||||
<a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={this.forkFunc}>
|
||||
<i className="iconfont icon-fork color-grey-9 mr3"></i>Fork
|
||||
</a>
|
||||
<Link className="detail_tag_btn_count" to={{ pathname: `/projects/${owner}/${projectsId}/fork_users`, state }}>
|
||||
{forked_count}
|
||||
</Link>
|
||||
{
|
||||
platform ?
|
||||
<Link className="detail_tag_btn_count" to={{ pathname: `/projects/${owner}/${projectsId}/fork_users`, state }}>
|
||||
{forked_count}
|
||||
</Link>
|
||||
:
|
||||
<span className="detail_tag_btn_count">{praises_count}</span>
|
||||
}
|
||||
</span>
|
||||
</span>
|
||||
}
|
||||
|
|
@ -465,7 +521,7 @@ class Detail extends Component {
|
|||
</Link>
|
||||
</li>
|
||||
{
|
||||
projectDetail && parseInt(projectDetail.type) !== 2 &&
|
||||
projectDetail && parseInt(projectDetail.type) !== 2 && platform &&
|
||||
<li className={pathname==="pulls" ? "active" : ""}>
|
||||
<Link to={{ pathname: `/projects/${owner}/${projectsId}/pulls`, state }}>
|
||||
<i className={pathname==="pulls" ? "iconfont icon-hebingqingqiu1 color-grey-3 mr5 font-14":"iconfont icon-hebingqingqiu1 color-grey-6 font-14 mr5"}></i>
|
||||
|
|
@ -474,12 +530,16 @@ class Detail extends Component {
|
|||
</Link>
|
||||
</li>
|
||||
}
|
||||
{/* <li className={url.indexOf("/ops") > -1 ? "active" : ""}>
|
||||
<Link to={{ pathname: `/projects/${owner}/${projectsId}/ops`, state }}>
|
||||
<i className="iconfont icon-gongzuoliu font-13 mr8"></i>工作流
|
||||
{projectDetail && projectDetail.ops_count ? <span>{projectDetail.ops_count}</span> : ""}
|
||||
</Link>
|
||||
</li> */}
|
||||
{
|
||||
platform &&
|
||||
<li className={pathname==="devops" ? "active" : ""}>
|
||||
<Link to={{ pathname: `/projects/${owner}/${projectsId}/devops${open_devops ? `/list`:""}`, state }}>
|
||||
<i className="iconfont icon-gongzuoliu font-13 mr8"></i>工作流(beta版)
|
||||
{projectDetail && projectDetail.ops_count ? <span>{projectDetail.ops_count}</span> : ""}
|
||||
</Link>
|
||||
</li>
|
||||
}
|
||||
|
||||
<li className={pathname==="milestones" ? "active" : ""}>
|
||||
<Link to={{ pathname: `/projects/${owner}/${projectsId}/milestones`, state }}>
|
||||
<i className={pathname==="milestones" ? "iconfont icon-lichengbei color-grey-3 mr5 font-14":"iconfont icon-lichengbei color-grey-6 font-14 mr5"}></i>
|
||||
|
|
@ -494,7 +554,7 @@ class Detail extends Component {
|
|||
</Link>
|
||||
</li>
|
||||
{
|
||||
isManager &&
|
||||
isManager && platform &&
|
||||
<li className={url.indexOf("/setting") > 0 ? "active" : ""}>
|
||||
<Link to={`/projects/${owner}/${projectsId}/setting`}>
|
||||
<i className={url.indexOf("/setting") > 0 ? "iconfont icon-cangku color-grey-3 mr5 font-14":"iconfont icon-cangku color-grey-6 font-14 mr5"}></i>
|
||||
|
|
@ -523,7 +583,7 @@ class Detail extends Component {
|
|||
}
|
||||
></Route>
|
||||
{/* 工作流 */}
|
||||
<Route path="/projects/:owner/:projectsId/ops"
|
||||
<Route path="/projects/:owner/:projectsId/devops"
|
||||
render={
|
||||
() => (<DevIndex {...this.props} {...this.state} {...common} />)
|
||||
}
|
||||
|
|
@ -652,6 +712,16 @@ class Detail extends Component {
|
|||
(props) => (<ForkUsers {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/projects/:owner/:projectsId/commits/branch/:branchName"
|
||||
render={
|
||||
(props) => (<CoderRootIndex {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/projects/:owner/:projectsId/branch/:branchName"
|
||||
render={
|
||||
(props) => (<CoderRootIndex {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/projects/:owner/:projectsId"
|
||||
render={
|
||||
(props) => (<CoderRootIndex {...this.props} {...props} {...this.state} {...common} />)
|
||||
|
|
|
|||
|
|
@ -3,27 +3,53 @@ import { Link } from 'react-router-dom';
|
|||
|
||||
class DetailTop extends Component {
|
||||
render() {
|
||||
const { coderCount } = this.props;
|
||||
const { coderCount , platform } = this.props;
|
||||
const { projectsId, owner } = this.props.match.params;
|
||||
const { pathname } = this.props.location;
|
||||
return (
|
||||
<p className="branch-wrapper">
|
||||
<Link to={`/projects/${owner}/${projectsId}/commits`} className={pathname.indexOf("/commits") > 0 ? "active" : ""}>
|
||||
<i className="iconfont icon-tijiaojilu font-20 mr3 font-bd"></i>
|
||||
<span>{(coderCount && coderCount.commits_count) || 0}</span>个提交
|
||||
</Link>
|
||||
<Link to={`/projects/${owner}/${projectsId}/branch`} className={pathname.indexOf("/branch") > 0 ? "active" : ""}>
|
||||
<i className="iconfont icon-fenzhi1 font-18 mr3"></i>
|
||||
<span>{(coderCount && coderCount.branches_count) || 0}</span>个分支
|
||||
</Link>
|
||||
<Link to={`/projects/${owner}/${projectsId}/tag`} className={pathname.indexOf("/tag") > 0 ? "active" : ""}>
|
||||
<i className="iconfont icon-biaoqian3 font-18 mr3"></i>
|
||||
<span>{(coderCount && coderCount.tags_count) || 0}</span>个标签
|
||||
</Link>
|
||||
<Link to={`/projects/${owner}/${projectsId}/releases`} className={pathname.indexOf("/releases") > 0 ? "active" : ""}>
|
||||
<i className="iconfont icon-fahangban font-18 mr3"></i>
|
||||
<span>{(coderCount && coderCount.version_releasesed_count) || 0}</span>个发行版
|
||||
</Link>
|
||||
|
||||
{
|
||||
platform ?
|
||||
<React.Fragment>
|
||||
<Link to={`/projects/${owner}/${projectsId}/commits`} className={pathname.indexOf("/commits") > 0 ? "active" : ""}>
|
||||
<i className="iconfont icon-tijiaojilu font-20 mr3 font-bd"></i>
|
||||
<span>{(coderCount && coderCount.commits_count) || 0}</span>个提交
|
||||
</Link>
|
||||
<Link to={`/projects/${owner}/${projectsId}/branchs`} className={pathname.indexOf("/branchs") > 0 ? "active" : ""}>
|
||||
<i className="iconfont icon-fenzhi1 font-18 mr3"></i>
|
||||
<span>{(coderCount && coderCount.branches_count) || 0}</span>个分支
|
||||
</Link>
|
||||
<Link to={`/projects/${owner}/${projectsId}/tag`} className={pathname.indexOf("/tag") > 0 ? "active" : ""}>
|
||||
<i className="iconfont icon-biaoqian3 font-18 mr3"></i>
|
||||
<span>{(coderCount && coderCount.tags_count) || 0}</span>个标签
|
||||
</Link>
|
||||
<Link to={`/projects/${owner}/${projectsId}/releases`} className={pathname.indexOf("/releases") > 0 ? "active" : ""}>
|
||||
<i className="iconfont icon-fahangban font-18 mr3"></i>
|
||||
<span>{(coderCount && coderCount.version_releasesed_count) || 0}</span>个发行版
|
||||
</Link>
|
||||
</React.Fragment>
|
||||
:
|
||||
<React.Fragment>
|
||||
<a href="javscript:void(0)" style={{cursor:"default"}}>
|
||||
<i className="iconfont icon-tijiaojilu font-20 mr3 font-bd"></i>
|
||||
<span>{(coderCount && coderCount.commits_count) || 0}</span>个提交
|
||||
</a>
|
||||
<a href="javscript:void(0)" style={{cursor:"default"}}>
|
||||
<i className="iconfont icon-fenzhi1 font-18 mr3"></i>
|
||||
<span>{(coderCount && coderCount.branches_count) || 0}</span>个分支
|
||||
</a>
|
||||
<a href="javscript:void(0)" style={{cursor:"default"}}>
|
||||
<i className="iconfont icon-biaoqian3 font-18 mr3"></i>
|
||||
<span>{(coderCount && coderCount.tags_count) || 0}</span>个标签
|
||||
</a>
|
||||
<a href="javscript:void(0)" style={{cursor:"default"}}>
|
||||
<i className="iconfont icon-fahangban font-18 mr3"></i>
|
||||
<span>{(coderCount && coderCount.version_releasesed_count) || 0}</span>个发行版
|
||||
</a>
|
||||
</React.Fragment>
|
||||
}
|
||||
|
||||
<a href="javscript:void(0)" style={{cursor:"default"}}>
|
||||
<i className="iconfont icon-cangku font-18 mr3"></i>
|
||||
仓库 <span className="ml3">{(coderCount && coderCount.size) || 0}</span>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import React, { useEffect, useState } from "react";
|
|||
import styled from "styled-components";
|
||||
import { Button ,Spin } from "antd";
|
||||
import { truncateCommitId } from '../common/util';
|
||||
import Nodata from '../Nodata';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import Files from '../Merge/Files';
|
||||
|
||||
import User from "../Component/User";
|
||||
import Keys from "../Component/Keys";
|
||||
|
|
@ -11,65 +12,34 @@ import axios from "axios";
|
|||
|
||||
const Infos = styled.div`
|
||||
border: 1px solid #dddddd;
|
||||
margin-bottom:15px;
|
||||
& .commitinfos {
|
||||
background-color: #f1f8ff;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding: 20px;
|
||||
}
|
||||
& > .f-wrap-between {
|
||||
padding: 10px 24px;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
`;
|
||||
const Operation = styled.p`
|
||||
border-bottom: 1px solid #eee;
|
||||
padding: 12px 0px;
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const FileUl = styled.ul`
|
||||
padding-top: 10px;
|
||||
& li {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
`;
|
||||
const DetailP = styled.p`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 20px 12px 12px;
|
||||
background-color: #fafafa;
|
||||
border: 1px solid #dddddd;
|
||||
`;
|
||||
|
||||
export default ({ projectDetail, match }) => {
|
||||
export default ({ match , history }) => {
|
||||
const [data, setData] = useState({undefined});
|
||||
const [commit, setCommit] = useState(undefined);
|
||||
const [files, setFiles] = useState(undefined);
|
||||
const [parents, setParents] = useState(undefined);
|
||||
const [committer, setCommitter] = useState(undefined);
|
||||
const [fileflag , setFileflag] = useState(false);
|
||||
const [isSpin, setIsSpin] = useState(true);
|
||||
|
||||
const repo_id = projectDetail && projectDetail.repo_id;
|
||||
const { sha } = match.params;
|
||||
const { sha , projectsId, owner } = match.params;
|
||||
useEffect(() => {
|
||||
if (repo_id && sha) {
|
||||
const url = `/repositories/${repo_id}/commits/${sha}.json`;
|
||||
if (projectsId && owner && sha) {
|
||||
const url = `/${owner}/${projectsId}/commits/${sha}.json`;
|
||||
axios
|
||||
.get(url)
|
||||
.then(result => {
|
||||
if (result) {
|
||||
setData(result.data);
|
||||
setCommit(result.data.commit);
|
||||
setFiles(result.data.files);
|
||||
setParents(result.data.parents);
|
||||
setCommitter(result.data.committer || (result.data.commit && result.data.commit.committer));
|
||||
setIsSpin(false);
|
||||
|
|
@ -79,78 +49,32 @@ export default ({ projectDetail, match }) => {
|
|||
console.log(error);
|
||||
});
|
||||
}
|
||||
}, [repo_id, sha]);
|
||||
const renderFiles = () => {
|
||||
return (
|
||||
<FileUl>
|
||||
{
|
||||
files && files.length > 0 && files.map((item,key)=>{
|
||||
return(
|
||||
<li>
|
||||
<span className="mr30 task-hide flex1">
|
||||
<i className="iconfont icon-wenjia color-grey-3 font-16 mr8"></i>
|
||||
{item.Name}
|
||||
</span>
|
||||
<span>
|
||||
<label className="color-green mr20">+{item.Addition}</label>
|
||||
<label className="color-red">-{item.Deletion}</label>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</FileUl>
|
||||
);
|
||||
};
|
||||
|
||||
function changeFlag(){
|
||||
let flag = !fileflag;
|
||||
setFileflag(flag);
|
||||
}
|
||||
|
||||
const filesDetail = () => {
|
||||
return (
|
||||
<div>
|
||||
<DetailP>
|
||||
<span>
|
||||
<i className="iconfont icon-youjiantou mr4 font-15 color-grey-9"></i>
|
||||
<span className="font-16 color-grey-3">README.md</span>
|
||||
</span>
|
||||
<Button>查看文件</Button>
|
||||
</DetailP>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
}, [projectsId , owner, sha]);
|
||||
return (
|
||||
<div className="main">
|
||||
<Spin spinning={isSpin}>
|
||||
<Infos>
|
||||
<div className="commitinfos">
|
||||
<p className="f-wrap-between">
|
||||
<span className="font-20 color-grey-3">
|
||||
{ commit && commit.title }
|
||||
</span>
|
||||
<Button type="primary">浏览代码</Button>
|
||||
</p>
|
||||
{commit && commit.message ? (
|
||||
<pre className="mt10">{commit.message}</pre>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<div className="f-wrap-between">
|
||||
{commit && commit.message &&
|
||||
<pre className="task-hide" style={{marginBottom:"0px",height:"28px",whiteSpace:"pre-wrap"}}>{commit.message}</pre>
|
||||
}
|
||||
<Button type="primary" onClick={()=>{history.push(`/projects/${owner}/${projectsId}/branch/${truncateCommitId(sha)}`)}} className="ml30">浏览代码</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="f-wrap-between" style={{ alignItems: "center" }}>
|
||||
<ul className="df">
|
||||
<User
|
||||
url={(committer && committer.image_url)|| "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"}
|
||||
url={(committer && getImageUrl(`images/${committer.image_url}`))|| "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"}
|
||||
name={committer && committer.name}
|
||||
/>
|
||||
{committer && committer.time_from_now && <li className="ml20 mt2">{committer.time_from_now}</li>}
|
||||
</ul>
|
||||
<li className="df">
|
||||
{
|
||||
parents && parents.length > 0 && parents.map((item,key)=>{
|
||||
return(
|
||||
<Keys title="父节点" value={truncateCommitId(item.sha) } className="mr20"></Keys>
|
||||
<Keys title="父节点" value={truncateCommitId(item.sha)} key={key} className="mr20"></Keys>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -158,35 +82,12 @@ export default ({ projectDetail, match }) => {
|
|||
</li>
|
||||
</div>
|
||||
</Infos>
|
||||
{
|
||||
files && files.length > 0 ?
|
||||
<React.Fragment>
|
||||
<Operation>
|
||||
<span className="files_info" onClick={changeFlag}>
|
||||
<i className={fileflag ? "iconfont icon-sanjiaoxing-down mr8 color-grey-9 font-16":"iconfont icon-triangle mr8 color-grey-9 font-16"}></i>
|
||||
<span className="color-grey-9">
|
||||
共有<span>{files && files.length}个文件被更改</span>,包括
|
||||
{data && data.additions ? (
|
||||
<span className="color-green">{data.additions}次插入</span>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
{data && data.additions && data.deletions ? "和" : ""}
|
||||
{data && data.deletions ? (
|
||||
<span className="color-red">{data.deletions}次删除</span>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
<Button>双栏查看</Button>
|
||||
</Operation>
|
||||
{fileflag && renderFiles()}
|
||||
{filesDetail()}
|
||||
</React.Fragment>
|
||||
:
|
||||
<Nodata _html="暂无文件修改信息!"/>
|
||||
}
|
||||
<Files
|
||||
history={history}
|
||||
data={data}
|
||||
owner={owner}
|
||||
projectsId={projectsId}
|
||||
/>
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ class Index extends Component {
|
|||
</div>
|
||||
<div className="baseInfo">
|
||||
<span className="look"><i className="iconfont icon-dianjiliang font-12"></i>{item.visits}</span>
|
||||
<span className="type">项目类型:{item.category && item.category.name}</span>
|
||||
<span className="type">{item.category && item.category.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,9 +20,16 @@ class IndexItem extends Component {
|
|||
projects && projects.length > 0 ? projects.map((item, key) => {
|
||||
return (
|
||||
<div className="p-r-Item" key={key}>
|
||||
<Link to={`/users/${item.author.login}`} className="show-user-link">
|
||||
<img className="p-r-photo" alt="" src={getImage(`${item.author && item.author.image_url}`)} ></img>
|
||||
</Link>
|
||||
{
|
||||
item.platform === "educoder" ?
|
||||
<a href="javascript:void(0)" style={{cursor:"default"}} className="show-user-link">
|
||||
<img className="p-r-photo" alt="" src={item.author && item.author.image_url} ></img>
|
||||
</a>
|
||||
:
|
||||
<Link to={`/users/${item.author.login}`} className="show-user-link">
|
||||
<img className="p-r-photo" alt="" src={getImageUrl(`${item.author && item.author.image_url}`)} ></img>
|
||||
</Link>
|
||||
}
|
||||
<div className="p-r-Infos">
|
||||
<div className="p-r-name">
|
||||
<Link to={`/projects/${item.author.login}/${item.identifier}`} className="hide-1 color-grey-3 font-18 task-hide " style={{ whiteSpace: "wrap", display: 'flex', width: 400 }}>
|
||||
|
|
@ -46,16 +53,16 @@ class IndexItem extends Component {
|
|||
}
|
||||
</Link>
|
||||
<span className="p-r-tags">
|
||||
<span className="pariseTag"><img src={img_parise} alt="" className="pariseImg" />赞 ({item.praises_count})</span>
|
||||
<span><i className="iconfont icon-fork mr3 font-16" style={{ color: "#1B8FFF" }} />fork ({item.forked_count})</span>
|
||||
<span className="pariseTag"><img src={img_parise} alt="" className="pariseImg" />赞 {item.praises_count}</span>
|
||||
<span><i className="iconfont icon-fork mr3 font-16" style={{ color: "#1B8FFF" }} />fork {item.forked_count}</span>
|
||||
</span>
|
||||
</div>
|
||||
<p className="break_word task-hide-2 mt10" style={{ maxHeight: "44px",lineHeight:"22px" }}>{item.description}</p>
|
||||
|
||||
<div className="p-r-about">
|
||||
<span className="p-r-detail">
|
||||
<span><label>浏览量:</label>{item.visits}</span>
|
||||
{item.category && item.category.id && <span><label>项目类别:</label>{item.category.name}</span>}
|
||||
{/* <span><label>浏览量:</label>{item.visits}</span> */}
|
||||
{/* {item.category && item.category.id && <span>{item.category.name}</span>} */}
|
||||
{item.last_update_time ? <span ><label>更新于</label>{item.time_ago}</span> : ""}
|
||||
{item.language && item.language.id ? <span className="color-grey-3">{item.language.name}</span> : ""}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@
|
|||
}
|
||||
.detail_tag_btn_name{
|
||||
padding:0px 10px;
|
||||
color: #666;
|
||||
color: #666!important;
|
||||
}
|
||||
.detail_tag_btn_name img{
|
||||
margin-right: 10px;
|
||||
|
|
@ -294,6 +294,7 @@
|
|||
.branch-wrapper > a >i{
|
||||
color: #5091FF;
|
||||
margin-right: 5px;
|
||||
cursor: default;
|
||||
}
|
||||
.branch-wrapper a{
|
||||
display: flex;
|
||||
|
|
@ -411,6 +412,7 @@
|
|||
padding: 13px 16px!important;
|
||||
}
|
||||
.commitKey{
|
||||
cursor: pointer;
|
||||
border:1px solid #FD7700;
|
||||
background-color:#FFF3DC;
|
||||
color: #FD7700!important;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
import React from 'react';
|
||||
import { AlignCenter , FlexAJ } from '../Component/layout';
|
||||
import User from '../Component/User';
|
||||
import { truncateCommitId } from '../common/util';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
function Commits({ commits , projectsId , owner }){
|
||||
return(
|
||||
<div className="pb20">
|
||||
{
|
||||
commits.map((item,key)=>{
|
||||
return(
|
||||
<div className="prCommits">
|
||||
<p className="prCreate">{item.created_at}</p>
|
||||
<div className="prInfo">
|
||||
<FlexAJ>
|
||||
<AlignCenter>
|
||||
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="commitKey" style={{marginLeft:0}}>{truncateCommitId(`${item.sha}`)}</Link>
|
||||
<p className="ml15 font-16 color-grey-3 task-hide" style={{maxWidth:"700px"}}>{item.message}</p>
|
||||
</AlignCenter>
|
||||
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(item.sha)}`} className="color-blue">浏览代码</Link>
|
||||
</FlexAJ>
|
||||
<AlignCenter className="mt15">
|
||||
<User url={getImageUrl(`images/${item.committer && item.committer.image_url}`)} name={`${item.committer && item.committer.name}`}></User><span>:提交于{item.time_from_now}</span>
|
||||
</AlignCenter>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Commits;
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
import React ,{useEffect,useState } from 'react';
|
||||
import { truncateCommitId } from '../common/util';
|
||||
import { AlignCenter , FlexAJ } from '../Component/layout';
|
||||
import { Button } from 'antd';
|
||||
import './merge.css';
|
||||
|
||||
function Files({data,history,owner,projectsId}){
|
||||
const [ files , setFiles ] = useState(data && data.files);
|
||||
|
||||
useEffect(()=>{
|
||||
if(data){
|
||||
setFiles(data.files);
|
||||
}
|
||||
},[data])
|
||||
|
||||
function showDown(flag,index,isBin){
|
||||
if(!isBin){
|
||||
var lists = files.concat();
|
||||
lists[index].flag = !flag ? true : false;
|
||||
lists.splice();
|
||||
setFiles(lists);
|
||||
}
|
||||
}
|
||||
|
||||
return(
|
||||
<div>
|
||||
<AlignCenter className="color-grey-9 pb10" style={{borderBottom:"1px solid #eee"}}>
|
||||
<i className="iconfont icon-sanjiaoxing-down mr5"></i>
|
||||
<span>
|
||||
共有<span className="color-grey-3"> {data && data.files_count} 个文件被更改</span>,包括
|
||||
{ data && data.total_addition ? <span className="color-green"> {data && data.total_addition} 次插入</span>:"" }
|
||||
{ data && data.total_addition && data.total_deletion ? " 和 ":""}
|
||||
{ data && data.total_deletion ? <span className="color-red"> {data && data.total_deletion} 次删除</span>:""}
|
||||
</span>
|
||||
</AlignCenter>
|
||||
{
|
||||
files && files.length>0 &&
|
||||
<div>
|
||||
{
|
||||
files.map((item,key)=>{
|
||||
return(
|
||||
<div className="files" key={key}>
|
||||
<FlexAJ className="filesInfo" style={{cursor:item.isBin ? "default":"pointer"}} onClick={()=>showDown(item.flag,key,item.isBin)}>
|
||||
<AlignCenter>
|
||||
{!item.isBin ? <i className={!item.flag?"iconfont icon-xiajiantou font-16 mr15 color-grey-9":"iconfont icon-youjiantou font-16 mr15 color-grey-9"}></i>:""}
|
||||
<i className="iconfont icon-wenjia font-16 mr8 color-grey-9"></i>
|
||||
<span>{item.name}</span>
|
||||
</AlignCenter>
|
||||
<span>
|
||||
<Button className="mr20" onClick={()=>{history.push(`/projects/${owner}/${projectsId}${item.sha ? `/branch/${truncateCommitId(item.sha)}?`:"?"}url=${item.name}`)}}>查看文件</Button>
|
||||
<span className="color-green">+{item.addition}</span>
|
||||
<span className="color-red ml20">-{item.deletion}</span>
|
||||
</span>
|
||||
</FlexAJ>
|
||||
{
|
||||
item.sections && item.sections.length >= 1 && !item.flag &&
|
||||
<div className="filesContent">
|
||||
{
|
||||
item.sections.map((i,k)=>{
|
||||
return(
|
||||
i.lines && i.lines.length>0 && i.lines.map((item,key)=>{
|
||||
return(
|
||||
<div key={k+key} className={(item.type === 2) ? "linesContent add" : item.type === 3 ? "linesContent reduce": item.type===4?"linesContent translate":"linesContent"}>
|
||||
<span className="lines">
|
||||
<span>{item.leftIdx && item.leftIdx !=="0" ? item.leftIdx :"" }</span>
|
||||
<span>{item.rightIdx && item.rightIdx !=="0" ? item.rightIdx :"" }</span>
|
||||
</span>
|
||||
<p>{item.content}</p>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Files;
|
||||
|
|
@ -214,7 +214,7 @@ class MergeDetail extends Component {
|
|||
)
|
||||
} else {
|
||||
return (
|
||||
<NoneData _html="暂时还没有相关数据哦!" />
|
||||
<NoneData _html="暂时还没有相关数据!" />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ class MergeItem extends Component {
|
|||
<span className="ml15">
|
||||
<Tag className="pr-branch-tag">
|
||||
<Link
|
||||
to={`/projects/${item.is_original ? item.fork_project_user : owner}/${ item.is_original ? item.fork_project_identifier : projectsId }?branch=${item.pull_request_head}`}
|
||||
to={`/projects/${item.is_original ? item.fork_project_user : owner}/${ item.is_original ? item.fork_project_identifier : projectsId }/branch/${item.pull_request_head}`}
|
||||
className="maxW200px hide-1 ver-middle"
|
||||
>
|
||||
{item.is_original
|
||||
|
|
@ -116,7 +116,7 @@ class MergeItem extends Component {
|
|||
</span>
|
||||
<Tag className="pr-branch-tag">
|
||||
<Link
|
||||
to={`/projects/${owner}/${projectsId}?branch=${item.pull_request_base}`}
|
||||
to={`/projects/${owner}/${projectsId}/branch/${item.pull_request_base}`}
|
||||
className="maxW200px hide-1 ver-middle"
|
||||
>
|
||||
{/* {item.is_fork ? item.pull_request_base : `${item.author_name}:${item.pull_request_base}`} */}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import axios from 'axios';
|
|||
import{ Form , Table , Spin } from 'antd'
|
||||
import { getImageUrl } from 'educoder';
|
||||
import {Link} from "react-router-dom";
|
||||
import { truncateCommitId} from '../common/util';
|
||||
class MergeSubmit extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
|
@ -36,7 +37,6 @@ class MergeSubmit extends Component{
|
|||
}
|
||||
|
||||
getDetail=()=>{
|
||||
|
||||
const { projectsId , mergeId, owner} = this.props.match.params;
|
||||
const url = `/projects/${owner}/${projectsId}/pull_requests/${mergeId}.json`;
|
||||
axios.get(url).then((result)=>{
|
||||
|
|
@ -83,8 +83,16 @@ class MergeSubmit extends Component{
|
|||
}).catch((error)=>{console.log(error)})
|
||||
}
|
||||
|
||||
title =()=>{
|
||||
return(
|
||||
<div className="f-wrap-between" style={{alignItems:"center"}}>
|
||||
<span className="font-16">提交列表</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
render(){
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
const { titledata } = this.state;
|
||||
const columns=[{
|
||||
title:"作者",
|
||||
|
|
@ -102,7 +110,7 @@ class MergeSubmit extends Component{
|
|||
title:"SHA",
|
||||
dataIndex: 'sha',
|
||||
render: (text) => (
|
||||
<span className="commitKey">{text}</span>
|
||||
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${text}`)}`} className="commitKey">{text}</Link>
|
||||
)
|
||||
},{
|
||||
title:"备注",
|
||||
|
|
@ -118,14 +126,6 @@ class MergeSubmit extends Component{
|
|||
<span>{text}</span>
|
||||
)
|
||||
}]
|
||||
|
||||
const title =()=>{
|
||||
return(
|
||||
<div className="f-wrap-between" style={{alignItems:"center"}}>
|
||||
<span className="font-16">提交列表</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return(
|
||||
<Spin spinning={this.state.isSpin}>
|
||||
|
|
@ -136,11 +136,9 @@ class MergeSubmit extends Component{
|
|||
showHeader={false}
|
||||
size="small"
|
||||
pagination={false}
|
||||
title={() => title()}
|
||||
title={() => this.title()}
|
||||
/>
|
||||
</Spin>
|
||||
// </div>
|
||||
// </div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React, { Component } from "react";
|
||||
import { Tabs } from 'antd';
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import { AlignCenter } from '../Component/layout';
|
||||
import axios from "axios";
|
||||
import { getImageUrl } from "educoder";
|
||||
import {
|
||||
|
|
@ -39,6 +40,8 @@ class MessageCount extends Component {
|
|||
SpinMerge: false,
|
||||
edit_spin: false,
|
||||
pr_status: undefined,
|
||||
|
||||
copyVisible:false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +50,18 @@ class MessageCount extends Component {
|
|||
SpinFlag: true,
|
||||
});
|
||||
this.getDetail();
|
||||
|
||||
// this.clickBody();
|
||||
};
|
||||
clickBody=()=>{
|
||||
document.body.addEventListener('click', e => {
|
||||
let name = e.target.className;
|
||||
if(name.indexOf("notHide")>-1 || name.indexOf("ant-tabs-tab")>-1 || name==="ant-tabs-nav-scroll"){return;}
|
||||
this.setState({
|
||||
copyVisible:false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getDetail = () => {
|
||||
const { projectsId, mergeId, owner } = this.props.match.params;
|
||||
|
|
@ -59,7 +73,7 @@ class MessageCount extends Component {
|
|||
this.setState({
|
||||
data: result.data,
|
||||
SpinFlag: false,
|
||||
pr_status: result.data.pull_request.status,
|
||||
pr_status: result.data && result.data.pull_request && result.data.pull_request.status,
|
||||
});
|
||||
} else {
|
||||
this.setState({ SpinFlag: false });
|
||||
|
|
@ -198,6 +212,33 @@ class MessageCount extends Component {
|
|||
return <RenderHtml className="break_word_comments imageLayerParent" value={v} />;
|
||||
};
|
||||
|
||||
setCopyVisible=(e)=>{
|
||||
e.stopPropagation();
|
||||
this.setState({
|
||||
copyVisible:true
|
||||
})
|
||||
}
|
||||
|
||||
copyItem =()=>{
|
||||
return(
|
||||
<div className="copyTab notHide">
|
||||
<Tabs defaultActiveKey="1" className="notHide" animated={false} size={"small"}>
|
||||
<Tabs.TabPane key="1" tab={<span className="notHide">HTTPS</span>}>{this.returnCopyUrl("https://gitee.com/44886/polhttp.git")}</Tabs.TabPane>
|
||||
<Tabs.TabPane key="2" tab={<span className="notHide">SSH</span>}>{this.returnCopyUrl("https://gitee.com/44886/polssh.git")}</Tabs.TabPane>
|
||||
</Tabs>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
returnCopyUrl=(url)=>{
|
||||
return(
|
||||
<div className="df notHide">
|
||||
<Input value={url} className="notHide" disabled={true}/>
|
||||
<Button type="primary" ghost className="ml15 notHide">复制</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { projectsId, mergeId , owner } = this.props.match.params;
|
||||
|
||||
|
|
@ -208,6 +249,7 @@ class MessageCount extends Component {
|
|||
isSpin,
|
||||
ismesrge,
|
||||
SpinFlag,
|
||||
copyVisible
|
||||
} = this.state;
|
||||
const { current_user, projectDetail } = this.props;
|
||||
const menu = (
|
||||
|
|
@ -258,7 +300,7 @@ class MessageCount extends Component {
|
|||
<div className="mt15">
|
||||
<Tag className="pr-branch-tag">
|
||||
<Link
|
||||
to={`/projects/${owner}/${data.pull_request.is_original?data.pull_request.fork_project_id:projectsId}?branch=${data.pull_request.head}`}
|
||||
to={`/projects/${owner}/${data.pull_request.is_original?data.pull_request.fork_project_id:projectsId}/branch/${data.pull_request.head}`}
|
||||
className="ver-middle"
|
||||
>
|
||||
{data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}:{data.pull_request.head}
|
||||
|
|
@ -273,7 +315,7 @@ class MessageCount extends Component {
|
|||
</span>
|
||||
<Tag className="pr-branch-tag">
|
||||
<Link
|
||||
to={`/projects/${owner}/${projectsId}?branch=${data.pull_request.base}`}
|
||||
to={`/projects/${owner}/${projectsId}/branch/${data.pull_request.base}`}
|
||||
className="ver-middle"
|
||||
>
|
||||
{/* {data.pull_request.is_fork ? data.pull_request.base : `${data.pull_request.pull_request_user}:${data.pull_request.base}`} */}
|
||||
|
|
@ -352,13 +394,20 @@ class MessageCount extends Component {
|
|||
</div>
|
||||
</div>
|
||||
<div className="ml10">
|
||||
<div className="mt15 text-right">
|
||||
<div className="mt15 text-right" style={{display:"flex",justifyContent:"flex-end"}}>
|
||||
{/* <span className="composeButton">
|
||||
<Dropdown overlay={this.copyItem()} visible={copyVisible} onClick={(e)=>this.setCopyVisible(e)}>
|
||||
<span>复制</span>
|
||||
</Dropdown>
|
||||
<span>下载为<i className="iconfont icon-sanjiaoxing-down color-blue"></i></span>
|
||||
</span> */}
|
||||
{current_user && projectDetail &&
|
||||
pr_status !== 2 &&
|
||||
pr_status === 0 &&
|
||||
projectDetail.permission !=="Reporter" && (
|
||||
<Button
|
||||
type="success"
|
||||
type="green"
|
||||
ghost
|
||||
className="ml20"
|
||||
onClick={()=>{this.props.history.push(`/projects/${owner}/${projectsId}/pulls/${mergeId}/UpdateMerge`);}}
|
||||
>
|
||||
编辑
|
||||
|
|
@ -369,7 +418,7 @@ class MessageCount extends Component {
|
|||
type="danger"
|
||||
ghost
|
||||
onClick={() => this.closedetail()}
|
||||
className="ml15"
|
||||
className="ml20"
|
||||
loading={isSpin}
|
||||
>
|
||||
拒绝
|
||||
|
|
@ -471,14 +520,12 @@ class MessageCount extends Component {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className=" main">
|
||||
<MergeFooter
|
||||
footer_type="show"
|
||||
order_id={data && data.issue.id}
|
||||
{...this.props}
|
||||
{...this.state}
|
||||
></MergeFooter>
|
||||
</div>
|
||||
<MergeFooter
|
||||
footer_type={true}
|
||||
order_id={data && data.issue.id}
|
||||
{...this.props}
|
||||
{...this.state}
|
||||
></MergeFooter>
|
||||
</div>
|
||||
) : (
|
||||
""
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { Component } from "react";
|
||||
import { Input, Select, Button, Spin, Alert } from "antd";
|
||||
import { Input, Select , Spin, Alert } from "antd";
|
||||
import axios from "axios";
|
||||
import "../Order/order.css";
|
||||
import "./merge.css";
|
||||
|
|
@ -24,21 +24,42 @@ class NewMerge extends Component {
|
|||
merge_head: false, // 是否向fork后的源项目发起合并请求
|
||||
default_message: "必须选择不同的分支",
|
||||
project_id: undefined, // 当前项目的id,也即开始发送合并请求的源项目id
|
||||
merge_project_user: undefined
|
||||
merge_project_user: undefined,
|
||||
oldProject:undefined,//保存选择目标分支、跳转页面后会刷新的project
|
||||
comparesData:undefined,//提交和文件的内容,保存compare接口返回的数据
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
const { projectsId } = this.props.match.params;
|
||||
|
||||
this.getmergelist(projectsId);
|
||||
// 监听回退事件
|
||||
if (window.history && window.history.pushState) {
|
||||
window.addEventListener('popstate', this.handleBack, false);
|
||||
}
|
||||
};
|
||||
|
||||
//获取新建分枝数据
|
||||
componentDidUpdate=(preProps)=>{
|
||||
const { project } = this.props;
|
||||
let oldProject = preProps.project;
|
||||
if(project && oldProject && (oldProject.id !== project.id)){
|
||||
this.compareProject(this.state.id,"master","master");
|
||||
}
|
||||
}
|
||||
// 页面销毁取消监听
|
||||
componentWillUnmount () {
|
||||
window.removeEventListener('popstate', this.handleBack, false);
|
||||
};
|
||||
|
||||
handleBack=()=>{
|
||||
const { projectsId } = this.props.match.params;
|
||||
this.getmergelist(projectsId);
|
||||
}
|
||||
|
||||
//获取新建分支数据
|
||||
getmergelist = (projectsId) => {
|
||||
this.setState({isSpin: true})
|
||||
const { owner } = this.props.match.params;
|
||||
|
||||
const url = `/${owner}/${projectsId}/pulls/new.json`;
|
||||
axios
|
||||
.get(url)
|
||||
|
|
@ -56,6 +77,7 @@ class NewMerge extends Component {
|
|||
this.set_default_pull(result.data.branches);
|
||||
this.set_default_merge(result.data.merge_projects);
|
||||
}
|
||||
this.compareProject(result.data.id,"master","master");
|
||||
this.setState({isSpin: false})
|
||||
})
|
||||
.catch((error) => {
|
||||
|
|
@ -64,6 +86,32 @@ class NewMerge extends Component {
|
|||
});
|
||||
};
|
||||
|
||||
// 获取compare接口
|
||||
compareProject=(baseid , localBranch , mergeBranch)=>{
|
||||
const { project } = this.props;
|
||||
const { owner , projectsId } = this.props.match.params;
|
||||
let url = `/${owner}/${projectsId}/compare`;
|
||||
if(project){
|
||||
if(baseid === project.id){
|
||||
this.setState({
|
||||
oldProject:project
|
||||
})
|
||||
url += `/${localBranch}...${mergeBranch}.json`;
|
||||
}else{
|
||||
const { oldProject } = this.state;
|
||||
const { author , identifier } =oldProject;
|
||||
url += `/${mergeBranch}...${author && author.login}/${identifier}:${localBranch}.json`;
|
||||
}
|
||||
axios.get(url).then(result=>{
|
||||
if(result){
|
||||
this.setState({
|
||||
comparesData:result.data
|
||||
})
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
}
|
||||
|
||||
set_default_pull = (branches) => {
|
||||
if(branches && branches.length>0){
|
||||
let default_pull = branches.filter((e) => e.name === "master")
|
||||
|
|
@ -117,12 +165,16 @@ class NewMerge extends Component {
|
|||
selectBrach = (type, value) => {
|
||||
this.state[type] = value;
|
||||
this.ischeckmerge();
|
||||
let { id ,merge , pull } = this.state;
|
||||
if(type==="pull"){
|
||||
this.compareProject(id,value,merge);
|
||||
}else{
|
||||
this.compareProject(id,pull,value);
|
||||
}
|
||||
};
|
||||
|
||||
selectProjectName = (value) => {
|
||||
console.log("value",value)
|
||||
const { project_id, projects_names,id } = this.state;
|
||||
const { owner } = this.props.match.params;
|
||||
const { projects_names,id } = this.state;
|
||||
let arr = projects_names && projects_names.filter(item=>item.id===value);
|
||||
let identifier = arr && arr[0].project_id;
|
||||
let login = arr && arr[0].project_user_login;
|
||||
|
|
@ -138,7 +190,6 @@ class NewMerge extends Component {
|
|||
})
|
||||
this.props.history.push(`/projects/${login}/${identifier}/pulls/new`);
|
||||
this.newMergelist(login,identifier);
|
||||
|
||||
};
|
||||
|
||||
//判断2分支是否可以合并
|
||||
|
|
@ -146,7 +197,7 @@ class NewMerge extends Component {
|
|||
ischeckmerge = () => {
|
||||
this.setState({ isSpin: true });
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
const { pull, merge, project_id, merge_head, id } = this.state;
|
||||
const { pull, merge , merge_head, id } = this.state;
|
||||
const url = `/${owner}/${projectsId}/pulls/check_can_merge.json`;
|
||||
axios.post(url, {
|
||||
head: pull,
|
||||
|
|
@ -194,9 +245,9 @@ class NewMerge extends Component {
|
|||
show_message,
|
||||
default_message,
|
||||
merge_head,
|
||||
projects_names,
|
||||
projects_names,id,comparesData
|
||||
} = this.state;
|
||||
const { projectsId } = this.props.match.params;
|
||||
|
||||
const renderBrances = (list, type) => {
|
||||
if (list && list.length > 0) {
|
||||
return list.map((item, key) => {
|
||||
|
|
@ -228,29 +279,26 @@ class NewMerge extends Component {
|
|||
return <div dangerouslySetInnerHTML={{ __html: html }}></div>;
|
||||
};
|
||||
let { project } = this.props;
|
||||
console.log("222 ",project);
|
||||
console.log("222111 ",projects_names);
|
||||
return (
|
||||
<div>
|
||||
<div className="main">
|
||||
<Spin spinning={isSpin}>
|
||||
<div className="merge-header width100 inline-block">
|
||||
<div className="width45 pull-left">
|
||||
<div className="width40 pull-left">
|
||||
<div className="color-grey-3 mb10 fwb">源分支:</div>
|
||||
<Input.Group compact className="display-flex">
|
||||
<Select
|
||||
defaultValue={project && project.id}
|
||||
class=" maxW50 hide-1 task-hide"
|
||||
value={id}
|
||||
className="hide-1 task-hide flex1"
|
||||
disabled
|
||||
style={{maxWidth:"200px"}}
|
||||
>
|
||||
{renderProjectNames(projects_names)}
|
||||
</Select>
|
||||
<Select
|
||||
defaultValue={pull}
|
||||
value={pull}
|
||||
onSelect={(e) => this.selectBrach("pull", e)}
|
||||
showSearch
|
||||
className="minW50 merge-flex1"
|
||||
className="merge-flex1 flex1"
|
||||
>
|
||||
{renderBrances(branches, false)}
|
||||
</Select>
|
||||
|
|
@ -261,24 +309,22 @@ class NewMerge extends Component {
|
|||
className={"iconfont icon-youjiang color-grey-c font-32"}
|
||||
></i>
|
||||
</div>
|
||||
<div className="width45 pull-left">
|
||||
<div className="width40 pull-left">
|
||||
<div>
|
||||
<div className="color-grey-3 mb10 fwb">目标分支:</div>
|
||||
<Input.Group compact className="display-flex">
|
||||
<Select
|
||||
defaultValue={project && project.id}
|
||||
class=" maxW50 hide-1 task-hide"
|
||||
value={project && project.id}
|
||||
className="hide-1 task-hide flex1"
|
||||
onSelect={(e) => this.selectProjectName(e)}
|
||||
style={{maxWidth:"200px"}}
|
||||
>
|
||||
{renderProjectNames(merge_projects)}
|
||||
</Select>
|
||||
<Select
|
||||
defaultValue={merge}
|
||||
value={merge}
|
||||
onSelect={(e) => this.selectBrach("merge", e)}
|
||||
showSearch
|
||||
className="minW50 merge-flex1"
|
||||
className="merge-flex1 flex1"
|
||||
>
|
||||
{renderBrances(merge_branches, merge_head)}
|
||||
</Select>
|
||||
|
|
@ -297,10 +343,20 @@ class NewMerge extends Component {
|
|||
data={data}
|
||||
merge={merge}
|
||||
pull={pull}
|
||||
files_count={comparesData && comparesData.diff && comparesData.diff.files_count}
|
||||
commits_count={comparesData && comparesData.commits_count}
|
||||
></MergeForm>
|
||||
)}
|
||||
</Spin>
|
||||
</div>
|
||||
<MergeFooter
|
||||
order_id={data && data.issue && data.issue.id}
|
||||
{...this.props}
|
||||
{...this.state}
|
||||
merge={merge}
|
||||
pull={pull}
|
||||
comparesData={comparesData}
|
||||
></MergeFooter>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,11 +37,15 @@ class UpdateMerge extends Component {
|
|||
merge: result.data.base,
|
||||
});
|
||||
} else {
|
||||
this.setState({ isSpin: false });
|
||||
this.setState({
|
||||
isSpin: false,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({ isSpin: false });
|
||||
this.setState({
|
||||
isSpin: false,
|
||||
});
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
|
@ -52,6 +56,7 @@ class UpdateMerge extends Component {
|
|||
<div>
|
||||
<div className="main">
|
||||
<Spin spinning={isSpin}>
|
||||
{" "}
|
||||
{data ? (
|
||||
<div>
|
||||
<div className="merge-header width100 inline-block">
|
||||
|
|
@ -66,17 +71,17 @@ class UpdateMerge extends Component {
|
|||
defaultValue={data.is_original ? `${data.fork_project_user}:${pull}` : `${pull}`}
|
||||
className="minW50 merge-flex1"
|
||||
disabled
|
||||
></Select>
|
||||
</Input.Group>
|
||||
</div>
|
||||
></Select>{" "}
|
||||
</Input.Group>{" "}
|
||||
</div>{" "}
|
||||
<div className="width10 pull-left text-center mt25">
|
||||
<i
|
||||
className={"iconfont icon-youjiang color-grey-c font-32"}
|
||||
></i>
|
||||
</div>
|
||||
></i>{" "}
|
||||
</div>{" "}
|
||||
<div className="width45 pull-left">
|
||||
<div>
|
||||
<div className="color-grey-3 mb10 fwb">目标分支:</div>
|
||||
<div className="color-grey-3 mb10 fwb"> 目标分支 : </div>{" "}
|
||||
<Input.Group compact className="display-flex">
|
||||
<Button className="merge-header-button maxW50 hide-1 task-hide">
|
||||
{`${data.project_author}/${data.project_name}`}
|
||||
|
|
@ -85,19 +90,18 @@ class UpdateMerge extends Component {
|
|||
defaultValue={data.is_original ? `${data.project_login}:${merge}` : `${merge}`}
|
||||
className="minW50 merge-flex1"
|
||||
disabled
|
||||
></Select>
|
||||
</Input.Group>
|
||||
</div>
|
||||
</div>
|
||||
></Select>{" "}
|
||||
</Input.Group>{" "}
|
||||
</div>{" "}
|
||||
</div>{" "}
|
||||
</div>
|
||||
|
||||
<MergeForm
|
||||
{...this.props}
|
||||
merge_type="edit"
|
||||
data={data}
|
||||
merge={merge}
|
||||
pull={pull}
|
||||
></MergeForm>
|
||||
></MergeForm>{" "}
|
||||
</div>
|
||||
) : (
|
||||
""
|
||||
|
|
|
|||
|
|
@ -40,4 +40,161 @@ form .ant-cascader-picker, form .ant-select {
|
|||
}
|
||||
.merge-header-button{
|
||||
background:rgba(241,248,255,1);
|
||||
}
|
||||
.width70{
|
||||
width:70%;
|
||||
}
|
||||
.width30{
|
||||
width:30%;
|
||||
}
|
||||
.width40{
|
||||
width:40%;
|
||||
}
|
||||
.display-flex{
|
||||
display: flex!important;
|
||||
}
|
||||
.w120{
|
||||
width: 120px;
|
||||
}
|
||||
.w240{
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
.custom-commit-tabs .ant-tabs-nav .ant-tabs-tab{
|
||||
padding:14px 0px!important;
|
||||
}
|
||||
.custom-commit-tabs .ant-tabs-bar{
|
||||
border-bottom: none;
|
||||
}
|
||||
.custom-commit-tabs .ant-tabs-nav .ant-tabs-tab-active .tabNum{
|
||||
background-color: #EBF4FE;
|
||||
}
|
||||
.custom-commit-tabs .ant-tabs-ink-bar{
|
||||
width: 34px!important;
|
||||
}
|
||||
.tabNum{
|
||||
display: inline-block;
|
||||
margin-left:8px ;
|
||||
border-radius: 10px;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
background-color: #eee;
|
||||
padding:0px 9px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 复制-下载为,组合按钮 */
|
||||
.composeButton{
|
||||
display: flex;
|
||||
border:1px solid #5091FF;
|
||||
border-radius: 5px;
|
||||
height: 34px;
|
||||
line-height: 34px;
|
||||
}
|
||||
.composeButton > span{
|
||||
display: block;
|
||||
padding:0px 18px;
|
||||
color: #5091FF;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.composeButton > span:hover{
|
||||
background-color: #F1F8FF;
|
||||
}
|
||||
.composeButton > span:first-child{
|
||||
border-radius: 5px 0px 0px 5px;
|
||||
border-right: 1px solid #5091FF;
|
||||
}
|
||||
.ant-btn{
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* 绿色按钮-type="green" */
|
||||
.ant-btn.ant-btn-green{
|
||||
border:1px solid #28BD6C;
|
||||
color: #28BD6C;
|
||||
}
|
||||
.copyTab{
|
||||
min-width: 370px;
|
||||
padding:0px 18px 22px 18px;
|
||||
box-shadow: 0px 2px 10px rgba(0,0,0,0.2);
|
||||
background-color: #fff;
|
||||
}
|
||||
.copyTab .ant-tabs-tab{
|
||||
padding:12px 0px!important;
|
||||
}
|
||||
|
||||
/* pr--提交tab页面 */
|
||||
.prCommits{
|
||||
border:1px solid #ddd;
|
||||
border-top: none;
|
||||
}
|
||||
.prCommits:first-child{
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
.prCommits .prCreate{
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
padding:0px 25px;
|
||||
background-color:#fafafa;
|
||||
color:#333;
|
||||
font-size: 16px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
.prCommits .prInfo{
|
||||
padding:20px 25px;
|
||||
}
|
||||
/* pr-文件修改信息页面 */
|
||||
.files{
|
||||
border:1px solid #ddd;
|
||||
margin-top: 15px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.filesInfo{
|
||||
padding:10px 15px;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
.filesContent{
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
.linesContent{
|
||||
display: flex;
|
||||
min-height: 30px;
|
||||
line-height: 30px;
|
||||
color: #333;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.linesContent > p{
|
||||
flex:1;
|
||||
}
|
||||
.linesContent .lines{
|
||||
display: flex;
|
||||
border-right: 1px solid #ddd;
|
||||
width: 100px;
|
||||
padding: 0px 8px;
|
||||
box-sizing: border-box;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.linesContent .lines > span:first-child{
|
||||
margin-right: 0px;
|
||||
}
|
||||
.linesContent .lines > span{
|
||||
width: 50%;
|
||||
text-align: right;
|
||||
display: block;
|
||||
color: #888;
|
||||
}
|
||||
.linesContent.translate{
|
||||
background-color:#F1F8FF;
|
||||
}
|
||||
.linesContent.translate .lines > span{
|
||||
border-right: 1px solid transparent;
|
||||
}
|
||||
.linesContent.reduce{
|
||||
background-color:rgba(247, 48, 48, 0.15);;
|
||||
}
|
||||
.linesContent.add{
|
||||
background: rgba(48, 232, 132, 0.15);
|
||||
}
|
||||
|
|
@ -423,7 +423,7 @@ class merge extends Component {
|
|||
</Spin>
|
||||
</div>
|
||||
) : (
|
||||
<NoneData _html="暂时还没有相关数据哦!" projectsId={projectsId} owner={owner} />
|
||||
<NoneData _html="暂时还没有相关数据!" projectsId={projectsId} owner={owner} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,45 +1,169 @@
|
|||
import React, { Component } from "react";
|
||||
import { Tabs, Empty } from "antd";
|
||||
import { Tabs, Spin } from "antd";
|
||||
import "../Order/order.css";
|
||||
import "./merge.css";
|
||||
import CodesCommit from "../Main/CoderRootCommit";
|
||||
import Commits from "./Commits";
|
||||
import Comments from "../comments/comments";
|
||||
|
||||
import Files from "./Files";
|
||||
import axios from 'axios';
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
class MergeFooter extends Component {
|
||||
constructor(props) {
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {};
|
||||
this.state={
|
||||
pageData:undefined,
|
||||
commitsData:undefined,
|
||||
filesData:undefined,
|
||||
isSpin:false,
|
||||
activeKey:"1",
|
||||
commitCount:0,
|
||||
filesCount:0
|
||||
}
|
||||
}
|
||||
componentDidMount=()=>{
|
||||
const { footer_type ,data } = this.props;
|
||||
if(footer_type){
|
||||
const { projectsId , owner , mergeId } = this.props.match.params;
|
||||
this.getCommit(owner,projectsId,mergeId);
|
||||
this.getFile(owner,projectsId,mergeId);
|
||||
}
|
||||
this.setState({
|
||||
activeKey:footer_type ? "1" : "2",
|
||||
commitCount:data && data.commits_count,
|
||||
filesCount:data && data.files_count
|
||||
})
|
||||
}
|
||||
componentDidUpdate=(prevProps)=>{
|
||||
const { comparesData } = this.props;
|
||||
const { footer_type } = this.props;
|
||||
if(footer_type){
|
||||
const { data } = this.props;
|
||||
if(data !== prevProps.data){
|
||||
this.setState({
|
||||
commitCount:data && data.commits_count,
|
||||
filesCount:data && data.files_count
|
||||
})
|
||||
}
|
||||
}
|
||||
if(comparesData !== prevProps.comparesData){
|
||||
this.setState({
|
||||
activeKey:footer_type ? "1" : "2"
|
||||
})
|
||||
this.changeTab(footer_type ? "1" : "2");
|
||||
}
|
||||
}
|
||||
|
||||
changeTab=(index)=>{
|
||||
this.setState({
|
||||
isSpin:true
|
||||
})
|
||||
this.setState({
|
||||
activeKey:index
|
||||
})
|
||||
const { footer_type , comparesData } = this.props;
|
||||
const { projectsId , owner , mergeId } = this.props.match.params;
|
||||
|
||||
if(footer_type){
|
||||
if(index === "2"){
|
||||
this.getCommit(owner,projectsId,mergeId);
|
||||
}else if(index === "3"){
|
||||
this.getFile(owner,projectsId,mergeId);
|
||||
}else{
|
||||
this.setState({
|
||||
isSpin:false
|
||||
})
|
||||
}
|
||||
}else{
|
||||
this.setState({
|
||||
commitsData:comparesData.commits,
|
||||
filesData:comparesData.diff,
|
||||
commitCount:comparesData.commits_count,
|
||||
filesCount:comparesData.diff && comparesData.diff.files_count,
|
||||
isSpin:false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
getCommit =(owner,projectsId,mergeId)=>{
|
||||
const url = `/${owner}/${projectsId}/pulls/${mergeId}/commits.json`;
|
||||
axios.get(url).then(result=>{
|
||||
if(result){
|
||||
this.setState({
|
||||
commitsData:result.data.commits,
|
||||
isSpin:false,
|
||||
commitCount:result.data.commits_count
|
||||
})
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
||||
getFile =(owner,projectsId,mergeId)=>{
|
||||
const url = `/${owner}/${projectsId}/pulls/${mergeId}/files.json`;
|
||||
axios.get(url).then(result=>{
|
||||
if(result){
|
||||
this.setState({
|
||||
filesData:result.data,
|
||||
isSpin:false,
|
||||
filesCount:result.data.files_count,
|
||||
})
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { footer_type, order_id } = this.props;
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
|
||||
const { footer_type, order_id, data , comparesData } = this.props;
|
||||
let { isSpin , activeKey , filesCount, commitCount , filesData , commitsData } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Tabs
|
||||
defaultActiveKey={footer_type === "show" ? "1" : "2"}
|
||||
className="custom-commit-tabs"
|
||||
>
|
||||
{
|
||||
footer_type === "show" &&
|
||||
<TabPane tab={<span className="ml-3 font-16">评论</span>} key="1">
|
||||
<Comments
|
||||
order_id={order_id}
|
||||
showNotification={this.props.showNotification}
|
||||
only_show_content={true}
|
||||
{...this.props}
|
||||
/>
|
||||
</TabPane>
|
||||
}
|
||||
|
||||
{/* <TabPane tab={<span className="ml-3 font-16">提交</span>} key="2">
|
||||
<CodesCommit {...this.props} main_class="pd10"></CodesCommit>
|
||||
</TabPane> */}
|
||||
{/* <TabPane tab={<span className="ml-3 font-16">文件</span>} key="3">
|
||||
<Empty />
|
||||
</TabPane> */}
|
||||
</Tabs>
|
||||
!footer_type && !comparesData || (comparesData && ((comparesData.commits && comparesData.commits.length===0)||(comparesData && !comparesData.diff)) )?"":
|
||||
<div className="main" style={{paddingTop:"0px"}}>
|
||||
<Spin spinning={isSpin}>
|
||||
<Tabs
|
||||
activeKey={activeKey}
|
||||
className="custom-commit-tabs"
|
||||
animated={false}
|
||||
onChange={this.changeTab}
|
||||
>
|
||||
{
|
||||
footer_type &&
|
||||
<TabPane
|
||||
tab={
|
||||
<span><span className="font-16">评论</span>
|
||||
{data && parseInt(data.comments_count) > 0 && <span className="tabNum">{data.comments_count}</span>}
|
||||
</span>
|
||||
} key="1">
|
||||
<Comments
|
||||
order_id={order_id}
|
||||
showNotification={this.props.showNotification}
|
||||
only_show_content={true}
|
||||
{...this.props}
|
||||
/>
|
||||
</TabPane>
|
||||
}
|
||||
{
|
||||
commitsData && commitsData.length > 0 &&
|
||||
<TabPane tab={<span><span className="font-16">提交</span>
|
||||
{commitCount > 0 && <span className="tabNum">{commitCount}</span>}
|
||||
</span>} key="2">
|
||||
<Commits {...this.props} commits={commitsData} projectsId={projectsId} owner={owner}></Commits>
|
||||
</TabPane>
|
||||
}
|
||||
{
|
||||
filesData && filesData.files && filesData.files.length>0 &&
|
||||
<TabPane tab={
|
||||
<span><span className="font-16">文件</span>
|
||||
{filesCount > 0 && <span className="tabNum">{filesCount}</span>}
|
||||
</span>
|
||||
} key="3">
|
||||
<Files {...this.props} data={filesData} projectsId={projectsId} owner={owner}/>
|
||||
</TabPane>
|
||||
}
|
||||
|
||||
</Tabs>
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ class MergeForm extends Component {
|
|||
this.props.form.validateFieldsAndScroll((err, values) => {
|
||||
if (!err) {
|
||||
const { projectsId, mergeId , owner } = this.props.match.params;
|
||||
const { merge, pull, merge_type, data } = this.props;
|
||||
const { merge, pull, merge_type, data , commits_count , files_count } = this.props;
|
||||
if (values.issue_tag_ids && values.issue_tag_ids.length > 0) {
|
||||
values.issue_tag_ids = [parseInt(values.issue_tag_ids)];
|
||||
} else {
|
||||
|
|
@ -154,7 +154,9 @@ class MergeForm extends Component {
|
|||
base: merge,
|
||||
is_original: data && data.is_original,
|
||||
fork_project_id: data && data.fork_project_id,
|
||||
merge_user_login: data && data.merge_user_login
|
||||
merge_user_login: data && data.merge_user_login,
|
||||
files_count,
|
||||
commits_count
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
|
|
@ -221,7 +223,7 @@ class MergeForm extends Component {
|
|||
};
|
||||
|
||||
render() {
|
||||
const { merge_type, data } = this.props;
|
||||
const { merge_type } = this.props;
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
const { projectsId, mergeId ,owner } = this.props.match.params;
|
||||
const {
|
||||
|
|
|
|||
|
|
@ -51,9 +51,7 @@ class Index extends Component {
|
|||
<div className="grid-item">
|
||||
<div className="setInputAddon">
|
||||
<Input
|
||||
addonBefore={`/${
|
||||
projectDetail && projectDetail.identifier
|
||||
}${urlroot}/`}
|
||||
addonBefore={`/${ projectDetail && projectDetail.identifier }${urlroot}/`}
|
||||
value={filename}
|
||||
onChange={this.changeFileName}
|
||||
placeholder="命名文件..."
|
||||
|
|
|
|||
|
|
@ -54,9 +54,7 @@ class UserSubmitComponent extends Component {
|
|||
const { getTopCount } = this.props;
|
||||
getTopCount && getTopCount(values.branchname);
|
||||
}
|
||||
let url = values.branchname
|
||||
? `/projects/${owner}/${projectsId}?branch=${values.branchname}`
|
||||
: `/projects/${owner}/${projectsId}`;
|
||||
let url = `/projects/${owner}/${projectsId}${values.branchname ? `/branch/${values.branchname}`: (branch ? `/branch/${branch}` : "")}`;
|
||||
this.props.history.push(url);
|
||||
}
|
||||
})
|
||||
|
|
@ -73,7 +71,7 @@ class UserSubmitComponent extends Component {
|
|||
// 确认修改文件
|
||||
UpdateFile = () => {
|
||||
this.setState({ isSpin: true });
|
||||
const { branch, detail, content, filepath } = this.props;
|
||||
const { branch, detail, content , currentBranch } = this.props;
|
||||
const { projectsId , owner } = this.props.match.params;
|
||||
const { submitType } = this.state;
|
||||
const url = `/${owner}/${projectsId}/update_file.json`;
|
||||
|
|
@ -82,7 +80,7 @@ class UserSubmitComponent extends Component {
|
|||
axios
|
||||
.put(url, {
|
||||
filepath: detail.path,
|
||||
branch: branch,
|
||||
branch: submitType === "1" ? undefined : (currentBranch || branch),
|
||||
new_branch: submitType === "1" ? values.branchname : undefined,
|
||||
content: content,
|
||||
sha: detail.sha,
|
||||
|
|
@ -91,12 +89,10 @@ class UserSubmitComponent extends Component {
|
|||
.then((result) => {
|
||||
this.setState({ isSpin: false });
|
||||
if (result.data && result.data.status === 1) {
|
||||
let url = values.branchname
|
||||
? `/projects/${owner}/${projectsId}?branch=${values.branchname}`
|
||||
: `/projects/${owner}/${projectsId}`;
|
||||
|
||||
debugger;
|
||||
let url = `/projects/${owner}/${projectsId}${(values.branchname ? `/branch/${values.branchname}` : ((currentBranch || branch) ? `/branch/${currentBranch || branch}`:""))}`;
|
||||
this.props.history.push(url);
|
||||
this.props.showNotification("修改成功!");
|
||||
this.props.showNotification("文件修改成功!");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
|
|
|
|||
|
|
@ -309,8 +309,10 @@ class Detail extends Component {
|
|||
<div className="list-left list-left-padding">
|
||||
<div className="list-right-item-padding background-f boder-4">
|
||||
<p className="grid-item-left pb15">
|
||||
<span className="issue_detail_info">分支:</span>
|
||||
<span>{data && data.branch_name ? data.branch_name : "--"}</span>
|
||||
<span className="issue_detail_info">负责人:</span>
|
||||
<span>
|
||||
{data && data.assign_user_name ? data.assign_user_name : "--"}
|
||||
</span>
|
||||
</p>
|
||||
<p className="grid-item-left pb15">
|
||||
<span className="issue_detail_info">标签:</span>
|
||||
|
|
@ -344,12 +346,6 @@ class Detail extends Component {
|
|||
<span className="issue_detail_info">分类:</span>
|
||||
<span>{data && data.tracker ? data.tracker : "--"}</span>
|
||||
</p>
|
||||
<p className="grid-item-left pb15">
|
||||
<span className="issue_detail_info">负责人:</span>
|
||||
<span>
|
||||
{data && data.assign_user_name ? data.assign_user_name : "--"}
|
||||
</span>
|
||||
</p>
|
||||
<p className="grid-item-left pb15">
|
||||
<span className="issue_detail_info">开始日期:</span>
|
||||
<span>{data && data.start_date ? data.start_date : "--"}</span>
|
||||
|
|
@ -363,6 +359,10 @@ class Detail extends Component {
|
|||
<span className="issue_detail_info">完成度:</span>
|
||||
<span>{data && data.done_ratio ? data.done_ratio : "--"}</span>
|
||||
</p>
|
||||
<p className="grid-item-left pb15">
|
||||
<span className="issue_detail_info">分支:</span>
|
||||
<span>{data && data.branch_name ? data.branch_name : "--"}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ class Milepost extends Component {
|
|||
})
|
||||
}
|
||||
</div>
|
||||
: <NoneData _html="暂时还没有相关数据哦!" />
|
||||
: <NoneData _html="暂时还没有相关数据!" />
|
||||
}
|
||||
{
|
||||
data && data.versions_count > limit ?
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ class MilepostDetail extends Component {
|
|||
<div className="setItemStyle">
|
||||
{
|
||||
search_count === 0 ?
|
||||
<NoneData _html="暂时还没有相关数据哦!" />
|
||||
<NoneData _html="暂时还没有相关数据!" />
|
||||
:
|
||||
issues && issues.length>0 && issues.map((item,key)=>{
|
||||
return(
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Popconfirm, Tag } from 'antd'
|
||||
import { Popconfirm } from 'antd'
|
||||
import { TagInfo } from '../Utils/TagColor';
|
||||
|
||||
|
||||
class OrderItem extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
|
@ -54,7 +52,7 @@ class OrderItem extends Component {
|
|||
{current_user && current_user.login && checkbox}
|
||||
<div className="flex-1">
|
||||
<p className="mb10 df" style={{alignItems:"center"}}>
|
||||
<Link to={`/projects/${owner}/${projectsId}/issues/${item.id}/detail`} target="_blank" title={item.name} className="hide-1 font-16 color-grey-3 lineh-30 mr10" style={{maxWidth:"300px"}}>{item.name}</Link>
|
||||
<Link to={`/projects/${owner}/${projectsId}/issues/${item.id}/detail`} target="_blank" title={item.name} className="hide-1 font-16 color-grey-3 lineh-30 mr10" style={{maxWidth:"370px"}}>{item.name}</Link>
|
||||
{TagInfo(item.priority,"mr10")}
|
||||
</p>
|
||||
<p className="color-grey-6 font-12">
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ class Tags extends Component {
|
|||
</div>
|
||||
</div>
|
||||
:
|
||||
<NoneData _html="暂时还没有相关数据哦!" />
|
||||
<NoneData _html="暂时还没有相关数据!" />
|
||||
}
|
||||
{
|
||||
data && data.issue_tags_count > limit ?
|
||||
|
|
|
|||
|
|
@ -239,6 +239,8 @@ class order extends Component {
|
|||
this.setState({
|
||||
search: value,
|
||||
isSpin: true,
|
||||
checkedValue:[],
|
||||
all:undefined
|
||||
});
|
||||
const { status_type } = this.state;
|
||||
|
||||
|
|
@ -258,7 +260,10 @@ class order extends Component {
|
|||
assigned_to_ids: "负责人",
|
||||
status_ids: "状态",
|
||||
done_ratios: "完成度",
|
||||
fixed_version_ids:"里程碑",
|
||||
paix: "排序",
|
||||
checkedValue:[],
|
||||
all:undefined
|
||||
});
|
||||
this.state.select_params = {
|
||||
search: undefined,
|
||||
|
|
@ -324,19 +329,19 @@ class order extends Component {
|
|||
id: id,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
const { status_type } = this.state;
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
const { status_type } = this.state;
|
||||
|
||||
this.getIssueList(status_type);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
this.getIssueList(status_type);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
islogin() {
|
||||
islogin=()=>{
|
||||
this.props.showLoginDialog();
|
||||
}
|
||||
renderNew =()=>{
|
||||
|
|
@ -349,9 +354,7 @@ class order extends Component {
|
|||
)
|
||||
}else{
|
||||
return(
|
||||
<a className="topWrapper_btn ml10" onClick={this.islogin}>
|
||||
+ 创建任务
|
||||
</a>
|
||||
<a className="topWrapper_btn ml10" onClick={this.islogin}>+ 创建任务</a>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -802,7 +805,7 @@ class order extends Component {
|
|||
|
||||
</div>
|
||||
{search_count === 0 ? (
|
||||
<NoneData _html="暂时还没有相关数据哦!" />
|
||||
<NoneData _html="暂时还没有相关数据!" />
|
||||
) : (
|
||||
<div style={{ minHeight: "500px" }}>
|
||||
<Checkbox.Group name="issues" onChange={this.checkIssues} value={checkedValue} style={{ width: "100%" }}>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ class order_form extends Component {
|
|||
subject: "",
|
||||
get_attachments: undefined,
|
||||
show_token: false,
|
||||
cannot_edit: false,
|
||||
issue_current_user: true
|
||||
};
|
||||
}
|
||||
componentDidUpdate=(prevPros)=>{
|
||||
|
|
@ -263,6 +265,7 @@ class order_form extends Component {
|
|||
});
|
||||
this.setState({
|
||||
done_ratio: "0",
|
||||
issue_current_user: true,
|
||||
});
|
||||
} else if (e === "3") {
|
||||
this.props.form.setFieldsValue({
|
||||
|
|
@ -270,6 +273,11 @@ class order_form extends Component {
|
|||
});
|
||||
this.setState({
|
||||
done_ratio: "100",
|
||||
issue_current_user: true,
|
||||
});
|
||||
}else if (e === "5") {
|
||||
this.setState({
|
||||
issue_current_user: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -371,19 +379,13 @@ class order_form extends Component {
|
|||
</div>
|
||||
<div className="list-left list-left-padding issue-edit-form-right">
|
||||
<div className="pd20 background-f issue-form-right">
|
||||
<Form.Item>
|
||||
{getFieldDecorator("branch_name", {
|
||||
rules: []
|
||||
})(
|
||||
<Form.Item label="指派成员">
|
||||
{getFieldDecorator("assigned_to_id", {rules: []})(
|
||||
<Select>
|
||||
<Option value={""}>分支未指定</Option>
|
||||
{branches && branches.length > 0 && branches.map((item, key) => {
|
||||
return (
|
||||
<Option value={item} key={key}>
|
||||
{item}
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
<Option value={""}>未指派成员</Option>
|
||||
{this.renderSelect(
|
||||
issue_chosen && issue_chosen.assign_user
|
||||
)}
|
||||
</Select>
|
||||
)}
|
||||
</Form.Item>
|
||||
|
|
@ -452,16 +454,6 @@ class order_form extends Component {
|
|||
)}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="指派成员">
|
||||
{getFieldDecorator("assigned_to_id", {rules: []})(
|
||||
<Select>
|
||||
<Option value={""}>未指派成员</Option>
|
||||
{this.renderSelect(
|
||||
issue_chosen && issue_chosen.assign_user
|
||||
)}
|
||||
</Select>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label="开始日期">
|
||||
<DatePicker
|
||||
value={start_date ? moment(start_date, "YYYY-MM-DD") : null}
|
||||
|
|
@ -485,28 +477,22 @@ class order_form extends Component {
|
|||
</Select>
|
||||
)}
|
||||
</Form.Item>
|
||||
{/* <Form.Item label="是否上链">
|
||||
<Switch
|
||||
checkedChildren="是"
|
||||
unCheckedChildren="否"
|
||||
defaultChecked={false}
|
||||
checked={issue_type && issue_type === "2"}
|
||||
onChange={this.change_issue_type}
|
||||
/>
|
||||
<Form.Item label="指定分支">
|
||||
{getFieldDecorator("branch_name", {
|
||||
rules: []
|
||||
})(
|
||||
<Select>
|
||||
<Option value={""}>分支未指定</Option>
|
||||
{branches && branches.length > 0 && branches.map((item, key) => {
|
||||
return (
|
||||
<Option value={item} key={key}>
|
||||
{item}
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
)}
|
||||
</Form.Item>
|
||||
{(show_token || (issue_type && issue_type === "2")) && (
|
||||
<Form.Item label="token">
|
||||
{getFieldDecorator("token", {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: "请填写token值",
|
||||
},
|
||||
],
|
||||
initialValue: token,
|
||||
})(<Input placeholder="请填写token值" />)}
|
||||
</Form.Item>
|
||||
)} */}
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import React , { useState } from 'react';
|
||||
import React , { useEffect, useState } from 'react';
|
||||
import SelectBranch from '../Branch/Select';
|
||||
import Title from '../Component/Title';
|
||||
import styled from 'styled-components';
|
||||
import { Blueline , FlexAJ , NumUl , GreenUnder , AlignCenter , WhiteBack } from '../Component/layout';
|
||||
|
||||
import axios from 'axios';
|
||||
const Div = styled.div`{
|
||||
padding:20px 30px;
|
||||
min-height:500px;
|
||||
|
|
@ -14,8 +14,30 @@ export default ((props)=>{
|
|||
const { projectsId , owner } = props.match.params;
|
||||
const projectDetail = props.projectDetail;
|
||||
|
||||
function resetSetting(){
|
||||
const { defaultBranch } = props;
|
||||
useEffect(()=>{
|
||||
if(defaultBranch){
|
||||
setBranch(defaultBranch);
|
||||
}
|
||||
},[defaultBranch]);
|
||||
|
||||
|
||||
function resetSetting(){
|
||||
const url = `/${owner}/${projectsId}.json`;
|
||||
axios.put(url, {
|
||||
default_branch:branch
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
props.showNotification(`分支设置成功!`);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
function settingRule(){
|
||||
props.history.push(`/projects/${owner}/${projectsId}/setting/branch/new`);
|
||||
}
|
||||
return(
|
||||
<WhiteBack>
|
||||
|
|
@ -31,17 +53,18 @@ export default ((props)=>{
|
|||
projectsId={projectsId}
|
||||
changeBranch={setBranch}
|
||||
owner={owner}
|
||||
history={props.history}
|
||||
/>
|
||||
<a className="color-blue ml20" onClick={resetSetting()}>设为默认分支</a>
|
||||
<a className="color-blue ml20" onClick={()=>resetSetting()}>设为默认分支</a>
|
||||
</AlignCenter>
|
||||
</div>
|
||||
<div>
|
||||
<FlexAJ className="pt20">
|
||||
<span className="color-grey-3">保护分支规则</span>
|
||||
<Blueline>+ 新建规则</Blueline>
|
||||
<Blueline onClick={()=>settingRule()}>+ 新建规则</Blueline>
|
||||
</FlexAJ>
|
||||
<NumUl>
|
||||
<li>限制分支的推送、合并。强制推送相关请去<GreenUnder>仓库设置</GreenUnder>。</li>
|
||||
<li>限制分支的推送、合并。强制推送相关请去<GreenUnder onClick={()=>{props.history.push(`/projects/${owner}/${projectsId}/setting`)}}>仓库设置</GreenUnder>。</li>
|
||||
<li>一个分支同时只能有一个保护分支规则生效,越早创建的规则优先级越高。</li>
|
||||
<li>保护分支规则只影响状态是【保护分支】的分支。【常规分支】和【只读分支】都不影响。</li>
|
||||
</NumUl>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,55 @@
|
|||
import React , { forwardRef , useCallback } from 'react';
|
||||
import { Form , Input , Select , Button } from 'antd';
|
||||
import Title from '../Component/Title';
|
||||
import { WhiteBack , Cancel } from '../Component/layout';
|
||||
import styled from 'styled-components';
|
||||
import React, { forwardRef, useCallback, useState, useEffect } from "react";
|
||||
import { Form, Input, Select, Button } from "antd";
|
||||
import Title from "../Component/Title";
|
||||
import { WhiteBack, Cancel } from "../Component/layout";
|
||||
import styled from "styled-components";
|
||||
import axios from "axios";
|
||||
|
||||
const {Option} = Select;
|
||||
const Div = styled.div`{
|
||||
padding:20px 30px;
|
||||
}`
|
||||
const { Option } = Select;
|
||||
const Div = styled.div`
|
||||
{
|
||||
padding: 20px 30px;
|
||||
}
|
||||
`;
|
||||
export default Form.create()(
|
||||
forwardRef(( { form })=>{
|
||||
const { getFieldDecorator } = form;
|
||||
forwardRef(({ form, match, history }) => {
|
||||
const [ list, setList ] = useState(undefined);
|
||||
const { projectsId, owner } = match.params;
|
||||
const { getFieldDecorator, validateFields } = form;
|
||||
|
||||
useEffect(() => {
|
||||
const url = `/${owner}/${projectsId}/collaborators.json`;
|
||||
axios.get(url).then((result) => {
|
||||
setList(result.data.members);
|
||||
})
|
||||
.catch((error) => {});
|
||||
}, []);
|
||||
|
||||
function getMember(list) {
|
||||
return (
|
||||
list &&
|
||||
list.length > 0 &&
|
||||
list.map((item, key) => {
|
||||
return (
|
||||
item.role !== "Manager" && (
|
||||
<Option value={item.id}>{item.name}</Option>
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function saveBranchRule() {
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget , className , isRequired ) => (
|
||||
(label, name, rules, widget, className, isRequired) => (
|
||||
<div className={className}>
|
||||
<span className={isRequired?"required":""}>{label}</span>
|
||||
<span className={isRequired ? "required" : ""}>{label}</span>
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
</Form.Item>
|
||||
|
|
@ -22,7 +57,7 @@ export default Form.create()(
|
|||
),
|
||||
[]
|
||||
);
|
||||
return(
|
||||
return (
|
||||
<WhiteBack>
|
||||
<Title>新建保护分支规则</Title>
|
||||
<Div>
|
||||
|
|
@ -30,31 +65,48 @@ export default Form.create()(
|
|||
"设置分支/通配符",
|
||||
"sign",
|
||||
[{ required: true, message: "请输入分支/通配符" }],
|
||||
<Input placeholder="请输入分支名称或通配符规则" />,'setStyleRule'
|
||||
<Input placeholder="请输入分支名称或通配符规则" />,
|
||||
"setStyleRule"
|
||||
)}
|
||||
<p className="color-grey-8 mb20">例如:设置为“master”,则对名称为“master”的分支生效;设置为“*-stable“ 或 ”release*“,则对名称符合此通配符的所有保护分支生效。</p>
|
||||
<p className="color-grey-8 mb20">
|
||||
例如:设置为“master”,则对名称为“master”的分支生效;设置为“*-stable“
|
||||
或 ”release*“,则对名称符合此通配符的所有保护分支生效。
|
||||
</p>
|
||||
{helper(
|
||||
"可推送代码成员",
|
||||
"psuhmember",
|
||||
[],
|
||||
<Select placeholder="请选择仓库成员" >
|
||||
[{ required: true, message: "请选择可推送代码成员" }],
|
||||
<Select placeholder="请选择仓库成员">
|
||||
<Option value="0">请选择仓库成员</Option>
|
||||
</Select>,'setSelectWidth'
|
||||
{getMember(list)}
|
||||
</Select>,
|
||||
"setSelectWidth"
|
||||
)}
|
||||
{helper(
|
||||
"可合并Pull Request成员",
|
||||
"pullmember",
|
||||
[],
|
||||
<Select placeholder="请选择仓库成员" >
|
||||
[{ required: true, message: "请选择可合并Pull Request成员" }],
|
||||
<Select placeholder="请选择仓库成员">
|
||||
<Option value="0">请选择仓库成员</Option>
|
||||
</Select>,'setSelectWidth'
|
||||
{getMember(list)}
|
||||
</Select>,
|
||||
"setSelectWidth"
|
||||
)}
|
||||
<div className="df pb30">
|
||||
<Button type="primary">保存</Button>
|
||||
<Cancel className="ml30">取消</Cancel>
|
||||
<Button type="primary" onClick={saveBranchRule}>
|
||||
保存
|
||||
</Button>
|
||||
<Cancel
|
||||
className="ml30"
|
||||
onClick={() => {
|
||||
history.push(`/projects/${owner}/${projectsId}/setting/branch`);
|
||||
}}
|
||||
>
|
||||
取消
|
||||
</Cancel>
|
||||
</div>
|
||||
</Div>
|
||||
</WhiteBack>
|
||||
)
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -360,6 +360,11 @@ class Collaborator extends Component {
|
|||
dataIndex: "email",
|
||||
render: (text) => <span>{text}</span>,
|
||||
},
|
||||
{
|
||||
title: "Token值",
|
||||
dataIndex: "token",
|
||||
render: (text) => <span>{text}</span>,
|
||||
},
|
||||
{
|
||||
title: roleTitle,
|
||||
dataIndex: "role_name",
|
||||
|
|
@ -493,7 +498,7 @@ class Collaborator extends Component {
|
|||
rowKey={(record) => record.id}
|
||||
></Table>
|
||||
) : (
|
||||
<NoneData _html="暂时还没有相关数据哦!" />
|
||||
<NoneData _html="暂时还没有相关数据!" />
|
||||
)}
|
||||
</div>
|
||||
</Spin>
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ class Index extends Component {
|
|||
}
|
||||
>
|
||||
<p>
|
||||
<Link to={`/projects/${projectsId}/setting/branch`} className="w-100">
|
||||
<Link to={`/projects/${owner}/${projectsId}/setting/branch`} className="w-100">
|
||||
<i className="iconfont icon-fenzhi font-20 mr10"></i>
|
||||
分支设置
|
||||
</Link>
|
||||
|
|
@ -128,7 +128,7 @@ class Index extends Component {
|
|||
<Route
|
||||
path="/projects/:owner/:projectsId/setting/branch"
|
||||
render={(props) => (
|
||||
<Branch {...this.props} {...props} {...this.state} />
|
||||
<Branch {...this.props} {...props } {...this.state} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ class Setting extends Component {
|
|||
}
|
||||
|
||||
componentDidUpdate=(prevPros)=>{
|
||||
console.log("dddd",this.props.checkIfLogin());
|
||||
if(prevPros && this.props && !this.props.checkIfLogin()){
|
||||
this.props.history.push("/403")
|
||||
return
|
||||
|
|
@ -145,7 +144,6 @@ class Setting extends Component {
|
|||
});
|
||||
};
|
||||
changePrivate = (e) => {
|
||||
console.log(e);
|
||||
this.setState({
|
||||
private_check: e.target.checked,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -410,7 +410,7 @@ class NewTags extends Component {
|
|||
</div>
|
||||
);
|
||||
} else {
|
||||
return <NoneData _html="暂时还没有相关数据哦!" />;
|
||||
return <NoneData _html="暂时还没有相关数据!" />;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ class CommonUsers extends Component {
|
|||
<Spin spinning={isSpin}>
|
||||
<div className="w-100 inline-block">
|
||||
{count === 0 ? (
|
||||
<NoneData _html="暂时还没有相关数据哦!" />
|
||||
<NoneData _html="暂时还没有相关数据!" />
|
||||
) : (
|
||||
<UserList users={users} userClass={'w-25'} {...this.props}></UserList>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ class ForkUsers extends Component {
|
|||
<Spin spinning={isSpin}>
|
||||
<div className="w-100 inline-block">
|
||||
{count === 0 ? (
|
||||
<NoneData _html="暂时还没有相关数据哦!" />
|
||||
<NoneData _html="暂时还没有相关数据!" />
|
||||
) : (
|
||||
this.renderList(users)
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export function getDateTime(value, dataformat) {
|
|||
return date.format(dataformat);
|
||||
}
|
||||
|
||||
export default function Time(UTCtiem) {
|
||||
export function Time(UTCtiem) {
|
||||
var dateTime = new Date(UTCtiem);
|
||||
|
||||
var year = dateTime.getFullYear();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,191 @@
|
|||
import React , { Component } from "react";
|
||||
import { Form , Input , Select,Divider,Button,Checkbox,Dropdown,Menu} from 'antd';
|
||||
import {Link} from 'react-router-dom';
|
||||
|
||||
import UploadComponent from '../Upload/Index';
|
||||
import '../Order/order.css';
|
||||
import './version.css';
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
const Option = Select.Option;
|
||||
const TextArea = Input.TextArea;
|
||||
class NewVersion extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state={
|
||||
branch_name:"",
|
||||
issue_tag_ids:"",
|
||||
fixed_version_id:"",
|
||||
issue_chosen:undefined,
|
||||
fileList:undefined,
|
||||
ischeck:undefined,
|
||||
pull:undefined,
|
||||
tag_name:'',
|
||||
data:undefined
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount=()=>{
|
||||
this.getSelectList();
|
||||
}
|
||||
|
||||
getSelectList=()=>{
|
||||
const { projectsId,versionId} = this.props.match.params;
|
||||
const url = `/projects/${projectsId}/version_releases/${versionId}/edit.json`;
|
||||
axios.get(url).then((result)=>{
|
||||
if(result){
|
||||
this.setState({
|
||||
data:result.data,
|
||||
pull:result.data.target_commitish
|
||||
})
|
||||
}
|
||||
}).catch((error)=>{
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//delete
|
||||
deleteversion=()=>{
|
||||
const { projectsId , versionId} = this.props.match.params;
|
||||
const url = `/projects/${projectsId}/version_releases/${versionId}.json`;
|
||||
axios.delete(url,{ data: {
|
||||
project_id: projectsId,
|
||||
id:versionId
|
||||
}
|
||||
}).then((result)=>{
|
||||
if(result){
|
||||
this.props.history.push(`/projects/${projectsId}/version`);
|
||||
|
||||
}
|
||||
}).catch((error)=>{
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
// 创建
|
||||
handleSubmit=()=>{
|
||||
this.props.form.validateFieldsAndScroll((err, values) => {
|
||||
if(!err){
|
||||
const { projectsId,versionId} = this.props.match.params;
|
||||
const { pull,ischeck } = this.state;
|
||||
const url = `/projects/${projectsId}/version_releases/${versionId}.json`;
|
||||
// if(values.issue_type==="普通"){
|
||||
// values.issue_type="1"
|
||||
// }
|
||||
axios.put(url,{
|
||||
...values,
|
||||
tag_name:this.state.data&&this.state.data.tag_name,
|
||||
draft:false,
|
||||
prerelease:ischeck,
|
||||
target_commitish:pull
|
||||
}).then(result=>{
|
||||
if(result){
|
||||
this.props.history.push(`/projects/${projectsId}/version`);
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
RedieonChange=(e)=>{
|
||||
this.setState({
|
||||
ischeck:e.target.checked
|
||||
})
|
||||
}
|
||||
Preservation=()=>{
|
||||
alert(this.state.data.tag_name)
|
||||
}
|
||||
|
||||
renderMenu =(array,id)=>{
|
||||
return(
|
||||
<Menu>
|
||||
{
|
||||
array && array.length > 0 && array.map((item,key)=>{
|
||||
return(
|
||||
<Menu.Item key={item} onClick={()=>this.getOption(item)}>{item}</Menu.Item>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
|
||||
getOption=(name)=>{
|
||||
this.setState({
|
||||
pull:name
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
changmodelname=(e)=>{
|
||||
this.setState({
|
||||
tag_name:e.target.value
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
const { projectsId } = this.props.match.params;
|
||||
return(
|
||||
<div className="main">
|
||||
<Form>
|
||||
<h1 style={{marginLeft:15,marginTop:20}}>发布新版</h1>
|
||||
<h5 style={{marginLeft:15}}>版本发布组织项目的版本。</h5>
|
||||
<Divider/>
|
||||
<div style={{display:'flex',marginLeft:15}}>
|
||||
{this.state.data&&this.state.data.tag_name}@{this.state.data&&this.state.data.target_commitish}
|
||||
</div>
|
||||
<div style={{display:'flex'}}>
|
||||
<div className="versionmilepostleft">
|
||||
<h1>标题</h1>
|
||||
<div>
|
||||
<Form.Item>
|
||||
{getFieldDecorator('name', {
|
||||
rules: [{
|
||||
required: true, message: '请输入标题'
|
||||
}],
|
||||
initialValue:this.state.data&&this.state.data.name
|
||||
|
||||
})(
|
||||
<Input placeholder="标题"/>
|
||||
)}
|
||||
</Form.Item>
|
||||
</div>
|
||||
<h1>内容</h1>
|
||||
<Form.Item>
|
||||
{getFieldDecorator('body', {
|
||||
rules: [{
|
||||
required: true, message: '请输入描述内容'
|
||||
}],
|
||||
initialValue:this.state.data&&this.state.data.body
|
||||
})(
|
||||
<TextArea placeholder="添加一个可选的扩展描述。。。" style={{height:"300px"}}/>
|
||||
|
||||
)}
|
||||
</Form.Item>
|
||||
{/* <UploadComponent load={this.UploadFunc} style={{width:80,marginLeft:15}}></UploadComponent> */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider/>
|
||||
<div className="fr">
|
||||
<Checkbox onChange={this.RedieonChange}>标记为预行版</Checkbox>
|
||||
<p>标记此版本不适合生产使用</p>
|
||||
</div>
|
||||
<div className="clearfix mt15" style={{marginTop:5}} >
|
||||
<a className='topWrapper_btn_delete fr' onClick={()=>this.deleteversion()} style={{marginLeft:15}}>删除发布</a>
|
||||
<a className='topWrapper_btn fr' onClick={()=>this.handleSubmit()} style={{marginRight:15}}>编辑发布信息</a>
|
||||
<Link to={`/projects/${projectsId}/version`} style={{marginRight:30}} className='topWrapper_btn fr'>取消</Link>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
const WrappedNewVersionForm = Form.create({ name: 'NewVersionForm' })(NewVersion);
|
||||
export default WrappedNewVersionForm;
|
||||
|
|
@ -177,7 +177,7 @@
|
|||
}
|
||||
.versionTips{
|
||||
width:30%;
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.infosTip{
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ class version extends Component {
|
|||
)
|
||||
} else {
|
||||
return (
|
||||
<NoneData _html="暂时还没有相关数据哦!" />
|
||||
<NoneData _html="暂时还没有相关数据!" />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +107,7 @@ class version extends Component {
|
|||
const { data , releases } = this.state
|
||||
|
||||
return (
|
||||
<div className="main">
|
||||
<div className="main" style={{paddingTop:"0px"}}>
|
||||
<div className="topWrapper">
|
||||
<span className="font-18 color-grey-3">版本发布</span>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -523,7 +523,7 @@ class comments extends Component {
|
|||
{new_comment(is_reply, undefined)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="children-comment-bg pd20 grid-item">
|
||||
<div className="children-comment-bg pd20 grid-item mb20">
|
||||
<img
|
||||
className="radius"
|
||||
src={
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@ export function truncateCommitId(str) {
|
|||
if (str && str.length > 11) {
|
||||
return str.substring(0, 10)
|
||||
}else{
|
||||
return undefined
|
||||
return str
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,7 +135,24 @@ form{
|
|||
vertical-align: middle;
|
||||
}
|
||||
.pd510{padding: 5px 10px;}
|
||||
|
||||
.modalsStyle{
|
||||
.ant-modal-content{
|
||||
&>.ant-modal-header{
|
||||
text-align: left!important;
|
||||
}
|
||||
}
|
||||
.ant-modal-body{
|
||||
max-width: 400px;
|
||||
margin:0px auto;
|
||||
text-align: left;
|
||||
min-height: 140px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.ant-modal-close-x{
|
||||
margin-top:8px;
|
||||
}
|
||||
}
|
||||
.list-l-Menu{
|
||||
margin-bottom: 12px;
|
||||
border-radius:2px;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,348 @@
|
|||
import React, { Component } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Avatar, Tag, Button, Spin, Input, Form, message, Divider} from "antd";
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import { withRouter } from "react-router";
|
||||
|
||||
import { SnackbarHOC } from "educoder";
|
||||
import { CNotificationHOC } from "../../modules/courses/common/CNotificationHOC";
|
||||
import { TPMIndexHOC } from "../../modules/tpm/TPMIndexHOC";
|
||||
|
||||
import axios from "axios";
|
||||
import { getImageUrl } from "educoder";
|
||||
|
||||
import Loadable from "react-loadable";
|
||||
import Loading from "../../Loading";
|
||||
import { ImageLayerOfCommentHOC } from "../../modules/page/layers/ImageLayerOfCommentHOC";
|
||||
|
||||
import SponsorTierItem from "./sponsor_tier_item";
|
||||
|
||||
import "../users/new_user.css";
|
||||
import "../css/index.scss";
|
||||
import '../users/Index.scss';
|
||||
import "./sponsor.css";
|
||||
|
||||
const tempData = [
|
||||
{id:1, tier: 5, description: "这能让我感到很开心"},
|
||||
{id:2, tier: 10, description: "如果您更加慷慨的话就选择这个"},
|
||||
{id:3, tier: 150, description: "这能为我带来相当多的额外收入"},
|
||||
{id:4, tier: 250, description: "这能为我带来相当多的额外收入"},
|
||||
{id:5, tier: 500, description: "这能为我带来相当多的额外收入"},
|
||||
{id:6, tier: 1000, description: "这能为我带来相当多的额外收入"},
|
||||
{id:7, tier: 5000, description: "这能为我带来相当多的额外收入"},
|
||||
];
|
||||
|
||||
const tempDesc = "我长期从事开源社区相关工作...目前已经开发了多个项目,如xxx, xxxx, ...\n我希望通过资助机制成为全职开源开发者,如果您对我的项目感兴趣,请资助我!"
|
||||
|
||||
const tempSponsors = [
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
{image_url: "avatars/User/b", username: "万山川", user_id: 1369, login:"alpc104"},
|
||||
];
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const TextArea = Input.TextArea;
|
||||
|
||||
const DescriptionForm = Form.create()(
|
||||
class extends Component{
|
||||
getItemsValue = ()=>{
|
||||
const val= this.props.form.getFieldsValue(); // 获取from表单的值
|
||||
return val;
|
||||
}
|
||||
render(){
|
||||
|
||||
const { form, initValue} = this.props;
|
||||
const { getFieldDecorator } = form; // 校验控件
|
||||
return(
|
||||
<Form >
|
||||
<FormItem>
|
||||
{getFieldDecorator(`description`,{
|
||||
rules: [],
|
||||
initialValue: initValue ? initValue : undefined
|
||||
})(
|
||||
// <Input placeholder="请输入"/>
|
||||
<TextArea rows={4} placeholder="请输入"></TextArea>
|
||||
)}
|
||||
</FormItem>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
class Sponsor extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isSpin: false,
|
||||
user: undefined,
|
||||
description: undefined,
|
||||
sponsors: undefined,
|
||||
edit: false,
|
||||
tiers: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
this.fetchUser();
|
||||
this.fetchData();
|
||||
};
|
||||
|
||||
fetchUser = () => {
|
||||
this.setState({
|
||||
isSpin: true,
|
||||
});
|
||||
const { current_user } = this.props;
|
||||
const { username } = this.props.match.params;
|
||||
|
||||
let url = `/users/${username || (current_user && current_user.login)}.json`;
|
||||
axios
|
||||
.get(url)
|
||||
.then((result) => {
|
||||
// TODO: 在这里添加了对用户自我介绍的处理,前后端交互实现后需要删掉
|
||||
// result.data.description = tempDesc;
|
||||
this.setState({
|
||||
user: result.data,
|
||||
isSpin: false,
|
||||
}, () => {this.fetchSponsors()});
|
||||
// console.log(result.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
this.setState({
|
||||
isSpin: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
fetchSponsors = () => {
|
||||
// console.log("fetch sponsors");
|
||||
const user_id = this.state.user.user_id;
|
||||
|
||||
let url = `/sponsorships/sponsored.json`;
|
||||
|
||||
axios.get(url, {params: {id: user_id}})
|
||||
.then((result) => {
|
||||
// console.log(result);
|
||||
this.setState({
|
||||
sponsors: result.data.sponsorships,
|
||||
isSpin: false,
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
this.setState({
|
||||
isSpin: false,
|
||||
});
|
||||
});
|
||||
// this.setState({
|
||||
// sponsors: tempData,
|
||||
// displayList: tempData,
|
||||
// })
|
||||
// this.setState({
|
||||
// sponsors: tempSponsors,
|
||||
// });
|
||||
}
|
||||
|
||||
fetchData = () => {
|
||||
let url = `/sponsor_tiers.json`;
|
||||
const user_login = this.props.match.params.username;
|
||||
axios
|
||||
.get(url, {params:{login: user_login}})
|
||||
.then((result) => {
|
||||
// console.log(result.data);
|
||||
// console.log(tempData)
|
||||
this.setState({
|
||||
tiers: result.data
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
editDescription = () => {
|
||||
this.setState({
|
||||
edit: true,
|
||||
});
|
||||
}
|
||||
|
||||
cancelEdit = () => {
|
||||
this.setState({
|
||||
edit: false,
|
||||
})
|
||||
}
|
||||
|
||||
confirmEdit = () => {
|
||||
//TODO: 增加和后端交互
|
||||
let value = this.formRef.getItemsValue().description;
|
||||
// console.log(value);
|
||||
let user = this.state.user;
|
||||
let url = `/users/${user.user_id}/update_description.json`
|
||||
axios.put(url, {description: value})
|
||||
.then((result) => {
|
||||
user.description = value;
|
||||
this.setState({
|
||||
user: user,
|
||||
edit: false
|
||||
})
|
||||
this.props.showNotification("修改成功")
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
this.props.showNotification("修改失败")
|
||||
})
|
||||
|
||||
|
||||
// if (user){
|
||||
// user.description = value;
|
||||
// }
|
||||
// this.setState({
|
||||
// user: user,
|
||||
// edit: false,
|
||||
// });
|
||||
}
|
||||
|
||||
visitorTemplate = () => {
|
||||
const user = this.state.user;
|
||||
return (
|
||||
<div>
|
||||
{user && user.description?
|
||||
(<p>{user.description}</p>):(<p>暂无自我介绍</p>)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
manageTemplate = () => {
|
||||
const user = this.state.user;
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<i className="iconfont icon-bianji3 font-15" onClick={() => this.editDescription()}></i>
|
||||
</div>
|
||||
{user && user.description? (<div>{user.description}</div>):(<div>暂无自我介绍</div>)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
editTemplate = () => {
|
||||
const user = this.state.user;
|
||||
return (
|
||||
<div>
|
||||
<DescriptionForm
|
||||
initValue={user && user.description}
|
||||
wrappedComponentRef={(form) => this.formRef = form}
|
||||
/>
|
||||
<Button onClick={() => this.confirmEdit()}>确认</Button>
|
||||
<Button onClick={() => this.cancelEdit()}>取消</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
sponsorList(){
|
||||
const {sponsors} = this.state;
|
||||
const sponsorList = (sponsors && sponsors.length>0 ? sponsors.map((item, key)=>{
|
||||
return (
|
||||
<Link to={`/users/${item.login}`} className="show-user-link">
|
||||
<img className="sponsor-page-sponsors" alt="" src={getImageUrl(`images/${item && item.image_url}`)} title={item.username}></img>
|
||||
</Link>);
|
||||
})
|
||||
:"")
|
||||
return (<p>{sponsorList}</p>);
|
||||
}
|
||||
|
||||
render(){
|
||||
const { current_user} = this.props;
|
||||
const { user, isSpin, tiers} = this.state;
|
||||
const sponsorList = this.sponsorList();
|
||||
// console.log(tiers);
|
||||
|
||||
var content = "";
|
||||
if (current_user && user && user.login !== current_user.login){
|
||||
content = this.visitorTemplate();
|
||||
}
|
||||
else if(current_user && user && user.login === current_user.login && this.state.edit){
|
||||
content = this.editTemplate();
|
||||
}
|
||||
else if(current_user && user && user.login === current_user.login && !this.state.edit){
|
||||
content = this.manageTemplate();
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="newMain clearfix">
|
||||
<Spin spinning={isSpin}>
|
||||
<div className="new-content-flex">
|
||||
<div className="sponsor-page-left">
|
||||
<div className="list-l-Menu pd20 ">
|
||||
<div className="text-center mt15 font-16 fwb"> 成为{user && user.username}的赞助者吧</div>
|
||||
<div className="text-center"><Avatar
|
||||
size={110}
|
||||
src={getImageUrl(`images/${user && user.image_url}`)}
|
||||
/>
|
||||
{user && user.user_identity && (
|
||||
<div className="mt-n15 position-relative">
|
||||
<Tag color="#FF6E21" style={{marginRight:"0px"}}>{user && user.user_identity}</Tag>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Divider />
|
||||
{content}
|
||||
<Divider />
|
||||
<div>
|
||||
赞助者:
|
||||
{sponsorList}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bgcF">
|
||||
{/* <div className="list-l-Menu pd20 ">
|
||||
{content}
|
||||
</div>
|
||||
<div className="list-l-Menu pd20 ">
|
||||
赞助者:
|
||||
{sponsorList}
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
<div className="sponsor-page-right">
|
||||
<SponsorTierItem
|
||||
{...this.props}
|
||||
{...this.state}
|
||||
tiers={tiers}>
|
||||
</SponsorTierItem>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default withRouter(
|
||||
ImageLayerOfCommentHOC({
|
||||
imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget",
|
||||
parentSelector: ".newMain",
|
||||
})(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(Sponsor))))
|
||||
);
|
||||
|
||||
|
|
@ -0,0 +1,325 @@
|
|||
import React, { Component } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Avatar, Tag, Button, Spin, Input, Divider, Form, Radio, Alert, message, Modal} from "antd";
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import { withRouter } from "react-router";
|
||||
|
||||
import { SnackbarHOC } from "educoder";
|
||||
import { CNotificationHOC } from "../../modules/courses/common/CNotificationHOC";
|
||||
import { TPMIndexHOC } from "../../modules/tpm/TPMIndexHOC";
|
||||
|
||||
import axios from "axios";
|
||||
import { getImageUrl } from "educoder";
|
||||
|
||||
import Loadable from "react-loadable";
|
||||
import Loading from "../../Loading";
|
||||
import { ImageLayerOfCommentHOC } from "../../modules/page/layers/ImageLayerOfCommentHOC";
|
||||
|
||||
import "../users/new_user.css";
|
||||
import "../css/index.scss";
|
||||
import '../users/Index.scss';
|
||||
import "./sponsor.css";
|
||||
import { submitUserCode } from "../../redux/actions/ojForUser";
|
||||
|
||||
const tempData = {amount:100, description: "如果您更加慷慨的话就选择这个"};
|
||||
const tempBalance = 999;
|
||||
const FormItem = Form.Item;
|
||||
const { confirm } = Modal;
|
||||
|
||||
const SponsorConfirmation = Form.create()(
|
||||
class extends Component{
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isSpin: false,
|
||||
user: undefined,
|
||||
tier: undefined,
|
||||
single: false,
|
||||
balance: undefined,
|
||||
is_sponsoring: false,
|
||||
visible: false,
|
||||
sponsorship_id: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
this.fetchUser();
|
||||
this.fetchTierInformation();
|
||||
this.fetchBalance();
|
||||
// this.fetchData();
|
||||
};
|
||||
|
||||
//组件刚刚挂载时,TPMINDEXHOC还没从后端获取current_user,需要在获取后,再使用current_user的内容
|
||||
componentWillReceiveProps = () => {
|
||||
if (this.props.current_user)
|
||||
this.fetchBalance();
|
||||
}
|
||||
|
||||
fetchUser = () => {
|
||||
this.setState({
|
||||
isSpin: true,
|
||||
});
|
||||
const { current_user } = this.props;
|
||||
const { username } = this.props.match.params;
|
||||
|
||||
let url = `/users/${username || (current_user && current_user.login)}.json`;
|
||||
axios
|
||||
.get(url)
|
||||
.then((result) => {
|
||||
this.setState({
|
||||
user: result.data,
|
||||
isSpin: false,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
this.setState({
|
||||
isSpin: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
fetchTierInformation = () => {
|
||||
const { current_user } = this.props;
|
||||
const { username, tier_id } = this.props.match.params;
|
||||
let url = `/sponsor_tiers/${tier_id}.json`;
|
||||
axios
|
||||
.get(url)
|
||||
.then((result) => {
|
||||
this.setState({
|
||||
tier: result.data.tier,
|
||||
is_sponsoring: result.data.is_sponsoring,
|
||||
sponsorship_id: result.data.sponsorship_id,
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
this.setState({
|
||||
isSpin: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fetchBalance = () => {
|
||||
const { current_user } = this.props;
|
||||
let url = `/wallets/balance.json`;
|
||||
if (current_user){
|
||||
axios
|
||||
.get(url, {params: {id: current_user.user_id}})
|
||||
.then((result) => {
|
||||
this.setState({
|
||||
balance: result.data.balance,
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
this.setState({
|
||||
isSpin: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
reSelect = () => {
|
||||
const {user} = this.state;
|
||||
this.setState({
|
||||
route_type: undefined
|
||||
})
|
||||
this.props.history.push(`/sponsor/${user && user.login}`)
|
||||
}
|
||||
|
||||
changeSingle = (e) => {
|
||||
|
||||
this.setState({
|
||||
single: e.target.value
|
||||
})
|
||||
}
|
||||
|
||||
updateSponsorship = () => {
|
||||
const value = this.props.form.getFieldsValue();
|
||||
const {tier, user, sponsorship_id} = this.state;
|
||||
const {current_user} = this.props;
|
||||
let url = `/sponsorships/${sponsorship_id}.json`;
|
||||
axios.put(url, {
|
||||
amount: tier.tier,
|
||||
visible: value.visible
|
||||
})
|
||||
.then((result) => {
|
||||
if (result && result.data.status == 1)
|
||||
this.props.showNotification(result.data.message);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
submit = () => {
|
||||
const value = this.props.form.getFieldsValue();
|
||||
const {tier, user} = this.state;
|
||||
const {current_user} = this.props;
|
||||
// console.log(value);
|
||||
let url = `/sponsorships.json`;
|
||||
axios.post(url, {
|
||||
amount: tier.tier,
|
||||
visible: value.visible,
|
||||
single: value.single,
|
||||
developer_id: user.user_id,
|
||||
})
|
||||
.then((result) => {
|
||||
// console.log(result);
|
||||
if (result && result.data.status == 1)
|
||||
this.props.showNotification(result.data.message);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
handleCancel = e => {
|
||||
this.setState({
|
||||
visible: false,
|
||||
});
|
||||
};
|
||||
|
||||
showModal = () => {
|
||||
this.setState({
|
||||
visible: true,
|
||||
});
|
||||
};
|
||||
|
||||
showConfirm = () => {
|
||||
const {user} = this.state;
|
||||
const fun = this.state.is_sponsoring?this.updateSponsorship:this.submit;
|
||||
let text = this.state.is_sponsoring?`确认要修改对 ${user && user.username} 的赞助吗?若修改金额,将在下次自动扣款生效。`
|
||||
:`确认要赞助 ${user && user.username} 吗?`;
|
||||
confirm({
|
||||
// title: '确认赞助',
|
||||
// icon: <ExclamationCircleOutlined />,
|
||||
content: text,
|
||||
onOk() {
|
||||
fun()
|
||||
},
|
||||
onCancel() {
|
||||
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
const {tier_id, username} = this.props.match.params;
|
||||
const {current_user, form} = this.props;
|
||||
const {user, isSpin, tier, balance, is_sponsoring, single} = this.state;
|
||||
const {getFieldDecorator} = form;
|
||||
|
||||
const current_username = current_user && current_user.username;
|
||||
const alert_text = this.state.single? `您选择了单次付费,本次扣除${tier && tier.tier}硬币`
|
||||
:`您选择了按月付费,每月20日将扣除${tier && tier.tier}硬币`;
|
||||
|
||||
// console.log("sponsoring", is_sponsoring);
|
||||
// console.log("tier: ", tier);
|
||||
// console.log("current user", current_user);
|
||||
|
||||
const radioStyle = {
|
||||
display: 'block',
|
||||
height: '30px',
|
||||
lineHeight: '30px',
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="newMain clearfix">
|
||||
<Spin spinning={isSpin}>
|
||||
<div className="new-content-flex">
|
||||
<div className="sponsor-confirmation-left">
|
||||
<div className="list-l-Menu pd20 ">
|
||||
<p>
|
||||
<Avatar
|
||||
size={50}
|
||||
src={getImageUrl(`images/${user && user.image_url}`)}
|
||||
/>
|
||||
<a href={`/sponsor/${user && user.login}`}>赞助{user && user.username}</a>/赞助等级确认
|
||||
</p>
|
||||
<p>
|
||||
赞助者为
|
||||
<Avatar
|
||||
size={50}
|
||||
src={getImageUrl(`images/${current_user && current_user.image_url}`)}
|
||||
/>
|
||||
{current_user && current_user.username}
|
||||
</p>
|
||||
<Divider></Divider>
|
||||
<p>所选赞助等级</p>
|
||||
<p>{tier && tier.tier}硬币</p>
|
||||
<p>{tier && tier.description}</p>
|
||||
<Button onClick={() => this.reSelect()}>重新选择</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="sponsor-confirmation-right">
|
||||
<div className="list-l-Menu pd20 ">
|
||||
<Form>
|
||||
<FormItem >
|
||||
{getFieldDecorator(`single`,{
|
||||
rules: [{
|
||||
required: true
|
||||
}],
|
||||
initialValue: single
|
||||
})(
|
||||
<Radio.Group onChange={(e) => this.changeSingle(e)} disabled={is_sponsoring}>
|
||||
<Radio style={radioStyle} value={true}>单次付费</Radio>
|
||||
<Radio style={radioStyle} value={false}>按月支付</Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
</FormItem>
|
||||
<p>本次支付金额{tier && tier.tier}硬币</p>
|
||||
<p>{this.state.single? "单次付费": "即日起-次月20日"}</p>
|
||||
<Divider></Divider>
|
||||
|
||||
<div>支付信息</div>
|
||||
<div>
|
||||
<div>
|
||||
<Avatar
|
||||
size={50}
|
||||
src={getImageUrl(`images/${current_user && current_user.image_url}`)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div>{current_user && current_user.username}</div>
|
||||
<div>硬币余额{balance}</div>
|
||||
</div>
|
||||
</div>
|
||||
<Alert message={alert_text} type="warning"/>
|
||||
<Divider></Divider>
|
||||
<span>赞助关系可见性</span>
|
||||
<FormItem >
|
||||
{getFieldDecorator(`visible`,{
|
||||
rules: [{
|
||||
required: true
|
||||
}],
|
||||
initialValue: 1
|
||||
})(
|
||||
<Radio.Group >
|
||||
<Radio style={radioStyle} value={1}>所有人可见</Radio>
|
||||
<Radio style={radioStyle} value={0}>私密</Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
</FormItem>
|
||||
<Button type='primary' className="confirm-btn" onClick={() => this.showConfirm()}>赞助 {user && user.username}</Button>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export default withRouter(
|
||||
ImageLayerOfCommentHOC({
|
||||
imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget",
|
||||
parentSelector: ".newMain",
|
||||
})(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(SponsorConfirmation))))
|
||||
);
|
||||
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
.sponsor-page-left{
|
||||
width: 65%;
|
||||
padding-right: 20px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.sponsor-page-right{
|
||||
width: 35%;
|
||||
padding-right: 20px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.sponsor-page-sponsors{
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
margin-right: 11px;
|
||||
}
|
||||
|
||||
.sponsor-confirmation-left{
|
||||
width: 35%;
|
||||
padding-right: 20px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.sponsor-confirmation-right{
|
||||
width: 65%;
|
||||
padding-right: 20px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.sponsor-inline{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.tier-Item:last-child{
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.tier-Item{
|
||||
border-bottom:1px solid rgba(238,238,238,1);
|
||||
padding:9px 12px;
|
||||
}
|
||||
|
||||
|
||||
.right{
|
||||
float: right
|
||||
}
|
||||
|
||||
.btn-border-5{
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.description-edit{
|
||||
min-height:28px;
|
||||
border:true;
|
||||
}
|
||||
|
||||
.tier-title{
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.mr10{
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.confirm-btn{
|
||||
width: 100%;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.sponsor-item-btn{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
|
@ -0,0 +1,422 @@
|
|||
import React, { Component } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Avatar, Tag, Button, Spin, Icon, Modal, Input, Form, message, Popconfirm, Divider, InputNumber} from "antd";
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import { withRouter } from "react-router";
|
||||
// import { EditOutlined } from "@ant-design/icons";
|
||||
|
||||
import { SnackbarHOC } from "educoder";
|
||||
import { CNotificationHOC } from "../../modules/courses/common/CNotificationHOC";
|
||||
import { TPMIndexHOC } from "../../modules/tpm/TPMIndexHOC";
|
||||
|
||||
import axios from "axios";
|
||||
import { getImageUrl } from "educoder";
|
||||
|
||||
import Loadable from "react-loadable";
|
||||
import Loading from "../../Loading";
|
||||
import { ImageLayerOfCommentHOC } from "../../modules/page/layers/ImageLayerOfCommentHOC";
|
||||
|
||||
import "../users/new_user.css";
|
||||
import "../css/index.scss";
|
||||
import '../users/Index.scss';
|
||||
import "./sponsor.css";
|
||||
import "../Main/list.css";
|
||||
import Item from "antd/lib/list/Item";
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
const EditTierForm = Form.create()(
|
||||
class extends Component{
|
||||
getItemsValue = ()=>{
|
||||
const val= this.props.form.getFieldsValue(); // 获取from表单的值
|
||||
return val;
|
||||
}
|
||||
render(){
|
||||
|
||||
const { form, initValue1, initValue2, initValueList } = this.props;
|
||||
const { getFieldDecorator } = form; // 校验控件
|
||||
return(
|
||||
<Form >
|
||||
<FormItem label={`金额`} >
|
||||
{getFieldDecorator(`tier`,{
|
||||
rules: [{
|
||||
message: '请输入数字!',
|
||||
pattern: /^[0-9]+$/,
|
||||
required: true
|
||||
}],
|
||||
initialValue: initValue1 ? initValue1 : undefined
|
||||
})(
|
||||
<InputNumber placeholder="请输入数字"/>
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label={`描述`} >
|
||||
{getFieldDecorator(`description`,{
|
||||
rules: [{
|
||||
message: '必填字段!',
|
||||
required: true,
|
||||
}, {
|
||||
max: 255,
|
||||
message: "长度不能超过255个字符"
|
||||
}],
|
||||
initialValue: initValue2 ? initValue2 : undefined
|
||||
})(
|
||||
<Input placeholder="请输入"/>
|
||||
)}
|
||||
</FormItem>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
class SponsorTierItem extends Component{
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
var edit = new Array();
|
||||
if (props.tiers){
|
||||
for(var i=0; i<props.tiers.length; i++) edit.push(false);
|
||||
}
|
||||
this.state = {
|
||||
tiers: props.tiers,
|
||||
new_tier: undefined,
|
||||
edit: edit,
|
||||
isSpin: false,
|
||||
}
|
||||
// this.state = {
|
||||
// tiers: undefined,
|
||||
// new_tier: undefined,
|
||||
// edit: undefined,
|
||||
// isSpin: false,
|
||||
// }
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
|
||||
}
|
||||
|
||||
// 如果服务器较慢,组件会先被挂载,此时父组件传来的props数据是空的,但是获得数据后,有新的props,需要更新。
|
||||
// 如果用户点击了修改自我描述等父组件的方法,父组件会重新渲染,这个方法又会被调用,有可能原有的编辑框会丢失。
|
||||
// 因此先判断一下父组件传过来的数据是否有变化。没有变化则不需要修改state
|
||||
componentWillReceiveProps = () => {
|
||||
if (this.props.tiers !== this.state.tiers){
|
||||
var edit = new Array();
|
||||
for(var i=0; i<this.props.tiers.length; i++) edit.push(false);
|
||||
this.setState({
|
||||
tiers: this.props.tiers,
|
||||
edit: edit,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fetchData = () => {
|
||||
let url = `/sponsor_tiers.json`;
|
||||
axios
|
||||
.get(url)
|
||||
.then((result) => {
|
||||
console.log(result.data);
|
||||
// console.log(tempData);
|
||||
var edit = new Array();
|
||||
for(var i=0; i<result.data.length; i++) edit.push(false);
|
||||
this.setState({
|
||||
tiers: result.data,
|
||||
edit: edit,
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
fetchUser = () => {
|
||||
this.setState({
|
||||
isSpin: true,
|
||||
});
|
||||
const { current_user } = this.props;
|
||||
const { username } = this.props.match.params;
|
||||
|
||||
let url = `/users/${username || (current_user && current_user.login)}.json`;
|
||||
axios
|
||||
.get(url)
|
||||
.then((result) => {
|
||||
this.setState({
|
||||
user: result.data,
|
||||
isSpin: false,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
this.setState({
|
||||
isSpin: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
editTier = (item, key, e) => {
|
||||
var edit = this.state.edit;
|
||||
|
||||
var editing = false;
|
||||
for(var i=0; i<edit.length; i++)
|
||||
editing = editing || edit[i];
|
||||
|
||||
if(editing){
|
||||
this.props.showNotification("请先完成当前编辑");
|
||||
return;
|
||||
}
|
||||
else{
|
||||
edit[key] = true;
|
||||
this.setState({
|
||||
edit:edit
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
confirmEdit = async (item, key, e) => {
|
||||
let url;
|
||||
try {
|
||||
const values = await this.formRef.props.form.validateFields();
|
||||
// console.log('Success:', values);
|
||||
} catch (errorInfo) {
|
||||
this.props.showNotification('提交失败,数据不合法');
|
||||
return false;
|
||||
}
|
||||
let values = this.formRef.getItemsValue();
|
||||
// console.log(this.formRef);
|
||||
const {current_user} = this.props;
|
||||
if (this.state.new_tier == key){
|
||||
console.log("new tier");
|
||||
url = `/sponsor_tiers.json`;
|
||||
axios
|
||||
.post(url, {
|
||||
...values,
|
||||
user_id: current_user.user_id
|
||||
})
|
||||
.then((result) => {
|
||||
var {tiers, edit} = this.state;
|
||||
tiers[key] = result.data.tier;
|
||||
edit[key] = false;
|
||||
this.setState({
|
||||
tiers: tiers,
|
||||
edit: edit,
|
||||
new_tier: undefined
|
||||
})
|
||||
// message.success("新增成功");
|
||||
this.props.showNotification(`新增成功!`);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
this.props.showNotification("新增失败");
|
||||
})
|
||||
}
|
||||
else{
|
||||
url = `/sponsor_tiers/${item.id}.json`
|
||||
axios
|
||||
.put(url, {
|
||||
...values,
|
||||
})
|
||||
.then((result) => {
|
||||
var {tiers, edit} = this.state;
|
||||
tiers[key] = result.data.tier;
|
||||
edit[key] = false;
|
||||
this.setState({
|
||||
tiers: tiers,
|
||||
edit: edit,
|
||||
new_tier: undefined
|
||||
})
|
||||
// message.success("修改成功");
|
||||
this.props.showNotification(`修改成功!`);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
this.props.showNotification("修改失败");
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// TODO: 在此处加入对后端的修改请求
|
||||
|
||||
// TODO: 修改的请求实现
|
||||
}
|
||||
|
||||
cancelEdit = (item, key, e) => {
|
||||
let {tiers, edit, new_tier} = this.state;
|
||||
if (new_tier){
|
||||
tiers.pop();
|
||||
edit.pop();
|
||||
}
|
||||
else {
|
||||
edit[key] = false;
|
||||
}
|
||||
this.setState({
|
||||
tiers: tiers,
|
||||
edit: edit,
|
||||
new_tier: undefined
|
||||
})
|
||||
}
|
||||
|
||||
newTier = () => {
|
||||
if (this.state.new_tier !== undefined){
|
||||
this.props.showNotification("请先完成当前编辑")
|
||||
return;
|
||||
}
|
||||
|
||||
let {tiers, edit} = this.state;
|
||||
tiers.push({tier: 1, description: ""})
|
||||
edit.push(true);
|
||||
this.setState({
|
||||
tiers: tiers,
|
||||
edit: edit,
|
||||
new_tier: tiers.length - 1,
|
||||
})
|
||||
}
|
||||
|
||||
deleteTier = (item, key, e) => {
|
||||
// TODO: 此处向后端发送请求删除
|
||||
let {tiers, edit} = this.state;
|
||||
|
||||
let url = `/sponsor_tiers/${item.id}.json`;
|
||||
|
||||
axios
|
||||
.delete(url)
|
||||
.then((result) => {
|
||||
tiers.splice(key, 1)
|
||||
edit.splice(key, 1)
|
||||
this.setState({
|
||||
tiers: tiers,
|
||||
edit: edit,
|
||||
})
|
||||
this.props.showNotification("删除成功");
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
this.props.showNotification("删除失败");
|
||||
})
|
||||
}
|
||||
|
||||
toConformation = (item, key, e) => {
|
||||
const {user} = this.props;
|
||||
this.setState({
|
||||
route_type: undefined
|
||||
})
|
||||
this.props.history.push(`/sponsor_confirmation/${user && user.login}/${item.id}`)
|
||||
}
|
||||
|
||||
visitorTemplate = (item, key) => {
|
||||
return (
|
||||
<ul className="tier-Item">
|
||||
|
||||
<div className="tier-title">
|
||||
{item.tier} 硬币
|
||||
<Button className="right btn-border-5" onClick={(e) => this.toConformation(item, key, e)}>选择</Button>
|
||||
</div>
|
||||
<div>
|
||||
{item.description}
|
||||
</div>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
manageTemplate = (item, key) => {
|
||||
return (
|
||||
<div className="tier-Item">
|
||||
<div>
|
||||
<span className="tier-title">{item.tier} 硬币</span>
|
||||
|
||||
<Popconfirm
|
||||
title="确认删除?"
|
||||
onConfirm={e => this.deleteTier(item, key, e)}
|
||||
// onCancel={cancel}
|
||||
okText="是"
|
||||
cancelText="否"
|
||||
>
|
||||
<i className="iconfont icon-shanchu font-15 right"></i>
|
||||
</Popconfirm>
|
||||
|
||||
<i className="iconfont icon-bianji3 font-15 mr10 right" onClick={e => this.editTier(item, key, e)}></i>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
{item.description}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
editTemplate = (item, key) => {
|
||||
return (
|
||||
<div className="tier-Item">
|
||||
<EditTierForm
|
||||
initValue1={item.tier}
|
||||
initValue2={item.description}
|
||||
wrappedComponentRef={(form) => this.formRef = form}
|
||||
/>
|
||||
<Button onClick={e => this.confirmEdit(item, key, e)}>确定</Button>
|
||||
<Button onClick={e => this.cancelEdit(item, key, e)}>取消</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {tiers} = this.state;
|
||||
const { current_user} = this.props;
|
||||
const {user} = this.props;
|
||||
|
||||
// console.log("item state tiers:", tiers);
|
||||
// console.log("item props tiers:", this.props.tiers);
|
||||
|
||||
const renderList = (
|
||||
tiers && tiers.length > 0 ? tiers.map((item, key) => {
|
||||
const tier = this.state.edit[key]? (<Input></Input>):item.tier;
|
||||
const description = this.state.edit[key]? (<Input></Input>):item.description;
|
||||
|
||||
var content = "";
|
||||
if (current_user && user && user.login !== current_user.login){
|
||||
content = this.visitorTemplate(item, key);
|
||||
}
|
||||
else if(current_user && user && user.login === current_user.login && this.state.edit[key]){
|
||||
content = this.editTemplate(item, key);
|
||||
}
|
||||
else if(current_user && user && user.login === current_user.login && !this.state.edit[key]){
|
||||
content = this.manageTemplate(item, key);
|
||||
}
|
||||
|
||||
// return (
|
||||
// <ul className="list-l-Menu">
|
||||
|
||||
// <div className="font-15 mr5">
|
||||
// 金额:{amount}
|
||||
// {current_user && user && user.login === current_user.login ?
|
||||
// // (<Icon type="edit" onClick={item => this.editTier(item)}/>
|
||||
// (<i className="iconfont icon-bianji3 font-15 mr5" onClick={e => this.editTier(item, key, e)}></i>):
|
||||
// <Button >选择</Button>}
|
||||
// </div>
|
||||
// <div className="font-15 mr5">
|
||||
// 描述:{description}
|
||||
// {current_user && user && user.login === current_user.login ?
|
||||
// (<i className="iconfont icon-shanchu font-15"></i>):""}
|
||||
// </div>
|
||||
// </ul>
|
||||
|
||||
// )
|
||||
return content;
|
||||
}) : ""
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<div className="list-l-Menu">
|
||||
<p className="tier-Item tier-title">选择您的赞助等级</p>
|
||||
{/* <Divider/> */}
|
||||
{renderList}
|
||||
</div>
|
||||
{current_user && user && user.login === current_user.login ?
|
||||
( <Button type="primary" onClick={() => this.newTier()}>新增赞助等级</Button>):
|
||||
""
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default SponsorTierItem;
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
import React , { useEffect , useState } from 'react';
|
||||
import { Button ,Spin , Pagination , Popconfirm } from 'antd';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Nodata from '../Nodata';
|
||||
import axios from 'axios';
|
||||
|
||||
const limit = 10;
|
||||
function CIList(props){
|
||||
const [ page , setPage ] = useState(1);
|
||||
const [ total , setTotal ] = useState(0);
|
||||
const [ isSpining , setIsSpining] = useState(true);
|
||||
const [ list , setList ] = useState(undefined);
|
||||
let user = props.current_user;
|
||||
|
||||
useEffect(()=>{
|
||||
setIsSpining(true);
|
||||
if(user && user.login){
|
||||
getInfo();
|
||||
}
|
||||
},[user,page])
|
||||
|
||||
function getInfo(){
|
||||
const url = `/users/${user.login}/projects.json`;
|
||||
axios.get(url,{
|
||||
params:{
|
||||
limit , page , category:"manage"
|
||||
}
|
||||
}).then(result=>{
|
||||
if(result && result.data){
|
||||
setList(result.data.projects);
|
||||
setTotal(result.data.count);
|
||||
setIsSpining(false);
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
function changePage(page){
|
||||
setPage(page);
|
||||
}
|
||||
|
||||
// 取消激活
|
||||
function cancelActivate(author,identifier){
|
||||
setIsSpining(true);
|
||||
const url =`/${author && author.login}/${identifier}/deactivate.json`;
|
||||
axios.delete(url).then(result=>{
|
||||
if(result){
|
||||
getInfo();
|
||||
}else{
|
||||
setIsSpining(false);
|
||||
}
|
||||
}).catch(error=>{setIsSpining(false);})
|
||||
}
|
||||
return(
|
||||
<div style={{minHeight:"400px"}}>
|
||||
<Spin spinning={isSpining}>
|
||||
{
|
||||
list && list.length > 0 ?
|
||||
<ul className="CIList">
|
||||
{list.map((item,key)=>{
|
||||
return(
|
||||
<li key={key}>
|
||||
<span>
|
||||
<Link to={`/projects/${item.author && item.author.login}/${item.identifier}${ item.open_devops ? "/devops/list":""}`}>{item.name}</Link>
|
||||
{ item.open_devops ?
|
||||
<span className="authTag green ml20">已激活</span>
|
||||
:
|
||||
<span className="authTag red ml20">未激活</span>
|
||||
}
|
||||
</span>
|
||||
{ item.open_devops ?
|
||||
<Popconfirm
|
||||
title="确定取消激活?"
|
||||
onConfirm={()=>cancelActivate(item.author,item.identifier)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button>取消激活</Button>
|
||||
</Popconfirm>
|
||||
:
|
||||
<Button type={"primary"} onClick={()=>{props.history.push(`/projects/${item.author && item.author.login}/${item.identifier}/devops`)}}>马上激活</Button>
|
||||
}
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
:<Nodata _html="暂无数据"/>
|
||||
}
|
||||
{
|
||||
total > limit &&
|
||||
<div className="mt20 mb30" style={{textAlign:"center"}}>
|
||||
<Pagination simple onChange={changePage} pageSize={limit} current={page} total={total}></Pagination>
|
||||
</div>
|
||||
}
|
||||
</Spin>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default CIList;
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
import React , { useEffect , useState , forwardRef , useCallback } from 'react';
|
||||
import { Button , Modal , Form , Input } from 'antd';
|
||||
import { AlignCenter } from '../Component/layout';
|
||||
import axios from 'axios';
|
||||
import Modals from '../Component/Modal';
|
||||
import PasswordAuthority from '../Component/PasswordAuthority';
|
||||
import { func } from 'prop-types';
|
||||
|
||||
const TIPS = "解除CI服务器绑定后,您所有的项目构建数据将被清空。确定解除绑定?";
|
||||
function CIdispose(props){
|
||||
const [ CIData , setCIData ] = useState(undefined);
|
||||
const [ step , setStep ] = useState(0);
|
||||
const [ visible, setVisible ] = useState(false);
|
||||
const [ bindVisible, setBindVisible ] = useState(false);
|
||||
const [ ci_certification, setCi_certification ] = useState(false);
|
||||
const [ btnLoading , setBtnLoading ] = useState(false);
|
||||
|
||||
const [ authorityValBox , setAuthorityValBox] = useState(false);
|
||||
|
||||
const { form: { getFieldDecorator, validateFields , setFieldsValue } } = props;
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget, isRequired) => (
|
||||
<React.Fragment>
|
||||
<span className={isRequired ? "required" : ""}>{label}</span>
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
</Form.Item>
|
||||
</React.Fragment>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(()=>{
|
||||
getInit();
|
||||
},[])
|
||||
|
||||
function getInit(){
|
||||
const url = `/users/ci/cloud_account.json`;
|
||||
axios.get(url).then(result=>{
|
||||
if(result && result.data){
|
||||
setCIData(result.data.cloud_account);
|
||||
setStep(result.data.step);
|
||||
setCi_certification(result.data.ci_certification);
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
// 解除绑定
|
||||
function cancelBind(){
|
||||
const url = `/users/ci/cloud_account/unbind.json`;
|
||||
axios.delete(url).then(result=>{
|
||||
if(result && result.data){
|
||||
props.showNotification("成功解除绑定!");
|
||||
setVisible(false);
|
||||
getInit();
|
||||
}
|
||||
}).catch(error=>{
|
||||
setBindVisible(false);
|
||||
})
|
||||
}
|
||||
|
||||
function onCancel(){
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
// 确定绑定服务器信息
|
||||
function sureBindInfo(){
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
setBtnLoading(true);
|
||||
const url = `/users/ci/cloud_account/bind.json`;
|
||||
axios.post(url,{
|
||||
...values
|
||||
}).then(result=>{
|
||||
setBtnLoading(false);
|
||||
if(result && result.data){
|
||||
setBindVisible(false);
|
||||
setCIData(result.data.cloud_account);
|
||||
setStep(result.data.step);
|
||||
props.showNotification("服务器绑定成功!");
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
// 取消绑定服务器信息
|
||||
function cancelBindInfo(){
|
||||
setBindVisible(false);
|
||||
setFieldsValue({
|
||||
ip_num:undefined,
|
||||
secret:undefined,
|
||||
account:undefined
|
||||
})
|
||||
}
|
||||
|
||||
function okAuthority(){
|
||||
setAuthorityValBox(false);
|
||||
getInit();
|
||||
}
|
||||
|
||||
function cancelAuthority(){
|
||||
setAuthorityValBox(false);
|
||||
}
|
||||
|
||||
return(
|
||||
<div className="disposeInfo">
|
||||
<PasswordAuthority authorityValBox={authorityValBox} successFunc={okAuthority} cancelFunc={cancelAuthority}></PasswordAuthority>
|
||||
<Modal
|
||||
className="modalsStyle"
|
||||
visible={bindVisible}
|
||||
title={"绑定CI服务器地址"}
|
||||
onCancel={cancelBindInfo}
|
||||
closable={true}
|
||||
footer={
|
||||
<div>
|
||||
<Button onClick={cancelBindInfo}>取消</Button>
|
||||
<Button loading={btnLoading} type={"primary"} style={{marginLeft:"20px"}} onClick={sureBindInfo}>确定</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Form style={{marginTop:"20px"}}>
|
||||
{helper(
|
||||
"服务器IP地址:",
|
||||
"ip_num",
|
||||
[{ required: true, message: "请输入服务器IP地址" }],
|
||||
<Input
|
||||
placeholder="请输入服务器IP地址"
|
||||
style={{ width: "368px" }}
|
||||
size="large"
|
||||
/>,
|
||||
true
|
||||
)}
|
||||
{helper(
|
||||
"服务器用户名:",
|
||||
"account",
|
||||
[{ required: true, message: "请输入服务器用户名" }],
|
||||
<Input placeholder="请输入服务器用户名" size="large" />,
|
||||
true
|
||||
)}
|
||||
{helper(
|
||||
"服务器密码:",
|
||||
"secret",
|
||||
[{ required: true, message: "请输入服务器密码" }],
|
||||
<Input.Password placeholder="请输入服务器密码" size="large" />,
|
||||
true
|
||||
)}
|
||||
</Form>
|
||||
</Modal>
|
||||
<Modals visible={visible} title={"解除绑定"} content={TIPS} onOk={cancelBind} onCancel={onCancel}/>
|
||||
<div className="disposeItem">
|
||||
<AlignCenter>
|
||||
<span>CI服务器地址</span>
|
||||
{CIData && step >= 1 && <span className="ml10">{CIData.ip}</span>}
|
||||
{ step === 0 && <span className="ml10 authTag red">未绑定</span> }
|
||||
{ step > 0 && !ci_certification && <span className="ml10 authTag red">未认证</span> }
|
||||
{ ci_certification && <span className="ml10 authTag green">已认证</span> }
|
||||
</AlignCenter>
|
||||
<AlignCenter>
|
||||
{ step === 0 && <Button type={'primary'} onClick={()=>setBindVisible(true)} >马上绑定</Button> }
|
||||
{ step > 0 && !ci_certification && <Button type={'primary'} style={{color:"#fff"}} onClick={()=>setAuthorityValBox(true)} target="_blank">马上认证</Button> }
|
||||
{ step >= 1 && <Button type={'danger'} className="ml20" onClick={()=>setVisible(true)}>解除绑定</Button> }
|
||||
</AlignCenter>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Form.create()(forwardRef(CIdispose));;
|
||||
|
|
@ -70,4 +70,52 @@ $flex:flex;
|
|||
margin: 8px 0 0 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul.ant-menu.menuStyle{
|
||||
padding:0px 30px;
|
||||
font-size: 16px;
|
||||
li{
|
||||
height: 70px;
|
||||
line-height: 70px;
|
||||
padding:0px;
|
||||
margin-right: 30px!important;
|
||||
}
|
||||
}
|
||||
.disposeInfo{
|
||||
padding:0px 30px;
|
||||
min-height: 400px;
|
||||
.disposeItem{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding:30px 0px;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
}
|
||||
}
|
||||
.authTag{
|
||||
display: inline-block;
|
||||
padding:0px 10px;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
&.red{
|
||||
border:1px solid #F73030;
|
||||
color: #F73030;
|
||||
}
|
||||
&.green{
|
||||
border:1px solid #28BD6C;
|
||||
color: #28BD6C;
|
||||
}
|
||||
}
|
||||
.CIList{
|
||||
padding:0px 30px;
|
||||
min-height: 400px;
|
||||
li{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding:28px 0px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,15 @@ import './Index.scss';
|
|||
import Loadable from "react-loadable";
|
||||
import Loading from "../../Loading";
|
||||
|
||||
|
||||
const InfosDevOps = Loadable({
|
||||
loader: () => import("./devOpsCI"),
|
||||
loading: Loading,
|
||||
});
|
||||
const InfosDevOpsCD = Loadable({
|
||||
loader: () => import("./devOpsCD"),
|
||||
loading: Loading,
|
||||
});
|
||||
const InfosUser = Loadable({
|
||||
loader: () => import("./InfosUser"),
|
||||
loading: Loading,
|
||||
|
|
@ -36,6 +45,19 @@ const UndoEvents = Loadable({
|
|||
loader: () => import("./undo_events"),
|
||||
loading: Loading,
|
||||
})
|
||||
const Wallet = Loadable({
|
||||
loader: () => import("./sponsor/wallet"),
|
||||
loading: Loading,
|
||||
});
|
||||
const SponsorManagement = Loadable({
|
||||
loader: () => import("./sponsor/SponsorManagement"),
|
||||
loading: Loading,
|
||||
});
|
||||
const SponsorDataCharts = Loadable({
|
||||
loader: () => import("./sponsor/communityData"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
class Infos extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
|
@ -43,7 +65,10 @@ class Infos extends Component {
|
|||
isSpin: false,
|
||||
user: undefined,
|
||||
project_type: undefined,
|
||||
route_type: undefined
|
||||
route_type: undefined,
|
||||
c: undefined,
|
||||
sponsor_management: undefined,
|
||||
choose_chart: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +103,10 @@ class Infos extends Component {
|
|||
change_project_type = (type) => {
|
||||
const {user} = this.state
|
||||
this.setState({
|
||||
project_type: type ,
|
||||
project_type: type,
|
||||
choose_wallet: false,
|
||||
sponsor_management: undefined,
|
||||
choose_chart: undefined,
|
||||
route_type: undefined
|
||||
})
|
||||
let url = `/users/${user && user.login}`
|
||||
|
|
@ -89,6 +117,15 @@ class Infos extends Component {
|
|||
|
||||
};
|
||||
|
||||
change_devops_type=(type)=>{
|
||||
const {user} = this.state;
|
||||
this.setState({
|
||||
project_type: type ,
|
||||
route_type: undefined
|
||||
})
|
||||
this.props.history.push(`/users/${user && user.login}/devops/${type}`);
|
||||
}
|
||||
|
||||
undo_link = () => {
|
||||
const {user} = this.state
|
||||
this.setState({
|
||||
|
|
@ -111,10 +148,63 @@ class Infos extends Component {
|
|||
this.props.history.push(`/users/${user && user.login}/organizes`)
|
||||
}
|
||||
|
||||
sponsor_link = () => {
|
||||
const {user} = this.state
|
||||
this.setState({
|
||||
route_type: undefined
|
||||
})
|
||||
this.props.history.push(`/sponsor/${user && user.login}`)
|
||||
}
|
||||
|
||||
sponsor_management_link = () => {
|
||||
const {user} = this.state
|
||||
this.setState({
|
||||
route_type: undefined,
|
||||
sponsor_management: true,
|
||||
project_type: undefined,
|
||||
choose_wallet: undefined,
|
||||
choose_chart: undefined,
|
||||
})
|
||||
this.props.history.push(`/users/${user && user.login}/sponsor_management`)
|
||||
}
|
||||
|
||||
wallet_link = () => {
|
||||
const {user} = this.state
|
||||
this.setState({
|
||||
project_type: undefined,
|
||||
choose_wallet: true,
|
||||
route_type: undefined,
|
||||
sponsor_management: undefined,
|
||||
choose_chart: undefined,
|
||||
})
|
||||
this.props.history.push(`/users/${user && user.login}/wallet`)
|
||||
}
|
||||
|
||||
sponsor_setting_link = () => {
|
||||
const {user} = this.state
|
||||
this.setState({
|
||||
route_type: undefined
|
||||
})
|
||||
this.props.history.push(`/users/${user && user.login}/sponsor_setting`)
|
||||
}
|
||||
|
||||
sponsor_statistic = () => {
|
||||
const {user} = this.state
|
||||
this.setState({
|
||||
project_type: undefined,
|
||||
choose_wallet: undefined,
|
||||
route_type: undefined,
|
||||
sponsor_management: undefined,
|
||||
choose_chart: true
|
||||
})
|
||||
this.props.history.push(`/users/${user && user.login}/sponsor_community_data`)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { current_user, mygetHelmetapi } = this.props;
|
||||
const { user, isSpin, project_type, route_type } = this.state;
|
||||
const { user, isSpin, project_type, route_type, choose_wallet, choose_chart, sponsor_management } = this.state;
|
||||
// console.log("current", current_user)
|
||||
// console.log("user", user)
|
||||
return (
|
||||
<div className="newMain clearfix">
|
||||
<Spin spinning={isSpin}>
|
||||
|
|
@ -137,10 +227,10 @@ class Infos extends Component {
|
|||
|
||||
<div>
|
||||
{user && current_user && user.login === current_user.login && (
|
||||
<div className="user-info-star-button ">
|
||||
<div className="user-info-star-button">
|
||||
<Button
|
||||
block
|
||||
className="text-button-grey"
|
||||
className="text-button-grey mr5"
|
||||
href={`${
|
||||
mygetHelmetapi &&mygetHelmetapi.new_course&&
|
||||
mygetHelmetapi.new_course.edit_account
|
||||
|
|
@ -148,10 +238,19 @@ class Infos extends Component {
|
|||
target="_blank"
|
||||
>
|
||||
{" "}
|
||||
<i className="iconfont icon-shezhi4 font-15 mr5"></i>
|
||||
<i className="iconfont icon-shezhi4 font-15"></i>
|
||||
修改资料
|
||||
</Button>
|
||||
<Button
|
||||
block
|
||||
className="text-button-grey"
|
||||
href={`/sponsor/${user && user.login}`}
|
||||
>
|
||||
赞助信息修改
|
||||
</Button>
|
||||
|
||||
</div>
|
||||
|
||||
)}
|
||||
{current_user && user && user.login !== current_user.login && (
|
||||
<div className="user-info-star-button ">
|
||||
|
|
@ -162,6 +261,13 @@ class Infos extends Component {
|
|||
fontClass={"font-14 ml5"}
|
||||
starText={"关注TA"}
|
||||
/>
|
||||
<Button
|
||||
block
|
||||
className="text-button-grey ml-5"
|
||||
href={`/sponsor/${user && user.login}`}
|
||||
>
|
||||
赞助
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -200,6 +306,7 @@ class Infos extends Component {
|
|||
</div>
|
||||
</div>
|
||||
)} */}
|
||||
|
||||
<div className="bgcF">
|
||||
<ul className="list-l-Menu">
|
||||
<li className="MenuTitle" onClick={() => this.change_project_type(undefined)}>
|
||||
|
|
@ -233,6 +340,33 @@ class Infos extends Component {
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{
|
||||
current_user && current_user.login &&
|
||||
<div className="bgcF">
|
||||
<ul className="list-l-Menu">
|
||||
<li className="MenuTitle">
|
||||
<i className="iconfont icon-gongzuoliu font-15 mr5"></i>
|
||||
DevOps工作流
|
||||
<i className="iconfont icon-youjiantou font-15 mr20 color-grey-9 pull-right"></i>
|
||||
</li>
|
||||
<li className={project_type && project_type === "CIService" ? "active" : ""} onClick={() => this.change_devops_type("CIService")}>
|
||||
<p>
|
||||
<span className="font-16 color-grey-3">CI服务</span>
|
||||
</p>
|
||||
</li>
|
||||
{/* <li className={project_type && project_type === "CDService" ? "active" : ""} onClick={() => this.change_devops_type("CDService")}>
|
||||
<p>
|
||||
<span className="font-16">CD服务</span>
|
||||
<span className="color-blue">
|
||||
{user && user.common_projects_count}
|
||||
</span>
|
||||
</p>
|
||||
</li> */}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
{/* <div className="bgcF">
|
||||
<div className="list-l-Menu">
|
||||
<p className="list-l-p pd20" onClick={() => this.organize_link()} >
|
||||
|
|
@ -245,7 +379,56 @@ class Infos extends Component {
|
|||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div> */}
|
||||
</div> */}
|
||||
{current_user && user && user.login == current_user.login && (
|
||||
|
||||
<div className="bgcF">
|
||||
<ul className="list-l-Menu">
|
||||
<li className="MenuTitle">
|
||||
<i className="iconfont icon-bianzu1 font-15 mr5"></i>
|
||||
赞助管理
|
||||
<i className="iconfont icon-youjiantou font-15 mr20 color-grey-9 pull-right"></i>
|
||||
</li>
|
||||
<li className={choose_wallet ? "active" : ""} onClick={() => this.wallet_link()}>
|
||||
<p>
|
||||
<span className="font-16">我的钱包</span>
|
||||
<span className="color-blue">
|
||||
{/* {user && user.common_projects_count} */}
|
||||
</span>
|
||||
</p>
|
||||
</li>
|
||||
<li className={sponsor_management ? "active" : ""} onClick={() => this.sponsor_management_link()}>
|
||||
<p>
|
||||
<span className="font-16">赞助管理</span>
|
||||
<span className="color-blue">
|
||||
{/* {user && user.sync_mirror_projects_count} */}
|
||||
</span>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{current_user && user && user.login == current_user.login && current_user.admin &&(
|
||||
|
||||
<div className="bgcF">
|
||||
<ul className="list-l-Menu">
|
||||
<li className="MenuTitle">
|
||||
<i className="iconfont icon-dashujucunchu font-15 mr5"></i>
|
||||
社区统计信息
|
||||
<i className="iconfont icon-youjiantou font-15 mr20 color-grey-9 pull-right"></i>
|
||||
</li>
|
||||
<li className={choose_chart ? "active" : ""} onClick={() => this.sponsor_statistic()}>
|
||||
<p>
|
||||
<span className="font-16">赞助信息统计</span>
|
||||
<span className="color-blue">
|
||||
{/* {user && user.common_projects_count} */}
|
||||
</span>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="list-right">
|
||||
{user && (
|
||||
|
|
@ -263,12 +446,42 @@ class Infos extends Component {
|
|||
return <UndoEvents {...this.props} {...this.state} />;
|
||||
}}
|
||||
></Route>
|
||||
<Route
|
||||
path="/users/:username/wallet"
|
||||
render={(props) => {
|
||||
return <Wallet {...this.props} {...this.state} />;
|
||||
}}
|
||||
></Route>
|
||||
<Route
|
||||
path="/users/:username/sponsor_management"
|
||||
render={(props) => {
|
||||
return <SponsorManagement {...this.props} {...this.state} />;
|
||||
}}
|
||||
></Route>
|
||||
<Route
|
||||
path="/users/:username/sponsor_community_data"
|
||||
render={(props) => {
|
||||
return <SponsorDataCharts {...this.props} {...this.state} is_sponsor={true}/>;
|
||||
}}
|
||||
></Route>
|
||||
<Route
|
||||
path="/users/:username/fan_users"
|
||||
render={() => {
|
||||
return <FanUser {...this.props} {...this.state} userType="fan_users"/>;
|
||||
}}
|
||||
></Route>
|
||||
<Route
|
||||
path="/users/:username/devops/CDService"
|
||||
render={() => {
|
||||
return <InfosDevOpsCD {...this.props} {...this.state} />;
|
||||
}}
|
||||
></Route>
|
||||
<Route
|
||||
path="/users/:username/devops/CIService"
|
||||
render={() => {
|
||||
return <InfosDevOps {...this.props} {...this.state} />;
|
||||
}}
|
||||
></Route>
|
||||
<Route
|
||||
path="/users/:username/projects/:project_type"
|
||||
render={() => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
import React , { useEffect , useState } from 'react';
|
||||
|
||||
function DevOpsCD(){
|
||||
return(
|
||||
<div>222</div>
|
||||
)
|
||||
}
|
||||
export default DevOpsCD;
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import React , { useEffect , useState } from 'react';
|
||||
import { Menu } from 'antd';
|
||||
import './Index.scss';
|
||||
import CIdispose from './CIdispose';
|
||||
import CIList from './CIList';
|
||||
|
||||
|
||||
function DevOpsCI(props){
|
||||
const [ selectKey , setSelectKey ] = useState("dispose");
|
||||
|
||||
function changeKeys(e){
|
||||
setSelectKey(e.key);
|
||||
}
|
||||
|
||||
return(
|
||||
<div>
|
||||
<Menu mode="horizontal" className="menuStyle" onClick={changeKeys} selectedKeys={[selectKey]}>
|
||||
<Menu.Item key="dispose">服务器配置</Menu.Item>
|
||||
<Menu.Item key="list">项目列表</Menu.Item>
|
||||
</Menu>
|
||||
{
|
||||
selectKey === "dispose" ?
|
||||
<CIdispose {...props}/>
|
||||
:
|
||||
<CIList {...props}/>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default DevOpsCI;
|
||||
|
|
@ -28,10 +28,15 @@
|
|||
.mt-n15{margin-top: -15px;}
|
||||
.position-relative{position: relative;}
|
||||
.mr-5{margin-right: 5px;}
|
||||
.mt-5{margin-top: 5px;}
|
||||
.ml-5{margin-left: 5px;}
|
||||
a.text-button-grey{
|
||||
color: rgba(0, 0, 0, 0.65)
|
||||
}
|
||||
.user-info-star-button{margin: 20px 50px 0 50px}
|
||||
.user-info-star-button{
|
||||
display: flex;
|
||||
margin: 20px 20px 0 20px
|
||||
}
|
||||
.list-l-p{
|
||||
width: 100%;
|
||||
display: -ms-flexbox;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Tooltip } from 'antd';
|
||||
import '../../css/index.scss'
|
||||
import '../../Main/list.css';
|
||||
|
||||
class CoinChangeItem extends Component {
|
||||
TurnToDetail = (login, url) => {
|
||||
this.props.history.push({
|
||||
pathname: url,
|
||||
state: login
|
||||
})
|
||||
}
|
||||
render() {
|
||||
const { coinChanges, current_user } = this.props;
|
||||
const renderList = (
|
||||
coinChanges && coinChanges.length > 0 ? coinChanges.map((item, key) => {
|
||||
let url = current_user && item.to_user_login == current_user.login? `/users/${item.from_user_login}`:`/users/${item.to_user_login}`;
|
||||
return (
|
||||
<div className="p-r-Item" key={key}>
|
||||
<div className="p-r-Infos">
|
||||
<p className="break_word task-hide-2 mt10" style={{ maxHeight: "44px",lineHeight:"22px" }}>金额:{current_user && item.to_user_login == current_user.login? "收入":"支出"}{item.amount}硬币</p>
|
||||
<p className="break_word task-hide-2 mt10" style={{ maxHeight: "44px",lineHeight:"22px" }}>变动原因:{item.reason}</p>
|
||||
{/* <p className="break_word task-hide-2 mt10" style={{ maxHeight: "44px",lineHeight:"22px" }}>备注:{item.description}</p> */}
|
||||
|
||||
<div className="p-r-about">
|
||||
<span className="p-r-detail">
|
||||
<span><label>时间:</label>{item.date}</span>
|
||||
{current_user && item.to_user_login == current_user.login?
|
||||
(<span><label>金额来源:</label><a href={url}>{item.from_user}</a></span>):
|
||||
(<span><label>金额去向:</label><a href={url}>{item.to_user}</a></span>)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}) : ""
|
||||
)
|
||||
return (
|
||||
<div className="project-list minH-670">
|
||||
{renderList}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
export default CoinChangeItem;
|
||||
|
|
@ -0,0 +1,309 @@
|
|||
import React, { Component } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Menu, Input, Spin, Pagination, Popover, Button, Divider } from "antd";
|
||||
import SponsorBarCharts from "./charts/sponsorBarChart";
|
||||
import SponsorPieCharts from "./charts/sponsorPieChart";
|
||||
|
||||
import axios from "axios";
|
||||
import CoinChangeItem from "./CoinChangeItem";
|
||||
import Nodata from "../../Nodata";
|
||||
import img_array from "../../Images/array.png";
|
||||
import SponsorList from "./sponsor_list";
|
||||
import "../../sponsor/sponsor.css";
|
||||
|
||||
// import "../new_user.css";
|
||||
// const Search = Input.Search;
|
||||
|
||||
// const tempData = [
|
||||
// {image_url: "avatars/User/b", username: "万山川", user_id: 1369, visible: true, sponsor: false, login:"alpc104", start_time: "2020-08-01", stop_time: "-", amount: 100},
|
||||
// {image_url: "avatars/User/b", username: "万山川", user_id: 1369, visible: true, sponsor: true, login:"alpc104", start_time: "2020-08-01", stop_time: "-", amount: 100},
|
||||
// {image_url: "avatars/User/b", username: "万山川", user_id: 1369, visible: false, sponsor: false, login:"alpc104", start_time: "2020-08-01", stop_time: "-", amount: 100},
|
||||
// {image_url: "avatars/User/b", username: "万山川", user_id: 1369, visible: false, sponsor: true, login:"alpc104", start_time: "2020-08-01", stop_time: "-", amount: 100},
|
||||
// {image_url: "avatars/User/b", username: "万山川", user_id: 1369, visible: false, sponsor: false, login:"alpc104", start_time: "2020-08-01", stop_time: "-", amount: 100},
|
||||
// {image_url: "avatars/User/b", username: "万山川", user_id: 1369, visible: false, sponsor: false, login:"alpc104", start_time: "2020-08-01", stop_time: "2020-09-05", amount: 100},
|
||||
// {image_url: "avatars/User/b", username: "万山川", user_id: 1369, visible: false, sponsor: true, login:"alpc104", start_time: "2020-08-01", stop_time: "2020-09-05", amount: 100},
|
||||
// {image_url: "avatars/User/b", username: "万山川", user_id: 1369, visible: false, sponsor: false, login:"alpc104", start_time: "2020-08-01", stop_time: "2020-09-05", amount: 100},
|
||||
// {image_url: "avatars/User/b", username: "万山川", user_id: 1369, visible: false, sponsor: false, login:"alpc104", start_time: "2020-08-01", stop_time: "2020-09-05", amount: 100},
|
||||
// {image_url: "avatars/User/b", username: "万山川", user_id: 1369, visible: false, sponsor: false, login:"alpc104", start_time: "2020-08-01", stop_time: "2020-09-05", amount: 100},
|
||||
// {image_url: "avatars/User/b", username: "万山川", user_id: 1369, visible: false, sponsor: false, login:"alpc104", start_time: "2020-08-01", stop_time: "2020-09-05", amount: 100},
|
||||
// ];
|
||||
|
||||
|
||||
class SponsorManagement extends Component{
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
page: 1,
|
||||
limit: 15,
|
||||
sort_by: undefined,
|
||||
totalCount: undefined,
|
||||
isSpin: false,
|
||||
total: undefined,
|
||||
category: "sponsoring",
|
||||
is_sponsor: false,
|
||||
sponsors: undefined,
|
||||
displayList: undefined,
|
||||
chartsData: {income:[], outcome:[]},
|
||||
};
|
||||
}
|
||||
|
||||
changeCategory = (cate) => {
|
||||
this.setState({
|
||||
category: cate.target.value,
|
||||
page: 1,
|
||||
}, ()=>{
|
||||
if(this.state.category === "chart")
|
||||
this.get_chart_data();
|
||||
else
|
||||
this.get_sponsors();
|
||||
});
|
||||
// if(cate.target.value === "chart"){
|
||||
// this.setState({
|
||||
// category: cate.target.value,
|
||||
// page: 1,
|
||||
// });
|
||||
// }
|
||||
// else{
|
||||
// this.setState({
|
||||
// category: cate.target.value,
|
||||
// page: 1,
|
||||
// }, ()=>{this.get_sponsors();});
|
||||
// }
|
||||
};
|
||||
|
||||
componentDidMount = () => {
|
||||
this.get_sponsors();
|
||||
}
|
||||
|
||||
get_chart_data = () => {
|
||||
this.setState({
|
||||
isSpin: true
|
||||
})
|
||||
|
||||
let url = `/wallets/balance_chart.json`;
|
||||
const {current_user} = this.props;
|
||||
let user_id = current_user && current_user.user_id;
|
||||
if (current_user){
|
||||
axios.get(url, {
|
||||
params: {
|
||||
id: user_id,
|
||||
sponsor: true,
|
||||
}})
|
||||
.then((result) => {
|
||||
this.setState({
|
||||
chartsData: result.data,
|
||||
isSpin: false,
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
this.setState({
|
||||
isSpin: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
get_sponsors = ()=>{
|
||||
const user_id = this.props.current_user.user_id;
|
||||
|
||||
let url = this.state.is_sponsor? `sponsoring`:`sponsored`;
|
||||
url = this.state.category === "stopped"? `stopped_` + url: url;
|
||||
url = `/sponsorships/` + url + `.json`;
|
||||
|
||||
const {page, limit} = this.state;
|
||||
this.setState({
|
||||
isSpin: true
|
||||
})
|
||||
axios.get(url, {
|
||||
params: {
|
||||
id: user_id,
|
||||
page: page,
|
||||
limit: limit,
|
||||
}})
|
||||
.then((result) => {
|
||||
// console.log(result);
|
||||
this.setState({
|
||||
displayList: result.data.sponsorships,
|
||||
total: result.data.count,
|
||||
isSpin: false,
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
this.setState({
|
||||
isSpin: false,
|
||||
});
|
||||
});
|
||||
// this.setState({
|
||||
// sponsors: tempData,
|
||||
// displayList: tempData,
|
||||
// })
|
||||
}
|
||||
|
||||
//切换页数
|
||||
changePage = (page) => {
|
||||
this.setState({
|
||||
page: page
|
||||
}, ()=>{this.get_sponsors()})
|
||||
};
|
||||
|
||||
// 排序
|
||||
ChangeSoryBy = (e) => {
|
||||
console.log(e.key)
|
||||
};
|
||||
|
||||
changeSearchValue = (e) => {
|
||||
this.setState({
|
||||
search: e.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
menu =()=> (
|
||||
<Menu onClick={this.ChangeSoryBy}>
|
||||
<Menu.Item key="time_order">时间从近到远排序</Menu.Item>
|
||||
<Menu.Item key="reverse_time_order">时间从远到近排序</Menu.Item>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
category_button=(category)=>{
|
||||
const { current_user, user } = this.props;
|
||||
const button_lists =
|
||||
user && current_user && user.login === current_user.login
|
||||
? [
|
||||
{ type: "sponsoring", name: "赞助中" },
|
||||
{ type: "stopped", name: "已终止" },
|
||||
{ type: "chart", name: "统计图表" },
|
||||
]
|
||||
:
|
||||
[];
|
||||
|
||||
let list = button_lists.map((item, key) => {
|
||||
return (
|
||||
<span key={key} className="pr15">
|
||||
<Button
|
||||
type={
|
||||
(category && category === item.type) || (!category && !item.type)
|
||||
? "primary"
|
||||
: "default"
|
||||
}
|
||||
ghost={
|
||||
(category && category === item.type) || (!category && !item.type)
|
||||
}
|
||||
value={item.type}
|
||||
onClick={this.changeCategory}
|
||||
>
|
||||
{item.name}
|
||||
</Button>
|
||||
</span>
|
||||
);
|
||||
})
|
||||
return list;
|
||||
}
|
||||
|
||||
changeStatus=(check_is_sponsor, e)=>{
|
||||
// const {is_sponsor} = this.state
|
||||
// const new_is_sponsor = is_sponsor === check_is_sponsor ? undefined : check_is_sponsor
|
||||
// this.state.is_sponsor = check_is_sponsor;
|
||||
this.setState({
|
||||
is_sponsor: check_is_sponsor,
|
||||
page: 1,
|
||||
}, ()=>{
|
||||
if(this.state.category === "chart")
|
||||
this.get_chart_data();
|
||||
else
|
||||
this.get_sponsors();
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { current_user, user } = this.props;
|
||||
const { category , is_sponsor, sponsors, displayList, chartsData} = this.state;
|
||||
const {isSpin, total, search, limit, page }= this.state;
|
||||
// console.log(displayList);
|
||||
const sponsorList = displayList && displayList.length > 0 ?
|
||||
<SponsorList
|
||||
{...this.props}
|
||||
userClass={"w-33"}
|
||||
current_user={current_user}
|
||||
users={displayList}
|
||||
rerender={this.get_sponsors}
|
||||
history={this.props.history}
|
||||
></SponsorList>
|
||||
:
|
||||
<Nodata _html={`暂时没有数据`} />
|
||||
|
||||
const chartComponent = <div>
|
||||
<p>七天内赞助{this.state.is_sponsor?"支出":"收入"}图</p>
|
||||
<SponsorBarCharts is_sponsor={this.state.is_sponsor} data={chartsData}></SponsorBarCharts>
|
||||
{/* <p>七天内赞助{this.state.is_sponsor?"支出":"收入"}图</p>
|
||||
<SponsorPieCharts is_sponsor={this.state.is_sponsor}></SponsorPieCharts> */}
|
||||
</div>
|
||||
|
||||
const displayComponent = category==="chart"?chartComponent
|
||||
:
|
||||
sponsorList;
|
||||
|
||||
return (
|
||||
// <div className="list-right boxShandow radius-2" style={{padding:0}}>
|
||||
<Spin spinning={isSpin}>
|
||||
{/* <div className="list-r-operation"> */}
|
||||
{/* <Search
|
||||
placeholder="输入关键字进行搜索"
|
||||
enterButton="搜索"
|
||||
size="large"
|
||||
onSearch={this.get_sponsors}
|
||||
className="list-r-Search"
|
||||
value={search}
|
||||
onChange={this.changeSearchValue}
|
||||
/> */}
|
||||
{/* <div>
|
||||
|
||||
<Popover content={this.menu()} trigger={["click"]} placement="bottom">
|
||||
<a className="ant-dropdown-link">
|
||||
<span className="color-blue font-16">
|
||||
排序 <img src={img_array} alt="" width="10px" />
|
||||
</span>
|
||||
</a>
|
||||
</Popover>
|
||||
</div> */}
|
||||
{/* </div> */}
|
||||
<div className="infosType">
|
||||
<div>{this.category_button(category)}</div>
|
||||
{
|
||||
user && current_user && user.login === current_user.login ?
|
||||
<div className="infoStatus">
|
||||
<span className={is_sponsor === true ? "active" : "" } onClick={(e)=>this.changeStatus(true, e)}>我赞助的</span>
|
||||
{
|
||||
!is_sponsor ? (<Divider type={"vertical"} className="statusDivider" ></Divider>):""
|
||||
}
|
||||
<span className={is_sponsor === false ? "active" : "" } onClick={(e)=>this.changeStatus(false, e)}>赞助我的</span>
|
||||
</div>
|
||||
:""
|
||||
}
|
||||
</div>
|
||||
{user && current_user && user.login === current_user.login?
|
||||
displayComponent:<Nodata _html={`暂时没有项目`} />
|
||||
}
|
||||
{
|
||||
total && total > limit && category!="chart"?
|
||||
<div className="edu-txt-center pt30 mb30 border-top-grey">
|
||||
<Pagination
|
||||
simple
|
||||
defaultCurrent={page}
|
||||
total={total}
|
||||
pageSize={limit}
|
||||
onChange={this.changePage}
|
||||
></Pagination>
|
||||
</div>
|
||||
:
|
||||
""
|
||||
}
|
||||
</Spin>
|
||||
// </div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default SponsorManagement;
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
import React, { Component } from 'react';
|
||||
import {XYPlot, VerticalBarSeries, VerticalGridLines, HorizontalGridLines, XAxis, YAxis, Crosshair, DiscreteColorLegend} from 'react-vis';
|
||||
// import DiscreteColorLegend from 'legends/discrete-color-legend';
|
||||
import "./style.scss";
|
||||
|
||||
// const ONE_DAY = 86400000;
|
||||
// const d = new Date().getTime()-ONE_DAY*7;
|
||||
|
||||
// const data = [
|
||||
// {x: new Date(d+ONE_DAY).toLocaleDateString(), y: 8},
|
||||
// {x: new Date(d+ONE_DAY*2).toLocaleDateString(), y: 5},
|
||||
// {x: new Date(d+ONE_DAY*3).toLocaleDateString(), y: 4},
|
||||
// {x: new Date(d+ONE_DAY*4).toLocaleDateString(), y: 9},
|
||||
// {x: new Date(d+ONE_DAY*5).toLocaleDateString(), y: 2},
|
||||
// {x: new Date(d+ONE_DAY*6).toLocaleDateString(), y: 7},
|
||||
// {x: new Date(d+ONE_DAY*7).toLocaleDateString(), y: 2},
|
||||
// ];
|
||||
|
||||
// const data2 = [
|
||||
// {x: new Date(d+ONE_DAY).toLocaleDateString(), y: 2},
|
||||
// {x: new Date(d+ONE_DAY*2).toLocaleDateString(), y: 3},
|
||||
// {x: new Date(d+ONE_DAY*3).toLocaleDateString(), y: 1},
|
||||
// {x: new Date(d+ONE_DAY*4).toLocaleDateString(), y: 5},
|
||||
// {x: new Date(d+ONE_DAY*5).toLocaleDateString(), y: 4},
|
||||
// {x: new Date(d+ONE_DAY*6).toLocaleDateString(), y: 0},
|
||||
// {x: new Date(d+ONE_DAY*7).toLocaleDateString(), y: 2},
|
||||
// ];
|
||||
|
||||
const ITEMS = [
|
||||
{title: '收入', strokeWidth: 13},
|
||||
{title: '支出', strokeWidth: 13}
|
||||
];
|
||||
|
||||
class CoinChangeCharts extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
crosshairValues: []
|
||||
};
|
||||
// console.log(this.props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {chartsData} = this.props;
|
||||
if(chartsData == undefined){
|
||||
return (<div className="App"></div>);
|
||||
}
|
||||
var max = 0;
|
||||
for(var i=0; i<chartsData.income.length; i++){
|
||||
max = Math.max(max, chartsData.income[i].y, chartsData.outcome[i].y);
|
||||
}
|
||||
return (
|
||||
<div className="App">
|
||||
<DiscreteColorLegend height={80} width={1300} items={ITEMS} />
|
||||
<XYPlot xType="ordinal" height={400} width= {700} yDomain={[-0.5, max]}>
|
||||
<VerticalGridLines />
|
||||
<HorizontalGridLines />
|
||||
<XAxis style={{
|
||||
line: {stroke: '#ADDDE1'},
|
||||
ticks: {stroke: '#ADDDE1'},
|
||||
text: {stroke: 'none', fill: '#6b6b76', fontWeight: 600}
|
||||
}}/>
|
||||
<YAxis style={{
|
||||
line: {stroke: '#ADDDE1'},
|
||||
ticks: {stroke: '#ADDDE1'},
|
||||
text: {stroke: 'none', fill: '#6b6b76', fontWeight: 600}
|
||||
}}/>
|
||||
<VerticalBarSeries data={chartsData.income} />
|
||||
<VerticalBarSeries data={chartsData.outcome} />
|
||||
|
||||
</XYPlot>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CoinChangeCharts;
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
import React, { Component } from 'react';
|
||||
import {XYPlot, VerticalBarSeries, VerticalGridLines, HorizontalGridLines, XAxis, YAxis, Crosshair, DiscreteColorLegend} from 'react-vis';
|
||||
// import DiscreteColorLegend from 'legends/discrete-color-legend';
|
||||
import "./style.scss";
|
||||
|
||||
const ONE_DAY = 86400000;
|
||||
const d = new Date().getTime()-ONE_DAY*7;
|
||||
|
||||
const data = [
|
||||
{x: new Date(d+ONE_DAY).toLocaleDateString(), y: 6},
|
||||
{x: new Date(d+ONE_DAY*2).toLocaleDateString(), y: 3},
|
||||
{x: new Date(d+ONE_DAY*3).toLocaleDateString(), y: 2},
|
||||
{x: new Date(d+ONE_DAY*4).toLocaleDateString(), y: 7},
|
||||
{x: new Date(d+ONE_DAY*5).toLocaleDateString(), y: 0},
|
||||
{x: new Date(d+ONE_DAY*6).toLocaleDateString(), y: 5},
|
||||
{x: new Date(d+ONE_DAY*7).toLocaleDateString(), y: 0},
|
||||
];
|
||||
|
||||
const data2 = [
|
||||
{x: new Date(d+ONE_DAY).toLocaleDateString(), y: 3},
|
||||
{x: new Date(d+ONE_DAY*2).toLocaleDateString(), y: 4},
|
||||
{x: new Date(d+ONE_DAY*3).toLocaleDateString(), y: 2},
|
||||
{x: new Date(d+ONE_DAY*4).toLocaleDateString(), y: 6},
|
||||
{x: new Date(d+ONE_DAY*5).toLocaleDateString(), y: 5},
|
||||
{x: new Date(d+ONE_DAY*6).toLocaleDateString(), y: 1},
|
||||
{x: new Date(d+ONE_DAY*7).toLocaleDateString(), y: 3},
|
||||
];
|
||||
|
||||
const ITEMS = [
|
||||
{title: '收入', strokeWidth: 13},
|
||||
{title: '支出', strokeWidth: 13}
|
||||
];
|
||||
|
||||
class SponsorBarCharts extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
crosshairValues: []
|
||||
};
|
||||
console.log(this.props)
|
||||
}
|
||||
|
||||
componentWillReceiveProps = () => {
|
||||
this.setState({
|
||||
crosshairValues: []
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const chartsData = this.props.is_sponsor?this.props.data.outcome:this.props.data.income;
|
||||
var max = 0;
|
||||
for(var i=0; i<chartsData.length; i++){
|
||||
max = Math.max(max, chartsData[i].y);
|
||||
}
|
||||
return (
|
||||
<div className="App">
|
||||
{/* <DiscreteColorLegend height={20} width={1300} items={ITEMS} /> */}
|
||||
<XYPlot animation={true} xType="ordinal" height={400} width= {700} yDomain={[-0.5, max]}>
|
||||
<VerticalGridLines />
|
||||
<HorizontalGridLines />
|
||||
<XAxis style={{
|
||||
line: {stroke: '#ADDDE1'},
|
||||
ticks: {stroke: '#ADDDE1'},
|
||||
text: {stroke: 'none', fill: '#6b6b76', fontWeight: 600}
|
||||
}}/>
|
||||
<YAxis style={{
|
||||
line: {stroke: '#ADDDE1'},
|
||||
ticks: {stroke: '#ADDDE1'},
|
||||
text: {stroke: 'none', fill: '#6b6b76', fontWeight: 600}
|
||||
} }/>
|
||||
<VerticalBarSeries data={chartsData} />
|
||||
|
||||
</XYPlot>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SponsorBarCharts;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue