Compare commits

..

45 Commits

Author SHA1 Message Date
caishi 465c4cc8c7 04-28休假期修改issue --需合并至其它分支(合并请求相关) 2021-04-28 20:23:57 +08:00
caishi 37668ddcd4 组织团队-无数据显示错误 2021-04-27 09:47:10 +08:00
caishi 7102594444 代码库编辑文件-切换到其它目录后要重新将编辑状态改为显示状态 2021-04-25 17:48:58 +08:00
caishi b2f2df65bb 样式覆盖 2021-04-23 18:07:15 +08:00
caishi 8a577fb263 资源库 2021-04-23 17:16:50 +08:00
caishi 5c491071b6 +上 关注后不需要提示 2021-04-23 16:37:16 +08:00
caishi c554237076 +上 贡献者悬浮框里增加的跳转链接不要新开页 2021-04-23 16:37:06 +08:00
caishi d22a741bf7 贡献者-悬浮内容增加跳转链接 2021-04-23 16:36:56 +08:00
caishi 383b3f5d74 imageUrl + / 2021-04-23 16:36:41 +08:00
caishi 63da7adcf9 个人中心关注-关注或者取消关注未更新状态 2021-04-23 16:36:31 +08:00
caishi 3243aeebc6 贡献者-悬浮卡片-测试版1 2021-04-23 16:36:22 +08:00
caishi 1a86a75345 发布评论者头像路径错误 2021-04-23 16:36:11 +08:00
caishi 3b6cc99d49 merge 2021-04-23 16:35:49 +08:00
caishi d872ffc606 merge 2021-04-23 16:31:15 +08:00
caishi 3b69c01ead merge 2021-04-23 16:30:45 +08:00
caishi 1e0608aa14 合并请求-提出申请者头像显示问题 2021-04-23 16:30:07 +08:00
caishi 9b6816e346 团队项目-团队项目管理-显示的name和跳转的login 2021-04-23 16:29:57 +08:00
caishi 6ee257231d 切换左侧目录,选择不同的文件时,文件详情没有更新 2021-04-23 16:29:46 +08:00
caishi 70edb73f6c all-默认头像(首字母加背景颜色) 2021-04-23 16:29:35 +08:00
caishi 5c7553d4aa merge 2021-04-23 16:29:16 +08:00
caishi 278701f24b 上线后的getImageURL也不用在前面加/ + 一些小样式修改 2021-04-23 16:27:56 +08:00
caishi 97ab819bf9 merge 2021-04-23 16:27:37 +08:00
caishi d870f17b85 readme-文件增加一个目录下拉icon 2021-04-23 16:26:02 +08:00
caishi 91ac6c2357 组织团队-新增一个团队标识 2021-04-23 16:25:47 +08:00
caishi 3702d1c1a5 merge 2021-04-23 16:25:35 +08:00
caishi 93d48c359e merge 2021-04-23 16:25:03 +08:00
caishi 80dace18e9 资源库不需要按引用次数排序 2021-04-23 16:24:23 +08:00
caishi 375cbb37df merge 2021-04-23 16:24:02 +08:00
caishi 10d933e037 merge develop 2021-04-23 16:23:29 +08:00
caishi 4fdd3f6f80 组织-团队列表的头像login为undefined 2021-04-23 16:22:36 +08:00
caishi 458b56e33b 去掉悬浮手册按钮 2021-04-23 16:22:22 +08:00
caishi c256887132 注册成功后跳转到首页 2021-03-31 15:13:32 +08:00
caishi 6a588db7f6 清理代码 2021-03-31 15:03:16 +08:00
caishi 6c4e1c6665 Merge branch 'standalone' into dev_local 2021-03-31 14:42:24 +08:00
caishi c554d2c00d 重置settings为undefined 2021-03-31 14:35:23 +08:00
caishi b69bf5974a remove 2021-03-31 14:28:22 +08:00
caishi ecb1691b4d Trustie 2021-03-31 14:17:48 +08:00
caishi 6a9f2b31a6 注册页面logo和底部信息 2021-03-31 14:04:09 +08:00
caishi 4947cd8456 浏览器ico要用trustie的logo 2021-03-31 12:07:11 +08:00
caishi 8429effe16 没logo时会将setting重置为空 2021-03-31 12:02:38 +08:00
caishi 49ebe450be 合并测试版分支 2021-03-31 11:21:07 +08:00
caishi e3c926da77 注册 2021-03-29 17:37:16 +08:00
caishi af48da2eb3 href 2021-03-29 17:14:56 +08:00
caishi 6630309466 Merge branch 'develop' into dev_local 2021-03-29 16:58:48 +08:00
caishi a7c3dee7e3 2020-11-26 10:55:03 +08:00
49 changed files with 603 additions and 1493 deletions

View File

@ -499,7 +499,6 @@
<option value="$PROJECT_DIR$/src/forge/Main/Detail.js" /> <option value="$PROJECT_DIR$/src/forge/Main/Detail.js" />
<option value="$PROJECT_DIR$/src/forge/Main/CoderRootCommit.js" /> <option value="$PROJECT_DIR$/src/forge/Main/CoderRootCommit.js" />
<option value="$PROJECT_DIR$/src/forge/Activity/ActivityItem.js" /> <option value="$PROJECT_DIR$/src/forge/Activity/ActivityItem.js" />
<option value="$PROJECT_DIR$/src/forge/Main/CoderRootDirectory.js" />
<option value="$PROJECT_DIR$/src/forge/Branch/CloneAddress.js" /> <option value="$PROJECT_DIR$/src/forge/Branch/CloneAddress.js" />
<option value="$PROJECT_DIR$/src/forge/Version/version.js" /> <option value="$PROJECT_DIR$/src/forge/Version/version.js" />
<option value="$PROJECT_DIR$/public/css/css_min_all.css" /> <option value="$PROJECT_DIR$/public/css/css_min_all.css" />
@ -1020,16 +1019,6 @@
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/src/forge/Main/CoderRootDirectory.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="153">
<caret line="9" column="50" lean-forward="true" selection-start-line="9" selection-start-column="50" selection-end-line="9" selection-end-column="50" />
<folding>
<element signature="n#CoderRootDirectory#0" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/src/modules/user/usersInfo/InfosBanner.js"> <entry file="file://$PROJECT_DIR$/src/modules/user/usersInfo/InfosBanner.js">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="192"> <state relative-caret-position="192">

17
package-lock.json generated
View File

@ -1,5 +1,5 @@
{ {
"name": "forge", "name": "educoder",
"version": "0.1.0", "version": "0.1.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
@ -3888,6 +3888,11 @@
"randomfill": "^1.0.3" "randomfill": "^1.0.3"
} }
}, },
"crypto-js": {
"version": "4.0.0",
"resolved": "https://registry.npm.taobao.org/crypto-js/download/crypto-js-4.0.0.tgz",
"integrity": "sha1-KQSrJnep0EKFai6i74DekuSjbcw="
},
"crypto-random-string": { "crypto-random-string": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz",
@ -20475,16 +20480,6 @@
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"dev": true "dev": true
}, },
"xterm": {
"version": "4.8.1",
"resolved": "https://registry.npm.taobao.org/xterm/download/xterm-4.8.1.tgz",
"integrity": "sha1-FVoXKaQ+Gom0BlJOIsVjQznjnKE="
},
"xterm-addon-fit": {
"version": "0.4.0",
"resolved": "https://registry.npm.taobao.org/xterm-addon-fit/download/xterm-addon-fit-0.4.0.tgz",
"integrity": "sha1-BuDF0KaqrPsAnvVl76HIHpPZAZM="
},
"y18n": { "y18n": {
"version": "3.2.1", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",

View File

@ -111,9 +111,7 @@
"webpack-dev-server": "^3.10.3", "webpack-dev-server": "^3.10.3",
"webpack-manifest-plugin": "^2.2.0", "webpack-manifest-plugin": "^2.2.0",
"whatwg-fetch": "2.0.3", "whatwg-fetch": "2.0.3",
"wrap-md-editor": "^0.2.20", "wrap-md-editor": "^0.2.20"
"xterm": "4.8.1",
"xterm-addon-fit": "0.4.0"
}, },
"scripts": { "scripts": {
"start": "node --max_old_space_size=15360 scripts/start.js", "start": "node --max_old_space_size=15360 scripts/start.js",

BIN
public/favicon-.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
public/favicon.ico Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -10,7 +10,7 @@ import {
import axios from 'axios'; import axios from 'axios';
import LoginDialog from './modules/login/LoginDialog'; import LoginDialog from './modules/login/LoginDialog';
import 'babel-polyfill'; import 'babel-polyfill';
import Loading from './Loading' import Loading from './Loading';
import Loadable from 'react-loadable'; import Loadable from 'react-loadable';
import marked from './common/marked'; import marked from './common/marked';

View File

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

View File

@ -162,28 +162,28 @@ export function getmyUrl(geturl) {
} }
export function getUploadActionUrl(path, goTest) { export function getUploadActionUrl(path, goTest) {
return `${getUrl()}/api/attachments.json${isDev ?`${isDev ?`?debug=${window._debugType || 'admin'}` : ""}` : ""}`; return `${getUrl()}/api/attachments.json?debug=${window._debugType || 'admin'}`;
} }
export function getUploadLogoActionUrl() { export function getUploadLogoActionUrl() {
return `${getUrl()}/api/resumes/logo.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`; return `${getUrl()}/api/resumes/logo.json?debug=${window._debugType || 'admin'}`;
} }
export function getUploadActionUrltwo(id) { export function getUploadActionUrltwo(id) {
return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}` return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json?debug=${window._debugType || 'admin'}`
} }
export function getUploadActionUrlthree() { export function getUploadActionUrlthree() {
return `${getUrlmys()}/api/jupyters/import_with_tpm.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}` return `${getUrlmys()}/api/jupyters/import_with_tpm.json?debug=${window._debugType || 'admin'}`
} }
export function getupload_git_file(id) { export function getupload_git_file(id) {
return `${getUrlmys()}/api/shixuns/${id}/upload_git_file.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}` return `${getUrlmys()}/api/shixuns/${id}/upload_git_file.json?debug=${window._debugType || 'admin'}`
} }
export function getUploadActionUrlOfAuth(id) { export function getUploadActionUrlOfAuth(id) {
return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}` return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json?debug=${window._debugType || 'admin'}`
} }
export function getRandomNumber(type) { export function getRandomNumber(type) {

View File

@ -102,7 +102,7 @@ export default (({ projectsId , branch , owner , changeBranch , branchList , tag
</div> </div>
); );
return( return(
<Popover placement='bottomLeft' visible={flag} content={menu} onClick={()=>setFlag(!flag)} overlayClassName="branch-tagBox-list"> <Popover placement="bottom" visible={flag} content={menu} onClick={()=>setFlag(!flag)} overlayClassName="branch-tagBox-list">
<div className="branch-tagBox"> <div className="branch-tagBox">
{/* {nav === 0 ?"分支":"标签"} */} {/* {nav === 0 ?"分支":"标签"} */}
<span className="color-grey-9 mr3 ml8"><i className="iconfont icon-fenzhi2 font-18"></i></span> <span className="color-grey-9 mr3 ml8"><i className="iconfont icon-fenzhi2 font-18"></i></span>

View File

@ -112,9 +112,6 @@ li.ant-menu-item{
right:240px; right:240px;
z-index: 10000; z-index: 10000;
} }
.laterest{
color: #05690d;
}
@media screen and (max-width: 1800px){ @media screen and (max-width: 1800px){
.handleBox{ .handleBox{

View File

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

View File

@ -1,60 +0,0 @@
import React , {forwardRef, useEffect} from 'react';
import { Modal , Form , Input , Button } from 'antd';
import './EAccount.scss';
function EducoderAccount({form , visible , onOk , email}){
const { getFieldDecorator, validateFields , setFieldsValue } = form;
useEffect(()=>{
if(email){
setFieldsValue({email})
}
},[email])
function onSure(){
validateFields((error,values)=>{
if(!error){
onOk(values);
}
})
}
const layout = {
labelCol: { span: 5 },
wrapperCol: { span: 18 },
};
return(
<Modal
visible={visible}
title="提示"
width="500px"
closable={false}
footer={
<Button type="primary" onClick={onSure}>确定</Button>
}
centered
>
<div>
<p className="mb15 edu-txt-center" style={{maxWidth:"350px",margin:"0px auto"}}>
为确保您能正常使用平台功能请确认以下信息:
</p>
<Form {...layout}>
<Form.Item label="邮箱">
{getFieldDecorator("email",{
rules:[{required:true,message:"请输入邮箱账号"}]
})(
<Input placeholder="请输入您的邮箱账号" width="220px"/>
)}
</Form.Item>
<Form.Item label="密码">
{getFieldDecorator("password",{
rules:[{required:true,message:"请输入邮箱密码"}]
})(
<Input.Password placeholder="请输入您的邮箱密码" width="220px"/>
)}
</Form.Item>
</Form>
</div>
</Modal>
)
}
export default Form.create()(forwardRef(EducoderAccount));

View File

@ -20,13 +20,10 @@ function Releases({owner,projectsId,releaseVersions}){
releaseVersions && releaseVersions.total_count>0 ? releaseVersions && releaseVersions.total_count>0 ?
releaseVersions.list.map((item,key)=>{ releaseVersions.list.map((item,key)=>{
return( return(
key === 0 &&<AlignTop className="mt10"> <AlignTop className="mt10">
<i className="iconfont icon-biaoqian3 color-grey-6 font-18 mr10"></i> <i className="iconfont icon-biaoqian3 color-grey-6 font-18 mr10"></i>
<div> <div>
<p className="font-16 color-grey-6"> <p className="font-16 color-grey-6"><Link to={`/projects/${owner}/${projectsId}/releases/8/update`}>{item.name}</Link></p>
<Link to={`/projects/${owner}/${projectsId}/releases/8/update`}>{item.name}</Link>
<span className="font-12 laterest ml5">最新</span>
</p>
<p className="color-grey-9 font-13">{item.created_at}</p> <p className="color-grey-9 font-13">{item.created_at}</p>
</div> </div>
</AlignTop> </AlignTop>

View File

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

View File

@ -36,7 +36,8 @@ function About(props, ref) {
const [ disabled, setDisabled ] = useState(false); const [ disabled, setDisabled ] = useState(false);
const [ typeFlag, setTypeFlag] = useState(false); const [ typeFlag, setTypeFlag] = useState(false);
const AuthorLogin = props.projectDetail && props.projectDetail.author && props.projectDetail.author.login;
const AuthorLogin = props.author && props.author.login;
const CurrentLogin = props.current_user && props.current_user.login; const CurrentLogin = props.current_user && props.current_user.login;
useEffect(()=>{ useEffect(()=>{
if(CurrentLogin === AuthorLogin){ if(CurrentLogin === AuthorLogin){
@ -55,6 +56,11 @@ function About(props, ref) {
setIsSpining(false); setIsSpining(false);
if(result && result.data ){ if(result && result.data ){
setStep(result.data.step); setStep(result.data.step);
// setStep(0);
// setFieldsValue({...result.data.cloud_account});
// if(result.data.cloud_account){
// setDisabled(true);
// }
} }
}).catch(error=>{ }).catch(error=>{
setIsSpining(false); setIsSpining(false);

View File

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

View File

@ -58,7 +58,6 @@ function Structure(props,ref){
return { return {
...item, ...item,
author:item.author && item.author.name, author:item.author && item.author.name,
image_url:item.author && item.author.image_url,
message: { message: {
branch: item.branch_target, branch: item.branch_target,
message: item.message, message: item.message,
@ -245,7 +244,7 @@ function Structure(props,ref){
{meg.sha && <span className="color-orange">{meg.sha}</span>} {meg.sha && <span className="color-orange">{meg.sha}</span>}
</div> </div>
<AlignCenter> <AlignCenter>
<img style={{borderRadius:"50%",marginRight:"10px",width:"25px",height:"25px"}} alt="" src={`${item.image_url && getUrl(`/images/${item.image_url}`)}`} /> <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" }}> <div className="task-hide ml5" style={{ maxWidth: "300px" }}>
{meg.message} {meg.message}
</div> </div>

View File

@ -194,18 +194,6 @@
&.rightSection{ &.rightSection{
width:100%; width:100%;
background-color: #081930; background-color: #081930;
.devopsNav{
background-color: #111c24;
border-bottom: none;
.ant-menu-item{
color: #ccc;
padding:0px;
margin:0px 20px!important;
}
.ant-menu-item.ant-menu-item-selected{
color: #1890ff;
}
}
.rightMainContent{ .rightMainContent{
padding:24px 30px; padding:24px 30px;
height:100vh; height:100vh;

View File

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

View File

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

View File

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

View File

@ -111,7 +111,7 @@ class NewHeader extends Component {
} }
onGlobalSearch=(value,item)=>{ onGlobalSearch=(value,item)=>{
window.location.href=`${item}?value=` + value; window.location.href=`${item && item.url}?value=` + value;
} }
openNotification = (messge) => { openNotification = (messge) => {
@ -403,39 +403,13 @@ class NewHeader extends Component {
visiblemyss: boll, visiblemyss: boll,
}) })
} }
getAppdata = () => {
try {
var chromesettingArray = JSON.parse(localStorage.getItem('chromesetting'));
var chromesettingresponseArray = JSON.parse(localStorage.getItem('chromesettingresponse'));
this.setState({
settings: chromesettingArray
});
if (chromesettingArray.tab_logo_url) {
this.gettablogourldata(chromesettingresponseArray);
} else {
this.gettablogourlnull();
}
} catch (e) {
this.geturlsdata();
}
};
geturlsdata = () => { geturlsdata = () => {
let url = "/setting.json"; let url = "/setting.json";
axios.get(url).then((response) => { axios.get(url).then((response) => {
if (response && response.data) { if (response && response.data) {
this.setState({ settings: response.data.setting }); this.setState({ settings: response.data.setting });
// localStorage.setItem('chromesetting', JSON.stringify(response.data.setting)); if (response.data.setting.tab_logo_url) {
// localStorage.setItem('chromesettingresponse', JSON.stringify(response)); this.gettablogourldata(response);
try {
if (response.data.setting.tab_logo_url) {
this.gettablogourldata(response);
} else {
this.gettablogourlnull();
}
} catch (e) {
this.gettablogourlnull();
} }
} else { } else {
this.gettablogourlnull(); this.gettablogourlnull();
@ -482,19 +456,14 @@ class NewHeader extends Component {
} }
render() { render() {
const { match} = this.props; const { match } = this.props;
let current_user = this.props.user; let current_user = this.props.user;
let { Addcoursestypes, let {
tojoinitemtype,
tojoinclasstitle,
code_notice,
checked_notice,
AccountProfiletype, AccountProfiletype,
submitapplications, submitapplications,
submitapplicationsvalue, submitapplicationsvalue,
user, user,
isRender, isRender,
showSearchOpentype,
headtypesonClickbool, headtypesonClickbool,
headtypess, headtypess,
settings, settings,
@ -577,8 +546,8 @@ class NewHeader extends Component {
}) })
} }
let search_url = settings && settings.common && settings.common.search; let search_url = settings && settings.common && settings.common.length> 0 && settings.common.filter(item=>item.name==="搜索");
let notice_url = settings && settings.common && settings.common.notice; let notice_url = settings && settings.common && settings.common.length> 0 && settings.common.filter(item=>item.name==="通知");
return ( return (
<div className="newHeaders" id="nHeader"> <div className="newHeaders" id="nHeader">
<div className="headerContent"> <div className="headerContent">
@ -646,7 +615,7 @@ class NewHeader extends Component {
} }
</div> </div>
<div className="head-right"> <div className="head-right">
{search_url ? this.SearchInput(openSearch,search_url):""} {search_url && search_url.length>0 ? this.SearchInput(openSearch,search_url[0]):""}
{ {
current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)? current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)?
<Dropdown overlay={this.addMenu(settings && settings.add)} placement="bottomRight"> <Dropdown overlay={this.addMenu(settings && settings.add)} placement="bottomRight">
@ -654,10 +623,10 @@ class NewHeader extends Component {
</Dropdown>:"" </Dropdown>:""
} }
{this.props.user && this.props.user.login && notice_url ? {this.props.user && this.props.user.login && (notice_url && notice_url.length>0) ?
<div className="ml30 edu-menu-panel"> <div className="ml30 edu-menu-panel">
{user && user.login && {user && user.login &&
<a href={`${notice_url}`} style={{ position: 'relative' }}> <a href={`${notice_url[0].url}`} style={{ position: 'relative' }}>
<i className="iconfont icon-xiaoxilingdang color-grey-6"></i> <i className="iconfont icon-xiaoxilingdang color-grey-6"></i>
<span className="newslight" style={{ display: this.props.Headertop === undefined ? "none" : this.props.Headertop.new_message === true ? "block" : "none" }}> <span className="newslight" style={{ display: this.props.Headertop === undefined ? "none" : this.props.Headertop.new_message === true ? "block" : "none" }}>
</span> </span>

View File

@ -1,6 +1,6 @@
import React , { useEffect , useState } from 'react'; import React , { useEffect , useState } from 'react';
import { WhiteBack , Box , LongWidth , ShortWidth , Gap , AlignCenter , FlexAJ } from '../Component/layout'; import { WhiteBack , Box , LongWidth , ShortWidth , Gap , AlignCenter , FlexAJ } from '../Component/layout';
import { Dropdown , Menu , Divider , Spin, Button } from 'antd'; import { Dropdown , Menu , Divider , Spin } from 'antd';
import { getImageUrl } from "educoder"; import { getImageUrl } from "educoder";
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import CloneAddress from '../Branch/CloneAddress'; import CloneAddress from '../Branch/CloneAddress';
@ -20,9 +20,7 @@ import DrawerPanel from '../Component/DrawerPanel';
import UpdateDescModal from './sub/UpdateDescModal'; import UpdateDescModal from './sub/UpdateDescModal';
import Nodata from '../Nodata'; import Nodata from '../Nodata';
/**
* projectDetail.type:0是托管项目1是镜像项目2是同步镜像项目(为2时不支持在线创建在线上传在线修改在线删除创建合并请求等功能)
*/
function CoderDepot(props){ function CoderDepot(props){
const [ projectDetail , setProjectDetail ]= useState(undefined); const [ projectDetail , setProjectDetail ]= useState(undefined);
const [ treeValue , setTreeValue ] = useState(undefined); const [ treeValue , setTreeValue ] = useState(undefined);
@ -44,18 +42,17 @@ function CoderDepot(props){
const [ openModal , setOpenModal ] = useState(false); const [ openModal , setOpenModal ] = useState(false);
const [ desc , setDesc ] = useState(undefined); const [ desc , setDesc ] = useState(undefined);
const [ website , setWebsite ] = useState(undefined); const [ website , setWebsite ] = useState(undefined);
const [ lesson_url , setLessonUrl ] = useState(undefined);
const owner = props.match.params.owner; const owner = props.match.params.owner;
const projectsId = props.match.params.projectsId; const projectsId = props.match.params.projectsId;
const branchName = props.match.params.branchName; const branchName = props.match.params.branchName;
let pathname = props.history.location.pathname; let pathname = props.history.location.pathname;
useEffect(()=>{ useEffect(()=>{
if(props.projectDetail){ if(props.projectDetail){
setProjectDetail(props.projectDetail); setProjectDetail(props.projectDetail);
setDesc(props.projectDetail.description); setDesc(props.projectDetail.description);
setWebsite(props.projectDetail.website); setWebsite(props.projectDetail.website);
setLessonUrl(props.projectDetail.lesson_url);
} }
},[props]) },[props])
@ -68,17 +65,17 @@ function CoderDepot(props){
},[treeValue]) },[treeValue])
useEffect(()=>{ useEffect(()=>{
if (pathname && projectDetail){ if (pathname){
if(pathname.indexOf(`/projects/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${branchName}/`) > -1) { if(pathname.indexOf(`/projects/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${branchName}/`) > -1) {
let url = pathname.split(`/tree/${branchName}/`)[1]; let url = pathname.split(`/tree/${branchName}/`)[1];
setTreeValue(url); setTreeValue(url);
getFileInfo(url,branchName); getFileInfo(url,branchName);
}else{ }else{
setTreeValue(undefined); setTreeValue(undefined);
getDirInfo(branchName ||projectDetail.default_branch); getDirInfo(branchName ||(projectDetail && projectDetail.default_branch));
} }
} }
},[pathname,projectDetail]) },[pathname])
// //
function getDirInfo(branch){ function getDirInfo(branch){
@ -95,7 +92,7 @@ function CoderDepot(props){
setZip_url(result.data.zip_url); setZip_url(result.data.zip_url);
let c = result.data.last_commit let c = result.data.last_commit
setLastCommit(c && c.commit); setLastCommit(c && c.commit);
setLastCommitAuthor(c && c.committer); setLastCommitAuthor(c && (c.author || (c.commit && c.commit.author)));
setMainFlag(true); setMainFlag(true);
setReadOnly(true); setReadOnly(true);
} }
@ -137,7 +134,7 @@ function CoderDepot(props){
} }
let c = result.data.last_commit let c = result.data.last_commit
setLastCommit(c && c.commit); setLastCommit(c && c.commit);
setLastCommitAuthor(c && c.committer); setLastCommitAuthor(c && (c.author || (c.commit && c.commit.author)));
setMainFlag(false); setMainFlag(false);
setReadOnly(true); setReadOnly(true);
} }
@ -219,16 +216,14 @@ function CoderDepot(props){
</Menu> </Menu>
</div> </div>
) )
// website function okUpdate(d,w){
function okUpdate(d,w,l){
const url = `/${owner}/${projectsId}.json`; const url = `/${owner}/${projectsId}.json`;
axios.put(url,{ axios.put(url,{
description:d,website:w,lesson_url:l description:d,website:w
}).then(result=>{ }).then(result=>{
if(result && result.data && result.data.id){ if(result && result.data && result.data.id){
setDesc(result.data.description); setDesc(result.data.description);
setWebsite(result.data.website); setWebsite(result.data.website);
setLessonUrl(result.data.lesson_url);
} }
}) })
} }
@ -238,7 +233,7 @@ function CoderDepot(props){
return( return(
<WhiteBack> <WhiteBack>
<UpdateDescModal desc={desc} website={website} lesson_url={lesson_url} visible={openModal} onCancel={()=>setOpenModal(false)} onOk={okUpdate}/> <UpdateDescModal desc={desc} website={website} visible={openModal} onCancel={()=>setOpenModal(false)} onOk={okUpdate}/>
<Spin spinning={isSpin}> <Spin spinning={isSpin}>
{ {
(dirInfo || fileInfo) && (dirInfo || fileInfo) &&
@ -253,10 +248,7 @@ function CoderDepot(props){
onClose={()=>setVisible(false)} onClose={()=>setVisible(false)}
list = {mainFlag ? dirInfo : undefined} list = {mainFlag ? dirInfo : undefined}
/> />
<div className="drawerBtn" onClick={()=>setVisible(true)}> <div className="drawerBtn" onClick={()=>setVisible(true)}><i className="iconfont icon-youjiantou"></i></div>
<i className="iconfont icon-youjiantou font-16"></i>
<span>目录</span>
</div>
</React.Fragment> </React.Fragment>
} }
<div style={{minHeight:"500px"}}> <div style={{minHeight:"500px"}}>
@ -298,21 +290,11 @@ function CoderDepot(props){
</AlignCenter> </AlignCenter>
<AlignCenter> <AlignCenter>
<div className="mr20 addOptionBtn"> <div className="mr20 addOptionBtn">
{ <a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/pulls/new`)} >+ 合并请求</a>
projectDetail.type !== 2 &&
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/pulls/new`)} >+ 合并请求</a>
}
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/issues/new`)} >+ 任务</a> <a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/issues/new`)} >+ 任务</a>
</div> </div>
{ type === "dir" && projectDetail.type !== 2 && { type === "dir" && <Dropdown.Button overlay={fileMenu} className="mr20">文件</Dropdown.Button>}
<Dropdown overlay={fileMenu} className="mr20"> <Dropdown.Button overlay={downloadMenu} type={'primary'}>下载</Dropdown.Button>
<Button type="default">文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-9"></i></Button>
</Dropdown>
}
<Dropdown overlay={downloadMenu} placement="bottomRight">
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white"></i></Button>
</Dropdown>
</AlignCenter> </AlignCenter>
</FlexAJ> </FlexAJ>
{ {
@ -321,7 +303,7 @@ function CoderDepot(props){
{ {
lastCommit && lastCommit &&
<div className="listtablehead"> <div className="listtablehead">
<User url={getImageUrl(`/${lastCommitAuthor && lastCommitAuthor.image_url}`)} name={lastCommitAuthor && lastCommitAuthor.name} id={lastCommitAuthor && lastCommitAuthor.id} login={lastCommitAuthor && lastCommitAuthor.login}/> <User url={getImageUrl(`/${lastCommitAuthor && lastCommitAuthor.image_url}`)} name={lastCommitAuthor && lastCommitAuthor.name} />
<div className={hideBtn && hide ? "ellipsistxt hide" :"ellipsistxt"}><p id="ptxt">{lastCommit && lastCommit.message}</p></div> <div className={hideBtn && hide ? "ellipsistxt hide" :"ellipsistxt"}><p id="ptxt">{lastCommit && lastCommit.message}</p></div>
{ hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> } { hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> }
@ -362,7 +344,6 @@ function CoderDepot(props){
md={mdFlag} md={mdFlag}
onEdit={onEdit} onEdit={onEdit}
currentBranch={branchName || (projectDetail && projectDetail.default_branch)} currentBranch={branchName || (projectDetail && projectDetail.default_branch)}
type={projectDetail.type}
></CoderRootFileDetail> ></CoderRootFileDetail>
} }
</ul> </ul>
@ -373,7 +354,7 @@ function CoderDepot(props){
(dirInfo && dirInfo.length === 0) && (fileInfo && fileInfo.length === 0) ? <Nodata _html="暂未发现文件"/> :"" (dirInfo && dirInfo.length === 0) && (fileInfo && fileInfo.length === 0) ? <Nodata _html="暂未发现文件"/> :""
} }
{/* readme文件显示(显示文件详情时不显示readme文件) */} {/* readme文件显示(显示文件详情时不显示readme文件) */}
{ dirInfo && (projectDetail && projectDetail.readme) ? <ReadMe ChangeFile={ChangeFile} readme={projectDetail && projectDetail.readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" } { dirInfo && (projectDetail && projectDetail.readme) ? <ReadMe ChangeFile={ChangeFile} readme={projectDetail && projectDetail.readme} operate={props && (props.isManager || props.isDeveloper)} history={props.history} /> :"" }
</div> </div>
</LongWidth> </LongWidth>
{ {
@ -384,12 +365,12 @@ function CoderDepot(props){
<FlexAJ className="font-18 color-grey-6 mb20" style={{lineHeight:"28px"}}>简介 <FlexAJ className="font-18 color-grey-6 mb20" style={{lineHeight:"28px"}}>简介
{projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner") && <i onClick={()=>setOpenModal(true)} className="iconfont icon-anquanshezhi color-grey-9 font-15"></i>} {projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner") && <i onClick={()=>setOpenModal(true)} className="iconfont icon-anquanshezhi color-grey-9 font-15"></i>}
</FlexAJ> </FlexAJ>
{desc && <p className="font-14 color-grey-9 mb15 task-hide-2" style={{lineHeight:"22px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}}>{desc}</p>} {desc && <p className="font-14 color-grey-9 mb15 task-hide-2" style={{lineHeight:"22px",WebkitLineClamp:"4",textAlign:"justify"}}>{desc}</p>}
{ {
website && website &&
<p className="color-grey-6 df"> <p className="color-grey-6 df">
<i className="iconfont icon-lianjie2 font-15 mr10 color-grey-9"></i> <i className="iconfont icon-lianjie2 font-15 mr10 color-grey-9"></i>
<a href={website} target="_blank" style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px",textDecoration:"underline"}}>{website}</a> <span style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px"}}>{website}</span>
</p> </p>
} }
<p> <p>
@ -408,14 +389,6 @@ function CoderDepot(props){
</p> </p>
} }
</div> </div>
{
lesson_url &&
<div>
<Divider />
<p className="font-16 color-grey-6">实践课程</p>
<a href={lesson_url} target="_blank" className="color-grey-6" style={{textDecoration:"underline"}}>{lesson_url}</a>
</div>
}
{/* 发布 */} {/* 发布 */}
{ {
projectDetail && projectDetail.release_versions && projectDetail && projectDetail.release_versions &&

View File

@ -496,11 +496,9 @@ class Detail extends Component {
} }
</span> </span>
<span className="detail_tag_btn"> <span className="detail_tag_btn">
<Tooltip title="复刻是fork的中文名即复制代码仓库" placement="bottom"> <a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={this.forkFunc}>
<a className="detail_tag_btn_name" style={{cursor:platform?"pointer":"default"}} onClick={this.forkFunc}> <i className="iconfont icon-fork color-grey-9 mr3"></i> (Fork)
<i className="iconfont icon-fork color-grey-9 mr3"></i> </a>
</a>
</Tooltip>
{ {
forked_count > 0 ? forked_count > 0 ?
platform ? platform ?
@ -518,7 +516,6 @@ class Detail extends Component {
{ {
firstSync ? "" : firstSync ? "" :
<DetailBanner <DetailBanner
history={this.props.history}
list={bannerList} list={bannerList}
owner={owner} owner={owner}
projectsId={projectsId} projectsId={projectsId}

View File

@ -83,10 +83,10 @@
} }
.addOptionBtn{ .addOptionBtn{
height: 32px; height: 32px;
line-height: 30px; line-height: 32px;
display: flex; display: flex;
border:1px solid #d9d9d9; border:1px solid #d9d9d9;
border-radius: 2px; border-radius: 4px;
a{ a{
padding:0px 13px; padding:0px 13px;
color: rgba(0, 0, 0, 0.65); color: rgba(0, 0, 0, 0.65);
@ -95,9 +95,6 @@
& > a:first-child{ & > a:first-child{
border-right: 1px solid #d9d9d9; border-right: 1px solid #d9d9d9;
} }
& > a:last-child{
border-right: none;
}
} }
.infoCount{ .infoCount{
display: inline-block; display: inline-block;
@ -260,30 +257,20 @@
.drawerBtn{ .drawerBtn{
position: fixed; position: fixed;
left: -13px; left: -13px;
border:1px solid rgb(207,205,223); border:1px solid #d9d9d9;
width: 34px; width: 34px;
border-radius: 0px 12px 12px 0px; border-radius: 0px 12px 12px 0px;
text-align: right;
height: 70px; height: 70px;
line-height: 70px;
top:50%; top:50%;
margin-top: -35px; margin-top: -35px;
cursor: pointer; cursor: pointer;
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: center;
&:hover{ &:hover{
box-shadow: 1px 0px 7px rgba(0,0,0,0.1); box-shadow: 1px 0px 7px rgba(0,0,0,0.1);
} }
span{
writing-mode: vertical-lr;
color: #202429;
width: 25px;
}
i{ i{
color: #24292e; color: #d9d9d9;
height: 18px;
line-height: 18px;
width: 18px;
} }
} }
.downMenu{ .downMenu{

View File

@ -1,18 +1,11 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Skeleton , Tooltip} from 'antd'; import { Skeleton } from 'antd';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
function DetailBanner({ history,list , owner , projectsId , isManager , url , pathname , state , urlFlag , projectDetail , platform ,open_devops }){ function DetailBanner({ list , owner , projectsId , isManager , url , pathname , state , urlFlag , projectDetail , platform ,open_devops }){
const [ menuName , setMenuName ] = useState(undefined); const [ menuName , setMenuName ] = useState(undefined);
useEffect(()=>{ useEffect(()=>{
if(list){ if(list){
// banner
if(pathname && pathname==="source"){
let a = list.filter(item=>item.menu_name === "resources");
if(a && a.length === 0){
history.push(`/projects/${owner}/${projectsId}`);
}
}
setMenuName(list); setMenuName(list);
} }
},[list]); },[list]);
@ -46,13 +39,11 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
{ {
item.menu_name === "issues" && item.menu_name === "issues" &&
<li className={pathname==="issues" ? "active" : ""}> <li className={pathname==="issues" ? "active" : ""}>
<Tooltip title="易修是Issue的中文名即问题列表" placement="bottom"> <Link to={{ pathname: `/projects/${owner}/${projectsId}/issues`, state }}>
<Link to={{ pathname: `/projects/${owner}/${projectsId}/issues`, state }}> <i className={pathname==="issues" ? "iconfont icon-renwu color-grey-3 mr5 font-14":"iconfont icon-renwu color-grey-6 font-14 mr5"}></i>
<i className={pathname==="issues" ? "iconfont icon-renwu color-grey-3 mr5 font-14":"iconfont icon-renwu color-grey-6 font-14 mr5"}></i> <span>易修 (Issue)</span>
<span>易修</span> {projectDetail && projectDetail.issues_count ? <span className="num">{projectDetail.issues_count}</span> : ""}
{projectDetail && projectDetail.issues_count ? <span className="num">{projectDetail.issues_count}</span> : ""} </Link>
</Link>
</Tooltip>
</li> </li>
} }
{ {
@ -75,8 +66,8 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
</li> </li>
:"" :""
} }
{/* { {
item.menu_name === "resources" && item.menu_name === "source" &&
<li className={pathname==="source" ? "active" : ""}> <li className={pathname==="source" ? "active" : ""}>
<Link to={{ pathname: `/projects/${owner}/${projectsId}/source`, state }}> <Link to={{ pathname: `/projects/${owner}/${projectsId}/source`, state }}>
<i className={pathname==="source" ? "iconfont icon-ziyuanpaihanghetuijian color-grey-3 mr5 font-14":"iconfont icon-ziyuanpaihanghetuijian color-grey-6 font-14 mr5"}></i> <i className={pathname==="source" ? "iconfont icon-ziyuanpaihanghetuijian color-grey-3 mr5 font-14":"iconfont icon-ziyuanpaihanghetuijian color-grey-6 font-14 mr5"}></i>
@ -84,7 +75,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
{projectDetail && projectDetail.source_count ? <span className="num">{projectDetail.source_count}</span> :""} {projectDetail && projectDetail.source_count ? <span className="num">{projectDetail.source_count}</span> :""}
</Link> </Link>
</li> </li>
} */} }
{ {
item.menu_name === "versions" && item.menu_name === "versions" &&
<li className={pathname==="milestones" ? "active" : ""}> <li className={pathname==="milestones" ? "active" : ""}>
@ -104,19 +95,19 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
</Link> </Link>
</li> </li>
} }
{
item.menu_name === "setting" &&
<li className={pathname === "setting" ? "active" : ""}>
<Link to={`/projects/${owner}/${projectsId}/setting`}>
<i className={url && url.indexOf("/setting") > 0 ? "iconfont icon-cangku color-grey-3 mr5 font-14":"iconfont icon-cangku color-grey-6 font-14 mr5"}></i>
<span>仓库设置</span>
</Link>
</li>
}
</React.Fragment> </React.Fragment>
) )
}) })
} }
{
isManager && platform ?
<li className={pathname === "setting" ? "active" : ""}>
<Link to={`/projects/${owner}/${projectsId}/setting`}>
<i className={url && url.indexOf("/setting") > 0 ? "iconfont icon-cangku color-grey-3 mr5 font-14":"iconfont icon-cangku color-grey-6 font-14 mr5"}></i>
<span>仓库设置</span>
</Link>
</li>:""
}
</ul> </ul>
: :
<Skeleton paragraph={false} active={true}/> <Skeleton paragraph={false} active={true}/>

View File

@ -2,13 +2,13 @@ import React , { forwardRef, useEffect } from 'react';
import {Form , Modal , Input } from 'antd'; import {Form , Modal , Input } from 'antd';
import "./sub.scss"; import "./sub.scss";
const { TextArea } = Input; const { TextArea } = Input;
function UpdateDescModal({form , visible , onCancel , onOk,desc,website,lesson_url}){ function UpdateDescModal({form , visible , onCancel , onOk,desc,website}){
const { getFieldDecorator, validateFields , setFieldsValue } = form; const { getFieldDecorator, validateFields , setFieldsValue } = form;
useEffect(()=>{ useEffect(()=>{
if(desc || website){ if(desc || website){
setFieldsValue({ setFieldsValue({
website,desc,lesson_url website,desc
}) })
} }
},[desc,website]) },[desc,website])
@ -17,7 +17,7 @@ function UpdateDescModal({form , visible , onCancel , onOk,desc,website,lesson_u
validateFields((err,values)=>{ validateFields((err,values)=>{
if(!err){ if(!err){
onCancel(); onCancel();
onOk(values.desc,values.website,values.lesson_url) onOk(values.desc,values.website)
} }
}) })
} }
@ -49,13 +49,6 @@ function UpdateDescModal({form , visible , onCancel , onOk,desc,website,lesson_u
<Input placeholder="website链接"/> <Input placeholder="website链接"/>
)} )}
</Form.Item> </Form.Item>
<Form.Item label="实践课程">
{getFieldDecorator("lesson_url",{
rules:[]
})(
<Input placeholder="实践课程链接"/>
)}
</Form.Item>
</Form> </Form>
</Modal> </Modal>
) )

View File

@ -178,7 +178,7 @@ class NewMerge extends Component {
let arr = projects_names && projects_names.filter(item=>item.id===value); let arr = projects_names && projects_names.filter(item=>item.id===value);
let identifier = arr && arr[0].project_id; let identifier = arr && arr[0].project_id;
let login = arr && arr[0].project_user_login; let login = arr && arr[0].project_user_login;
let is_fork_id = parseInt(value) !== parseInt(id) let is_fork_id = parseInt(value) !== parseInt(id);
this.setState({ this.setState({
isSpin: true, isSpin: true,
merge_head: is_fork_id, merge_head: is_fork_id,

View File

@ -253,6 +253,24 @@ class merge extends Component {
</Menu.Item> </Menu.Item>
</Menu> </Menu>
); );
const Paginations = (
<React.Fragment>
{search_count > limit ? (
<div className="mt30 mb50 edu-txt-center">
<Pagination
simple
defaultCurrent={page}
total={search_count}
pageSize={limit}
onChange={this.ChangePage}
></Pagination>
</div>
) : (
""
)}
</React.Fragment>
);
return ( return (
<div className="main" style={{padding:"0px"}}> <div className="main" style={{padding:"0px"}}>
<div className="topWrapper" style={{borderBottom:"none",padding:"20px"}}> <div className="topWrapper" style={{borderBottom:"none",padding:"20px"}}>
@ -401,21 +419,9 @@ class merge extends Component {
{...this.props} {...this.props}
{...this.state} {...this.state}
></OrderItem> ></OrderItem>
{Paginations}
</div> </div>
):""} ):""}
{search_count > select_params.limit ? (
<div className="mt30 mb50 edu-txt-center">
<Pagination
simple
current={select_params.page}
total={search_count}
pageSize={select_params.limit}
onChange={this.ChangePage}
></Pagination>
</div>
) : (
""
)}
{ data && data.issues && data.issues.length === 0 ? <NoneData _html="暂时还没有相关数据!" projectsId={projectsId} owner={owner} /> :""} { data && data.issues && data.issues.length === 0 ? <NoneData _html="暂时还没有相关数据!" projectsId={projectsId} owner={owner} /> :""}
</Spin> </Spin>
</div> </div>

View File

@ -34,17 +34,19 @@ class MergeForm extends Component {
this.set_defatul(); this.set_defatul();
}; };
componentDidUpdate=(prevPros)=>{ componentDidUpdate=(prevPros)=>{
const { projectsId ,owner } = this.props.match.params;
const pId = prevPros.match.params.projectsId;
const oId = prevPros.match.params.owner;
if(pId !== projectsId || oId !== owner ){
// console.log("切换了项目分支···········");
this.get_default_selects();
}
if(prevPros && this.props && !this.props.checkIfLogin()){ if(prevPros && this.props && !this.props.checkIfLogin()){
this.props.history.push("/403") this.props.history.push("/403")
return return
} }
} }
// check_is_login =() =>{
// if(!this.props.checkIfLogin()){
// this.props.history.push("/403")
// return
// }
// };
get_default_selects = () => { get_default_selects = () => {
const { projectsId ,owner } = this.props.match.params; const { projectsId ,owner } = this.props.match.params;
this.setState({ isSpin: true }); this.setState({ isSpin: true });

View File

@ -218,7 +218,7 @@ class MilepostDetail extends Component {
</span> </span>
<div className="milepostdiv"> <div className="milepostdiv">
<Link to={`/projects/${owner}/${projectsId}/milestones/${meilid}/edit`} className="topWrapper_btn" style={{ marginRight: 15 }} >编辑里程碑</Link> <Link to={`/projects/${owner}/${projectsId}/milestones/${meilid}/edit`} className="topWrapper_btn" style={{ marginRight: 15 }} >编辑里程碑</Link>
<Link to={`/projects/${owner}/${projectsId}/issues/${meilid}/new`} className="topWrapper_btn">创建任务</Link> <Link to={`/projects/${owner}/${projectsId}/issues/${meilid}/new`} className="topWrapper_btn">创建易修</Link>
</div> </div>
</FlexAJ> </FlexAJ>
</div> </div>

View File

@ -352,12 +352,12 @@ class order extends Component {
if (this.props.checkIfLogin()) { if (this.props.checkIfLogin()) {
return( return(
<Link className="topWrapper_btn ml10" target="_blank" to={`/projects/${owner}/${projectsId}/issues/new`}> <Link className="topWrapper_btn ml10" target="_blank" to={`/projects/${owner}/${projectsId}/issues/new`}>
+&nbsp;创建任务 +&nbsp;创建易修
</Link> </Link>
) )
}else{ }else{
return( return(
<a className="topWrapper_btn ml10" onClick={this.islogin}>+&nbsp;创建任务</a> <a className="topWrapper_btn ml10" onClick={this.islogin}>+&nbsp;创建易修</a>
) )
} }
} }

View File

@ -310,14 +310,14 @@ class order_form extends Component {
<div className="list-right"> <div className="list-right">
<div className="pd20"> <div className="pd20">
<h3 className="mb15"> <h3 className="mb15">
{form_type === "new" ? "新建" :( form_type === "copy" ? "复制" : "编辑")}任务 {form_type === "new" ? "新建" :( form_type === "copy" ? "复制" : "编辑")}易修
</h3> </h3>
<Form.Item> <Form.Item>
{getFieldDecorator("subject", { {getFieldDecorator("subject", {
rules: [ rules: [
{ {
required: true, required: true,
message: "请填写任务标题", message: "请填写易修标题",
}, },
] ]
})(<Input placeholder="标题" size="large" />)} })(<Input placeholder="标题" size="large" />)}

View File

@ -11,7 +11,7 @@ function Collaborator(props){
const [ newGroupId , setNewGroupId] = useState(undefined); const [ newGroupId , setNewGroupId] = useState(undefined);
const {projectsId ,owner} = props.match.params; const {projectsId ,owner} = props.match.params;
const author = props && props.projectDetail && props.projectDetail.author; const author = props.projectDetail && props.projectDetail.author;
function getID(id){ function getID(id){
setNewId(id); setNewId(id);
@ -42,7 +42,7 @@ function Collaborator(props){
<div> <div>
{ {
nav === "1" ? nav === "1" ?
<Member newId={newId} projectsId={projectsId} owner={owner} project_id={props.project_id} author={props.projectDetail && props.projectDetail.author} showNotification={props.showNotification}/> <Member newId={newId} projectsId={projectsId} owner={owner} project_id={props.project_id} author={props.author} showNotification={props.showNotification}/>
: :
<Group owner={owner} projectsId={projectsId} newGroupId={newGroupId}/> <Group owner={owner} projectsId={projectsId} newGroupId={newGroupId}/>
} }

View File

@ -20,6 +20,8 @@ function CollaboratorMember({projectsId,owner,project_id,author,showNotification
const [ role , setRole ] = useState(undefined); const [ role , setRole ] = useState(undefined);
const [ listData , setListData ] = useState(undefined); const [ listData , setListData ] = useState(undefined);
const [ total , setTotal ] = useState(0); const [ total , setTotal ] = useState(0);
useEffect(()=>{ useEffect(()=>{
if(newId){ if(newId){
addCollaborator(newId); addCollaborator(newId);

View File

@ -13,7 +13,6 @@ const menu = [
{name:"易修 (Issue)",index:"issues"}, {name:"易修 (Issue)",index:"issues"},
{name:"合并请求",index:"pulls"}, {name:"合并请求",index:"pulls"},
{name:"工作流(beta版)",index:"devops"}, {name:"工作流(beta版)",index:"devops"},
// {name:"资源库",index:"resources"},
{name:"里程碑",index:"versions"}, {name:"里程碑",index:"versions"},
{name:"动态",index:"activity"}, {name:"动态",index:"activity"},
] ]

View File

@ -84,11 +84,12 @@ export default ((props) => {
// //
function removeUser(username) { function removeUser(username) {
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users/${username}.json`;
if (username) { if (username) {
const url = `/organizations/${OIdentifier}/teams/${groupId}/team_users/quit.json`;
axios.delete(url).then((result) => { axios.delete(url).then((result) => {
if (result && result.data) { if (result && result.data) {
props.showNotification(`已成功退出团队!`);
props.history.push(`/organize/${OIdentifier}`);
} }
}).catch((error) => { }); }).catch((error) => { });
} }

View File

@ -95,35 +95,15 @@ export default Form.create()(
}) })
setVisible(false); setVisible(false);
} }
function checkname(rule, value, callback){
if(!value){
callback();
}
if(value && !value.match(/^[a-zA-Z][a-zA-Z0-9_-]{3,19}$/)){
callback("只能使用以字母开头包含字母、数字、下划线、横杠等长度4到20个字符");
}
callback();
}
return( return(
<div> <div>
<WhiteBack> <WhiteBack>
<Title>基本设置</Title> <Title>基本设置</Title>
<Div> <Div>
<Form> <Form>
{helper(
"组织账号:",
"name",
[
{ required: true, message: "请输入组织账号" },
{
validator:checkname
}
],
<Input placeholder="请输入组织账号" disabled/>,true
)}
{helper( {helper(
"组织名称:", "组织名称:",
"nickname", "name",
[{ required: true, message: "请输入组织名称" }], [{ required: true, message: "请输入组织名称" }],
<Input placeholder="请输入组织名称" />,true <Input placeholder="请输入组织名称" />,true
)} )}

View File

@ -56,7 +56,7 @@ export default ((props)=>{
detail && detail &&
<Cards <Cards
src={`/organize/${OIdentifier}/group/${groupId}`} src={`/organize/${OIdentifier}/group/${groupId}`}
title={detail.nickname||detail.name} title={detail.name}
rightBtn={ rightBtn={
flag && <span className="subNavs"> flag && <span className="subNavs">
<Link to={`/organize/${OIdentifier}/member`} className={pathname ===`/organize/${OIdentifier}/member` ? "active":""}><span>组织成员</span>{detail.num_users && <lable>{detail.num_users}</lable>}</Link> <Link to={`/organize/${OIdentifier}/member`} className={pathname ===`/organize/${OIdentifier}/member` ? "active":""}><span>组织成员</span>{detail.num_users && <lable>{detail.num_users}</lable>}</Link>

View File

@ -1,7 +1,6 @@
import React, { Component } from "react"; import React, { Component } from "react";
import { Upload, Icon , Button } from 'antd'; import { Upload, Button, Icon } from 'antd';
import { getUploadActionUrl, appendFileSizeToUploadFileAll } from 'educoder'; import { getUploadActionUrl, appendFileSizeToUploadFileAll } from 'educoder';
import { AlignCenter } from '../Component/layout';
import axios from 'axios'; import axios from 'axios';
const { Dragger } = Upload; const { Dragger } = Upload;
@ -29,12 +28,22 @@ class Index extends Component {
onAttachmentRemove = (file) => { onAttachmentRemove = (file) => {
if (!file.percent || file.percent === 100) { if (!file.percent || file.percent === 100) {
// this.props.confirm({
// content: '是否确认删除?',
// onOk: () => {
// this.deleteAttachment(file)
// },
// onCancel() {
// console.log('Cancel');
// },
// });
this.deleteAttachment(file) this.deleteAttachment(file)
return false; return false;
} }
} }
deleteAttachment = (file) => { deleteAttachment = (file) => {
const url = `/attachments/${file.response ? file.response.id : file.uid}.json` const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
axios.delete(url, { axios.delete(url, {
}).then((response) => { }).then((response) => {
@ -73,7 +82,7 @@ class Index extends Component {
fileIdList = (fileList) => { fileIdList = (fileList) => {
let array = []; let array = [];
fileList && fileList.length > 0 && fileList.map((item) => { fileList && fileList.length > 0 && fileList.map((item) => {
return array.push(item.response && (item.response.id || (item.response.data && item.response.data.id))); return array.push(item.response && item.response.id);
}) })
array && this.props.load && this.props.load(array); array && this.props.load && this.props.load(array);
} }
@ -89,27 +98,21 @@ class Index extends Component {
render() { render() {
//判断是否已经提交,如已提交评论则上一条评论数据清除 //判断是否已经提交,如已提交评论则上一条评论数据清除
const { isComplete, icon , btn , className , size , actionUrl } = this.props; const { isComplete, icon } = this.props;
const { fileList } = this.state; const { fileList } = this.state;
let list = isComplete === true ? fileList : undefined; let list = isComplete === true ? fileList : undefined;
const upload = { const upload = {
name: 'file', name: 'file',
fileList: list, fileList: list,
action: actionUrl || `${getUploadActionUrl()}`, action: `${getUploadActionUrl()}`,
onChange: this.handleChange, onChange: this.handleChange,
onRemove: this.onAttachmentRemove, onRemove: this.onAttachmentRemove,
beforeUpload: this.beforeUpload beforeUpload: this.beforeUpload
}; };
return ( return (
btn ? <Dragger {...upload} className={this.props.className}>
<Upload {...upload} className={className}>
<Button type={"default"}>上传文件</Button>
<span className="ml10 color-grey-9">(你可以上传小于<span className="color-red">{size}MB</span>)</span>
</Upload>
:
<Dragger {...upload} className={className}>
{icon || <Icon type="inbox" />} {icon || <Icon type="inbox" />}
<p className="ant-upload-text font-14">拖动文件或<span className="color-blue">点击此处上传</span></p> <p className="ant-upload-text font-14">拖动文件或<span className="color-blue">点击此处上传</span></p>
</Dragger> </Dragger>

BIN
src/images/login/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -17,6 +17,21 @@ const paramRequestOldUrlArray = [
] ]
const paramRequestNewUrlArray = [ const paramRequestNewUrlArray = [
// 获取代码内容
// (matchResult) => {
// const stageId = matchResult[1]
// return `/tasks/${stageId}/rep_content.json`
// },
// 获取版本库目录、文件
// http://testeduplus2.educoder.net/tasks/se79x25pzfwo/git_entries.json?path=&dev=master&gpid=3441
// (matchResult) => {
// const stageId = matchResult[1]
// // return `/tasks/${stageId}/git_entries.json`
// return `/myshixuns/${stageId}/repository.json`
// },
// `/tasks/tonblikwzj78/choose_build.json`
(matchResult) => { (matchResult) => {
const stageId = matchResult[1] const stageId = matchResult[1]
return `/tasks/${stageId}/choose_build.json` return `/tasks/${stageId}/choose_build.json`
@ -50,4 +65,20 @@ export function requestProxy(config) {
}); });
} }
return config; return config;
} }
/**
('/api/v1/careers/qweqw/edit/').match(/\/api\/v1\/careers\/(\w*)\/edit/i)
0: "/api/v1/careers/qweqw/edit"
1: "qweqw"
example:
`/api/v1/games/${this.props.game.identifier}/answer_grade` ->
`/tasks/${this.props.game.identifier}/answer_grade.json`
https://testeduplus2.educoder.net/api/v1/games/feguz4tiqpvx/rep_content
?path=src/step2/CLnkQueue.cpp&shixun_gpid=2791&status=0&retry=0 ->
http://testeduplus2.educoder.net/tasks/tonblikwzj78/rep_content.json
?path=1-4.py&shixun_gpid=2448&status=0
*/

View File

@ -1366,6 +1366,10 @@ samp {
line-height: 40px; line-height: 40px;
} }
.courseForm .ant-input-group>.ant-input:first-child,
.ant-input-group-addon:first-child {
height: 40px;
}
.courseForm .ant-select-selection, .courseForm .ant-select-selection,
.courseForm .ant-select-selection-selected-value { .courseForm .ant-select-selection-selected-value {
@ -1718,6 +1722,12 @@ samp {
background-color: #fff !important; background-color: #fff !important;
} }
.ant-input-group-addon {
color: #666 !important;
font-size: 12px;
border: 1px solid #d9d9d9 !important;
border-left: none !important;
}
.check_on { .check_on {
background: #4CACFF; background: #4CACFF;

View File

@ -1,14 +1,13 @@
import React, {Component} from "react"; import React, { Component } from "react";
import moment from 'moment'; import moment from 'moment';
import { getImageUrl } from 'educoder'; import { getImageUrl } from 'educoder';
import '../courses/css/members.css'; import '../courses/css/members.css';
import "../courses/common/formCommon.css"; import "../courses/common/formCommon.css"
import '../courses/css/Courses.css'; import '../courses/css/Courses.css';
import beijintulogontwo from '../../../src/images/login/beijintulogontwo.png'; import beijintulogontwo from '../../../src/images/login/beijintulogontwo.png';
import educodernet from '../../../src/images/login/educodernet.png'; import educodernet from '../../../src/images/login/logo.png';
import LoginRegisterComponent from '../user/LoginRegisterComponent'; import LoginRegisterComponent from '../user/LoginRegisterComponent';
import FindPasswordComponent from '../user/FindPasswordComponent'; import FindPasswordComponent from '../user/FindPasswordComponent';
//educoder登入页面
var newContainer={ var newContainer={
background: `url(${beijintulogontwo})`, background: `url(${beijintulogontwo})`,
@ -47,7 +46,6 @@ class EducoderLogin extends Component {
} }
}else if(props.match.url === "/register"){ }else if(props.match.url === "/register"){
// showbool: 1,
this.state = { this.state = {
showbool: 1, showbool: 1,
loginstatus:false, loginstatus:false,
@ -64,18 +62,12 @@ class EducoderLogin extends Component {
loginstatus:true, loginstatus:true,
} }
} }
} }
} }
Setlogins=(i)=>{ Setlogins=(i)=>{
console.log("96ye");
console.log(i)
this.setState({ this.setState({
logini:i logini:i
}) })
} }
gohome=()=>{ gohome=()=>{
window.location.href="/" window.location.href="/"
@ -94,84 +86,39 @@ class EducoderLogin extends Component {
render() { render() {
let {showbool,loginstatus,logini} = this.state; let { showbool } = this.state;
const { settings } = this.props;
return ( return (
<div style={newContainer} className=" clearfix" > <div style={newContainer} className=" clearfix" >
<div style={{"justify-content": "center","align-items": "center","width": "100%",textAlign:"center"}}>
<div > <div style={{cursor:"pointer"}}>
<div style={{ {
"display": "flex", settings && settings.login_logo_url ?
"justify-content": "center", <img style={{cursor:"pointer"}} alt="" onClick={()=>this.gohome()} width="80px" src={getImageUrl(settings.login_logo_url)}/>
"align-items": "center", :
"width": "100%" <img style={{cursor:"pointer"}} alt="" onClick={()=>this.gohome()} src={educodernet} width="80px"/>
}}> }
<div style={{cursor:"pointer"}}>
{this.props.mygetHelmetapi === null ? ""
:
this.props.mygetHelmetapi===undefined||this.props.mygetHelmetapi.login_logo_url===null|| this.props.mygetHelmetapi.login_logo_url===undefined?
<img style={{cursor:"pointer"}} onClick={()=>this.gohome()} src={educodernet}/>
:
<img style={{cursor:"pointer"}} onClick={()=>this.gohome()} src={getImageUrl(this.props.mygetHelmetapi.login_logo_url)}/>
}
</div>
</div> </div>
{ {
showbool === 1 ? showbool === 1 ?
<div style={{ <div style={{
display: "flex", display: "flex",
justifyContent: "center", justifyContent: "center",
width: "100%", width: "100%",
marginTop: "25px", marginTop: "25px",
}}> }}>
<div> <div>
<LoginRegisterComponent {...this.props} {...this.state} Setshowbool={(e)=>this.Setshowbool(e)} ></LoginRegisterComponent>
<LoginRegisterComponent {...this.props} {...this.state}
Setshowbool={(e)=>this.Setshowbool(e)} ></LoginRegisterComponent>
</div>
</div> </div>
</div>
: :
<div style={{ <div style={{display: "flex",justifyContent: "center",width: "100%",marginTop: "25px",}}>
display: "flex", <div>
justifyContent: "center", <FindPasswordComponent {...this.props} {...this.state} Setshowbool={(e)=>this.Setshowbool(e)}></FindPasswordComponent>
width: "100%", </div>
marginTop: "25px", </div>
}}>
<div >
<FindPasswordComponent {...this.props} {...this.state}
Setshowbool={(e)=>this.Setshowbool(e)}></FindPasswordComponent>
</div>
</div>
} }
{this.props.mygetHelmetapi === null ? <div style={{ <div className="font-14 color-grey-9 " style={{marginTop:"20px"}}><span className="font-18">©</span>&nbsp;{moment().year()}&nbsp;Trustie<span className="ml15 mr15">ICP17009477</span><a href="https://team.trustie.net" style={{"color":"#888"}} target="_blank">Trustie</a>&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;IntelliDE inside.</div>
display: "flex",
justifyContent: "center",
width: "100%",
}}>
<div className="font-14 color-grey-9 " style={{marginTop:"20px"}}><span className="font-18">©</span>&nbsp;{moment().year()}&nbsp;EduCoder<span className="ml15 mr15">ICP17009477</span><a href="https://team.trustie.net" style={{"color":"#888"}} target="_blank">Trustie</a>&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;IntelliDE inside.</div>
</div>:
this.props.mygetHelmetapi===undefined||this.props.mygetHelmetapi.main_site===null|| this.props.mygetHelmetapi.main_site===undefined? <div style={{
display: "flex",
justifyContent: "center",
width: "100%",
}}>
<div className="font-14 color-grey-9 " style={{marginTop:"20px"}}><span className="font-18">©</span>&nbsp;{moment().year()}&nbsp;EduCoder<span className="ml15 mr15">ICP17009477</span><a href="https://team.trustie.net" style={{"color":"#888"}} target="_blank">Trustie</a>&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;IntelliDE inside.</div>
</div>:this.props.mygetHelmetapi.main_site===true?
<div style={{
display: "flex",
justifyContent: "center",
width: "100%",
}}>
<div className="font-14 color-grey-9 " style={{marginTop:"20px"}}><span className="font-18">©</span>&nbsp;{moment().year()}&nbsp;EduCoder<span className="ml15 mr15">ICP17009477</span><a href="https://team.trustie.net" style={{"color":"#888"}} target="_blank">Trustie</a>&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;IntelliDE inside.</div>
</div>
:""
}
</div> </div>
</div> </div>
) )

View File

@ -4,7 +4,6 @@ import Dialog from 'material-ui/Dialog';
import { notification } from 'antd'; import { notification } from 'antd';
import axios from 'axios'; import axios from 'axios';
import educoderLogo from './educoder.png';
import './LoginDialog.css'; import './LoginDialog.css';
import { broadcastChannelPostMessage } from 'educoder' import { broadcastChannelPostMessage } from 'educoder'
@ -302,9 +301,12 @@ class LoginDialog extends Component {
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
this.setState({ this.setState({
isRender: nextProps.isRender isRender: nextProps.isRender
}) })
// console.log(nextProps.isRender);
} }
IsPC = () => { IsPC = () => {
var userAgentInfo = navigator.userAgent; var userAgentInfo = navigator.userAgent;
@ -321,8 +323,8 @@ class LoginDialog extends Component {
return flag; return flag;
} }
componentDidMount() { componentDidMount() {
//true为PC端false为手机端
let flag = this.IsPC(); let flag = this.IsPC(); //true为PC端false为手机端
this.setState({ this.setState({
isphone: flag isphone: flag
}) })
@ -354,6 +356,7 @@ class LoginDialog extends Component {
} }
loginEDU = () => { loginEDU = () => {
let { loginValue, passValue, regular, isGoingValue } = this.state; let { loginValue, passValue, regular, isGoingValue } = this.state;
if (regular === 1) { if (regular === 1) {
return return
@ -375,8 +378,15 @@ class LoginDialog extends Component {
if (response.data.message === "登录密码出错已达上限,账号已被锁定, 请10分钟后重新登录或找回密码") { if (response.data.message === "登录密码出错已达上限,账号已被锁定, 请10分钟后重新登录或找回密码") {
const messge = ( const messge = (
<div> <div>
<p>登录密码出错已达上限账号已被锁定</p> <p>
<p className="mt10">请10分钟后重新登录或<a href={'https://www.trustie.net/account/lost_password'} style={{textDecoration: "underline",color: "#4CACFF"}}>找回密码</a></p> 登录密码出错已达上限账号已被锁定
</p>
<p className="mt10">
请10分钟后重新登录或<a href={'https://www.trustie.net/account/lost_password'} style={{
textDecoration: "underline",
color: "#4CACFF",
}}>找回密码</a>
</p>
</div> </div>
) )
this.openNotifications(messge); this.openNotifications(messge);
@ -420,6 +430,11 @@ class LoginDialog extends Component {
getloginurl = (url) => { getloginurl = (url) => {
window.location.href = url; window.location.href = url;
}; };
openweixinlogin = () => {
this.setState({
weixinlogin: true
})
}
openNotifications = (btn) => { openNotifications = (btn) => {
// type 1 成功提示绿色 2提醒颜色黄色 3错误提示红色 // type 1 成功提示绿色 2提醒颜色黄色 3错误提示红色
notification.open({ notification.open({
@ -455,16 +470,18 @@ class LoginDialog extends Component {
} }
render() { render() {
let { login, isGoing, isGoingValue, disabled , Phonenumberisnotco , dialogBox, isRender, weixinlogin } = this.state; let { qqlogin, login, isGoing, isGoingValue, disabled, bottonclass, Phonenumberisnotco,
let { settings } = this.props; dialogBox, isRender, weixinlogin } = this.state;
let { settings } = this.props;
if (isRender === undefined) { if (isRender === undefined) {
isRender = false isRender = false
} }
return ( return (
<Dialog open={true} id="DialogID" <Dialog open={true} id="DialogID"
className="zindextest" className="zindextest"
style={{ display: isRender === false ? 'none' : '' }} style={{ display: isRender == false ? 'none' : '' }}
disableEscapeKeyDown={true} disableEscapeKeyDown={true}
disableBackdropClick={true} disableBackdropClick={true}
onClose={() => this.handleDialogClose()} onClose={() => this.handleDialogClose()}
@ -495,7 +512,7 @@ class LoginDialog extends Component {
<li onClick={() => { this.enter(0) }}>登录</li> <li onClick={() => { this.enter(0) }}>登录</li>
</ul>} </ul>}
<div className="login-panel" id="login-panel-1" style={{ display: login == 0 ? 'block' : 'none' }}> <div className="login-panel" id="login-panel-1" style={{ display: login == 0 ? 'block' : 'none' }}>
<form acceptCharset="UTF-8" action="/login" id="main_login_form" method="post"> {weixinlogin === true ? "" : <form acceptCharset="UTF-8" action="/login" id="main_login_form" method="post">
<div style={{ "display": "inline", "padding": "0", "margin": "0" }}> <div style={{ "display": "inline", "padding": "0", "margin": "0" }}>
<input name="utf8" type="hidden" value="✓"></input> <input name="utf8" type="hidden" value="✓"></input>
@ -520,10 +537,9 @@ class LoginDialog extends Component {
<div style={{ height: '25px' }}><p className="color-orange edu-txt-left none" id="username_error_notice" <div style={{ height: '25px' }}><p className="color-orange edu-txt-left none" id="username_error_notice"
style={{ display: Phonenumberisnotco === undefined ? 'none' : 'block' }}>{Phonenumberisnotco}</p></div> style={{ display: Phonenumberisnotco === undefined ? 'none' : 'block' }}>{Phonenumberisnotco}</p></div>
<div> <div>
<input <input type="password" id="password_loggin_input"
type="password"
id="password_loggin_input"
name="password" name="password"
ref="passwordText" ref="passwordText"
onInput={this.passwordChange} onInput={this.passwordChange}
@ -533,8 +549,8 @@ class LoginDialog extends Component {
this.loginEDU : () => { this.loginEDU : () => {
} }
} }
placeholder="密码" placeholder="密码" >
/> </input>
<div style={{ height: '25px' }}> <div style={{ height: '25px' }}>
<p className="color-orange edu-txt-left none" id="password_error_notice"> <p className="color-orange edu-txt-left none" id="password_error_notice">
请输入密码 请输入密码
@ -565,25 +581,38 @@ class LoginDialog extends Component {
<a onClick={(url) => this.getloginurl(`${settings && settings.common && settings.common.register}`)} className="color-grey-9">注册</a> <a onClick={(url) => this.getloginurl(`${settings && settings.common && settings.common.register}`)} className="color-grey-9">注册</a>
</span> </span>
</p> </p>
{
settings && settings.third_party && settings.third_party.length > 0 ? {this.props.user && this.props.user.main_site === true ? this.state.isphone === true ? <p className="clearfix mt20">
<p className="clearfix mt20"> <span className={"startlogin"}> 快速登录 </span>
<div className={"mt10"}>
<a onClick={() => this.openweixinlogin()}>
<img src={require('./WeChat.png')} alt="微信登录" />
</a>
<a onClick={() => this.openqqlogin()} className={"ml10"}>
<img src={require('./qq.png')} alt="qq登录" />
</a>
</div>
</p> : <p className="clearfix mt20">
<span className={"startlogin"}> 快速登录 </span> <span className={"startlogin"}> 快速登录 </span>
<div className={"mt10"}> <div className={"mt10"}>
{settings.third_party.map((item,key)=>{ <a onClick={() => this.openphoneqqlogin()} className={"ml10"}>
return( <img src={require('./qq.png')} alt="qq登录" />
<a href={`${item.url}`}> </a>
<img src={item.name === "educoder" ? educoderLogo : ""} width="46px" alt={`${item.name}登录`} />
</a>
)
})
}
</div> </div>
</p> </p> : ""}
:"" </form>}
} {weixinlogin === true ? <iframe
</form> className={"weixinheight390"}
frameBorder="0"
sandbox="allow-scripts allow-same-origin allow-top-navigation"
scrolling="no"
src={`https://open.weixin.qq.com/connect/qrconnect?appid=wx6b119e2d829c13fa&redirect_uri=https%3a%2f%2fwww.educoder.net%2fotherloginstart&response_type=code&scope=snsapi_login&state=null,${window.location.host}#wechat_redirect`}></iframe> : ""}
{weixinlogin === true ? <p className="clearfix ">
<a className={"startlogin color-blue"} onClick={() => this.hideweixinlogin()}>返回账号登录</a>
</p> : ""}
</div> </div>
{/*快捷登录*/}
</div> </div>
</div> </div>
: ""} : ""}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1062,7 +1062,7 @@ class TPMBanner extends Component {
</div> : </div> :
<div className="task-popup-content"> <div className="task-popup-content">
<p className="task-popup-text-center font-16 mt10 mb10"> <p className="task-popup-text-center font-16 mt10 mb10">
尚未创建任务的实训不能申请发布 尚未创建易修的实训不能申请发布
</p> </p>
</div> </div>
} }

View File

@ -5,7 +5,6 @@ import axios from 'axios';
import { Spin } from 'antd'; import { Spin } from 'antd';
import './TPMIndex.css'; import './TPMIndex.css';
import LoginDialog from '../login/LoginDialog'; import LoginDialog from '../login/LoginDialog';
import EducoderAccount from '../../forge/Component/EducoderAccount';
export function TPMIndexHOC(WrappedComponent) { export function TPMIndexHOC(WrappedComponent) {
return class II extends React.Component { return class II extends React.Component {
@ -206,14 +205,13 @@ export function TPMIndexHOC(WrappedComponent) {
render() { render() {
let { isRender , current_user , giteaVisible , email } = this.state; let { isRender , current_user } = this.state;
const common = { const common = {
showLoginDialog: this.showLoginDialog, showLoginDialog: this.showLoginDialog,
checkIfLogin: this.checkIfLogin, checkIfLogin: this.checkIfLogin,
}; };
return ( return (
<div className="indexHOC"> <div className="indexHOC">
<EducoderAccount visible={giteaVisible} email={email} onOk={this.onOk}/>
{isRender === true ? <LoginDialog {isRender === true ? <LoginDialog
Modifyloginvalue={() => this.hideLoginDialog()} Modifyloginvalue={() => this.hideLoginDialog()}
{...this.props} {...this.props}

File diff suppressed because it is too large Load Diff