Merge branch 'jupyter' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_jupyter

chromesetting
杨树林 5 years ago
commit 4bf67843a8

@ -316,6 +316,11 @@ const RecordDetail = Loadable({
loader: () => import('./modules/developer/recordDetail'), loader: () => import('./modules/developer/recordDetail'),
loading: Loading loading: Loading
}); });
// jupyter tpi
const JupyterTPI = Loadable({
loader: () => import('./modules/tpm/jupyter'),
loading: Loading
});
// //个人竞赛报名 // //个人竞赛报名
// const PersonalCompetit = Loadable({ // const PersonalCompetit = Loadable({
// loader: () => import('./modules/competition/personal/PersonalCompetit.js'), // loader: () => import('./modules/competition/personal/PersonalCompetit.js'),
@ -615,7 +620,7 @@ class App extends Component {
<Route path="/shixuns/:shixunId" component={TPMIndexComponent}> <Route path="/shixuns/:shixunId" component={TPMIndexComponent}>
</Route> </Route>
{/*列表页*/} {/*列表页 实训项目列表*/}
<Route path="/shixuns" component={TPMShixunsIndexComponent}/> <Route path="/shixuns" component={TPMShixunsIndexComponent}/>
@ -697,6 +702,10 @@ class App extends Component {
(props) => (<Developer {...this.props} {...props} {...this.state} />) (props) => (<Developer {...this.props} {...props} {...this.state} />)
}/> }/>
<Route path="/jupytertpi"
component={JupyterTPI}
/>
<Route exact path="/" <Route exact path="/"
// component={ShixunsHome} // component={ShixunsHome}
render={ render={

@ -13,7 +13,7 @@ function locationurl(list){
if (window.location.port === "3007") { if (window.location.port === "3007") {
} else { } else {
window.location.replace(list) window.location.href(list)
} }
} }
let hashTimeout let hashTimeout

@ -0,0 +1,15 @@
/*
* @Description: 引入阿里图标库
* @Author: tangjiang
* @Github:
* @Date: 2019-12-10 09:03:48
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-10 09:05:41
*/
import { Icon } from 'antd';
const MyIcon = Icon.createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/font_1535266_ss6796i6f6j.js'
});
export default MyIcon;

@ -756,7 +756,7 @@ class Fileslists extends Component{
Savesname={this.state.Savesname} Savesname={this.state.Savesname}
Cancel={this.state.Cancel} Cancel={this.state.Cancel}
Saves={this.state.Saves} Saves={this.state.Saves}
course_groups={this.state.course_groups} // course_groups={this.state.course_groups}
/>:""} />:""}
{/*发送*/} {/*发送*/}

@ -428,6 +428,9 @@ class NewShixunModel extends Component{
.ant-drawer-body { .ant-drawer-body {
padding:15px 24px 24px 0px; padding:15px 24px 24px 0px;
} }
.ant-dropdown {
z-index:11000
}
` `
} }
</style> </style>
@ -536,6 +539,21 @@ class NewShixunModel extends Component{
className="fl task-hide edu-txt-left mt3" className="fl task-hide edu-txt-left mt3"
name="shixun_homework[]" name="shixun_homework[]"
></Checkbox> ></Checkbox>
{
this.props.type==='shixuns'?
(
item.is_jupyter===true?
<div className="myysljupyter fl ml15 mt3 intermediatecenter">
<p className="myysljupytertest">
Jupyter
</p>
</div>
:""
)
:""
}
<a target="_blank" href={this.props.type==='shixuns'?`/shixuns/${item.identifier}/challenges`:`/paths/${item.id}`} className="ml15 fl font-16 color-dark maxwidth1100" <a target="_blank" href={this.props.type==='shixuns'?`/shixuns/${item.identifier}/challenges`:`/paths/${item.id}`} className="ml15 fl font-16 color-dark maxwidth1100"
dangerouslySetInnerHTML={{__html: item.title}} dangerouslySetInnerHTML={{__html: item.title}}
> >

@ -385,3 +385,22 @@
.newshixunmodels{ .newshixunmodels{
margin: 0 auto; margin: 0 auto;
} }
.myysljupyter{
width:48px;
height:22px;
background:#FF6802;
border-radius:2px 10px 10px 2px;
}
.myysljupytertest{
width:39px;
height:16px;
font-size:12px;
color:#FFFFFF;
line-height:16px;
}
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

@ -492,13 +492,13 @@ class YslDetailCards extends Component{
:<i className="iconfont icon-bofang progressRing-part font-18 mt10"></i> :<i className="iconfont icon-bofang progressRing-part font-18 mt10"></i>
} }
</span> </span>
<span className={this.props.current_user&&this.props.current_user.admin===false&&line.shixun_status==="暂未公开"?"paragraph_name color204":"paragraph_name color-grey3"}> <span className={this.props.current_user&&this.props.current_user.admin===false&&this.props.current_user&&this.props.current_user.business===false&&line.shixun_status==="暂未公开"?"paragraph_name color204":"paragraph_name color-grey3"}>
<span className="subject_stage_shixun_index">{key+1}</span>-{index+1}&nbsp;&nbsp;{line.shixun_name} <span className="subject_stage_shixun_index">{key+1}</span>-{index+1}&nbsp;&nbsp;{line.shixun_name}
</span> </span>
</li> </li>
{ {
this.props.current_user&&this.props.current_user.admin===false&&line.shixun_status==="暂未公开"? this.props.current_user&&this.props.current_user.admin===false&&this.props.current_user&&this.props.current_user.business===false&&line.shixun_status==="暂未公开"?
<li className="fr status_li"><span className="fr color204">暂未公开</span></li> <li className="fr status_li"><span className="fr color204">暂未公开</span></li>
: :
<li className={showparagraph===false?"none":"fr status_li"}> <li className={showparagraph===false?"none":"fr status_li"}>
@ -512,7 +512,7 @@ class YslDetailCards extends Component{
</li> </li>
} }
{this.props.current_user&&this.props.current_user.admin===false&&line.shixun_status==="暂未公开"?"": <li className={showparagraph===false?"fr status_li":"fr status_li"}> {this.props.current_user&&this.props.current_user.admin===false&&this.props.current_user&&this.props.current_user.business===false&&line.shixun_status==="暂未公开"?"": <li className={showparagraph===false?"fr status_li":"fr status_li"}>
{ {
showparagraphkey === key && showparagraphindex === index ? "" : showparagraphkey === key && showparagraphindex === index ? "" :
<span className="fr color204">实验任务 <span <span className="fr color204">实验任务 <span

@ -9,13 +9,15 @@
import './index.scss'; import './index.scss';
import React from 'react'; import React from 'react';
import { Table, Button, Dropdown, Icon, Menu, Card, Input, Select, Tag } from 'antd'; import { Table, Button, Dropdown, Icon, Menu, Card, Input, Select, Tag, Modal } from 'antd';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import actions from '../../redux/actions'; import actions from '../../redux/actions';
import MultipTags from './components/multiptags'; import MultipTags from './components/multiptags';
import { Link } from 'react-router-dom'; // import { Link } from 'react-router-dom';
import CONST from '../../constants'; import CONST from '../../constants';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
import { toStore } from 'educoder';
// import MyIcon from '../../common/components/MyIcon';
const {tagBackground, diffText} = CONST; const {tagBackground, diffText} = CONST;
const { Search } = Input; const { Search } = Input;
@ -104,14 +106,30 @@ class DeveloperHome extends React.PureComponent {
options = { options = {
title: '操作', title: '操作',
key: 'action', key: 'action',
fixed: 'right', // fixed: 'right',
width: 100, width: 100,
render: (text, record) => ( render: (text, record) => (
<span> <React.Fragment>
<Button type="primary" onClick={() => this.handleClickEditor(record.identifier)}>编辑 <Button
shape="circle"
type="primary"
icon="edit"
size="small"
onClick={() => this.handleClickEditor(record.identifier)}
>
{/* <Link to={`/problems/${record.identifier}/edit`}></Link> */} {/* <Link to={`/problems/${record.identifier}/edit`}></Link> */}
</Button> </Button>
</span> <Button
shape="circle"
type="danger"
icon="close"
size="small"
style={{ marginLeft: '10px' }}
onClick={() => this.handleClickDelete(record)}
>
{/* <Link to={`/problems/${record.identifier}/edit`}></Link> */}
</Button>
</React.Fragment>
), ),
} }
@ -222,6 +240,22 @@ class DeveloperHome extends React.PureComponent {
this.props.history.push(`/problems/${identifier}/edit`) this.props.history.push(`/problems/${identifier}/edit`)
} }
} }
// 删除
handleClickDelete = (record) => {
const { deleteItem } = this.props;
Modal.confirm({
title: '删除',
content: `确定要删除${record.name}吗?`,
okText: '确定',
cancelText: '取消',
onOk () {
// 调用删除接口
console.log(record.identifier);
deleteItem(record.identifier);
}
});
}
// table条件变化时 // table条件变化时
handleTableChange = (pagination, filters, sorter) => { handleTableChange = (pagination, filters, sorter) => {
const {field, order} = sorter; const {field, order} = sorter;
@ -374,7 +408,7 @@ class DeveloperHome extends React.PureComponent {
// console.log('name has click', record); // console.log('name has click', record);
// 先调用start接口获取返回的 identifier, 再跳转到开启编辑 // 先调用start接口获取返回的 identifier, 再跳转到开启编辑
if (this.isLogin()) { if (this.isLogin()) {
// console.log(record); toStore('hack_identifier', record.identifier); // 保存当前编辑的id号
this.props.startProgramQuestion(record.identifier, this.props); this.props.startProgramQuestion(record.identifier, this.props);
} }
} }
@ -499,7 +533,8 @@ const mapDispatchToProps = (dispatch) => ({
handleClick: () => dispatch(actions.toggleTodo()), handleClick: () => dispatch(actions.toggleTodo()),
fetchOJList: (params) => dispatch(actions.getOJList(params)), fetchOJList: (params) => dispatch(actions.getOJList(params)),
changePaginationInfo: (obj) => dispatch(actions.changePaginationInfo(obj)), changePaginationInfo: (obj) => dispatch(actions.changePaginationInfo(obj)),
startProgramQuestion: (id, props) => dispatch(actions.startProgramQuestion(id, props)) startProgramQuestion: (id, props) => dispatch(actions.startProgramQuestion(id, props)),
deleteItem: (identifier) => dispatch(actions.deleteItem(identifier))
}); });
export default withRouter(connect( export default withRouter(connect(

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-27 16:02:36 * @Date: 2019-11-27 16:02:36
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-03 09:19:54 * @LastEditTime: 2019-12-10 09:30:27
*/ */
import './index.scss'; import './index.scss';
import React, { useState, useRef } from 'react'; import React, { useState, useRef } from 'react';

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-28 08:44:54 * @Date: 2019-11-28 08:44:54
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-03 12:38:27 * @LastEditTime: 2019-12-10 09:24:02
*/ */
import './index.scss'; import './index.scss';
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
@ -19,7 +19,7 @@ function ExecResult (props) {
// 指定渲染初始, 加载中, 加载完成页面内容 // 指定渲染初始, 加载中, 加载完成页面内容
const renderInit = () => ( const renderInit = () => (
<div className={'excute_result_area excute_flex_center'}> <div className={'excute_result_area excute_flex_center'}>
<span className={'init_ctx'}>先点击调试代码运行您的代码</span> <span className={'init_ctx'}>填写测试用例的输入值点击调试代码</span>
</div> </div>
); );
const renderLoading = () => ( const renderLoading = () => (

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-27 19:46:14 * @Date: 2019-11-27 19:46:14
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-03 09:14:59 * @LastEditTime: 2019-12-10 09:31:00
*/ */
import './index.scss'; import './index.scss';
import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef } from 'react'; import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef } from 'react';
@ -42,7 +42,6 @@ function InitTabCtx (props, ref) {
<Form className={'user_case_form'}> <Form className={'user_case_form'}>
<FormItem <FormItem
className={'input_area flex_l'} className={'input_area flex_l'}
label='输入'
> >
{ {
getFieldDecorator('input', { getFieldDecorator('input', {
@ -50,7 +49,10 @@ function InitTabCtx (props, ref) {
{ required: true, message: '输入值不能为空'} { required: true, message: '输入值不能为空'}
], ],
initialValue: inputValue initialValue: inputValue
})(<TextArea rows={5} />) })(<TextArea
rows={8}
placeholder="请填写测试用例的输入值,点击“调试代码”"
/>)
} }
</FormItem> </FormItem>
</Form> </Form>

@ -27,7 +27,7 @@ export default class MultipTags extends PureComponent {
<span className={`tag-txt ${type}`}> <span className={`tag-txt ${type}`}>
{ text } { text }
</span> </span>
<span className={'tag-numb'}> <span className={`tag-numb ${type}`}>
{ result } { result }
</span> </span>
</div> </div>

@ -5,38 +5,75 @@
.tag-txt, .tag-numb{ .tag-txt, .tag-numb{
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
padding: 0 10px;
// line-height: 20px; // line-height: 20px;
// height: 20px; // height: 20px;
box-sizing: border-box;
font-size: 12px; font-size: 12px;
text-align: center; text-align: center;
height: 24px;
padding: 0 10px;
} }
.tag-txt{
border: 1px solid transparent;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
color: #fff;
.tag-txt,
.tag-numb{
border: 1px solid transparent;
&.primary{ &.primary{
background: #1890ff; // background: #28BD8B;
border-color: #28BD8B;
color: #28BD8B;
} }
&.warning{ &.warning{
background: #faad14; // background: #FF9802;
border-color: #FF9802;
color: #FF9802;
} }
&.success{ &.success{
background: #52c41a; // background: #52c41a;
border-color: #28BD8B;
color: #28BD8B;
} }
&.error{ &.error{
background: #f5222d; // background: #FF5555;
border-color: #FF5555;
color: #FF5555;
}
}
.tag-txt{
position: relative;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
// color: #fff;
border-right: none;
&::before {
position: absolute;
content: '';
right: 0;
top: 5px;
bottom:5px;
border-right: 1px solid transparent;
}
&.primary::before{
border-right-color: #28BD8B;
}
&.warning::before{
border-right-color: #FF9802;
}
&.success::before{
border-right-color: #28BD8B;
}
&.error::before{
border-right-color: #FF5555;
} }
} }
.tag-numb{ .tag-numb{
border: 1px solid rgba(238, 238, 238, 1);
border-top-right-radius: 4px; border-top-right-radius: 4px;
border-bottom-right-radius: 4px; border-bottom-right-radius: 4px;
border-left-color: transparent; border-left-color: transparent;
margin-left: -1px; margin-left: -1px;
min-width: 40px; min-width: 40px;
border-left: none;
} }
} }

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-27 15:02:52 * @Date: 2019-11-27 15:02:52
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 16:50:54 * @LastEditTime: 2019-12-10 09:20:42
*/ */
import './index.scss'; import './index.scss';
import React, { useState, useRef, useEffect } from 'react'; import React, { useState, useRef, useEffect } from 'react';
@ -14,6 +14,8 @@ import { connect } from 'react-redux';
import MonacoEditor from '@monaco-editor/react'; import MonacoEditor from '@monaco-editor/react';
import SettingDrawer from '../../components/monacoSetting'; import SettingDrawer from '../../components/monacoSetting';
import CONST from '../../../../constants'; import CONST from '../../../../constants';
import MyIcon from '../../../../common/components/MyIcon';
// import actions from '../../../../redux/actions'; // import actions from '../../../../redux/actions';
const { fontSetting, opacitySetting } = CONST; const { fontSetting, opacitySetting } = CONST;
@ -38,7 +40,7 @@ function MyMonacoEditor (props, ref) {
const [theme, setTheme] = useState(() => { // 主题 theme const [theme, setTheme] = useState(() => { // 主题 theme
return fromStore('oj_theme') || 'dark'; return fromStore('oj_theme') || 'dark';
}); });
const [ height, setHeight ] = useState('calc(100% - 112px)'); const [ height, setHeight ] = useState('calc(100% - 56px)');
const editorRef = useRef(null); const editorRef = useRef(null);
useEffect(() => { useEffect(() => {
@ -48,7 +50,7 @@ function MyMonacoEditor (props, ref) {
}, [props]); }, [props]);
useEffect(() => { useEffect(() => {
setHeight(showOrHideControl ? 'calc(100% - 382px)' : 'calc(100% - 112px)'); setHeight(showOrHideControl ? 'calc(100% - 382px)' : 'calc(100% - 56px)');
}, [showOrHideControl]); }, [showOrHideControl]);
// 控制侧边栏设置的显示 // 控制侧边栏设置的显示
@ -101,13 +103,19 @@ function MyMonacoEditor (props, ref) {
}) })
} }
const renderRestore = identifier ? (
<MyIcon type="iconzaicizairu" />
) : '';
return ( return (
<React.Fragment> <React.Fragment>
<div className={"monaco_editor_area"}> <div className={"monaco_editor_area"}>
<div className="code_title"> <div className="code_title">
{/* 未保存时 ? '学员初始代码文件' : main.x */}
<span className='flex_strict' style={{ color: '#fff'}}>{identifier ? '' : '学员初始代码文件'}</span>
<span className='flex_strict'>{identifier ? '已保存' : ''}</span> <span className='flex_strict'>{identifier ? '已保存' : ''}</span>
<span onClick={handleRestoreCode} className="flex_normal">{identifier ? '恢复初始代码' : ''}</span> <span onClick={handleRestoreCode} className="flex_normal">{renderRestore}</span>
<Icon className={'code-icon'} type="setting" onClick={handleShowDrawer}/> {/* <Icon className={'code-icon'} type="setting" onClick={handleShowDrawer}/> */}
<MyIcon className='code-icon' type="iconshezhi" onClick={handleShowDrawer}/>
</div> </div>
<MonacoEditor <MonacoEditor
height={height} height={height}

@ -4,7 +4,8 @@
display: flex; display: flex;
align-items: center; align-items: center;
// justify-content: space-between; // justify-content: space-between;
background: #000; // background: #000;
background: #333333;
color: #fff; color: #fff;
height: 56px; height: 56px;
padding: 0 30px; padding: 0 30px;
@ -19,5 +20,39 @@
.code-icon{ .code-icon{
cursor: pointer; cursor: pointer;
} }
.flex_strict,
.flex_normal,
.code-icon{
color: #888;
}
}
}
.setting_drawer{
// .ant-drawer-body{
// // height: calc(100vh - 120px);
// // overflow-y: auto;
// }
.ant-drawer-content{
top: 120px;
bottom: 56px;
height: calc(100vh - 176px);
background: #333333;
color: #fff;
.setting_h2{
color: #fff;
}
select{
color: #fff;
background: #222222;
height: 24px;
// line-height: 24px;
margin-top: 4px;
}
select option{
background: gold;
color: #fff;
}
} }
} }

@ -0,0 +1,28 @@
/*
* @Description: 用户头像及昵称
* @Author: tangjiang
* @Github:
* @Date: 2019-12-09 17:11:28
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-09 17:36:55
*/
import './index.scss';
import React from 'react';
import { getImageUrl } from 'educoder'
function UserInfo (props) {
const {image_url, name} = props.userInfo;
return (
<div className={'avator_nicker'}>
<img alt="用户头像" className={'student_img'} src={getImageUrl(`images/${image_url}` || 'images/educoder/headNavLogo.png?1526520218')} />
<span className={'student_nicker'}>
{name || ''}
</span>
</div>
);
}
export default UserInfo
export {
UserInfo
};

@ -0,0 +1,25 @@
.avator_nicker{
position: absolute;
color: #fff;
line-height: 65px;
// height: 65px;
.student_img,
.student_nicker{
display: inline-block;
vertical-align: top;
}
.student_nicker{
margin-left: 10px;
}
.student_img{
width: 30px;
height: 30px;
border-radius: 50%;
margin-top: 15px;
}
}

@ -9,10 +9,12 @@ import './index.scss';
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import SplitPane from 'react-split-pane';// import { Form } from 'antd'; import SplitPane from 'react-split-pane';// import { Form } from 'antd';
import { Button, Icon } from 'antd'; import { Button } from 'antd';
import { Link } from 'react-router-dom';
import LeftPane from './leftpane'; import LeftPane from './leftpane';
import RightPane from './rightpane'; import RightPane from './rightpane';
import { withRouter } from 'react-router';
import { toStore } from 'educoder';
import UserInfo from '../components/userInfo';
// import RightPane from './rightpane/index'; // import RightPane from './rightpane/index';
import actions from '../../../redux/actions'; import actions from '../../../redux/actions';
@ -22,10 +24,15 @@ const NewOrEditTask = (props) => {
handlePublish, handlePublish,
// testCases = [], // testCases = [],
// ojTestCaseValidate = [], // ojTestCaseValidate = [],
// changeSubmitLoadingStatus, identifier,
isPublish,
userInfo,
submitLoading,
changeSubmitLoadingStatus,
changePublishLoadingStatus, changePublishLoadingStatus,
startProgramQuestion,
getUserInfoForNew,
// updateTestAndValidate, // updateTestAndValidate,
identifier,
} = props; } = props;
// 表单提交 // 表单提交
@ -34,12 +41,15 @@ const NewOrEditTask = (props) => {
if (props.identifier) { if (props.identifier) {
props.handleUpdateOjForm(props); props.handleUpdateOjForm(props);
} else { } else {
// 改变loading状态
changeSubmitLoadingStatus(true);
props.handleFormSubmit(props); // 提交表单 props.handleFormSubmit(props); // 提交表单
} }
}; };
useEffect(() => { useEffect(() => {
// 获取用户信息
getUserInfoForNew();
// console.log('获取路由参数: ====', props.match.params); // console.log('获取路由参数: ====', props.match.params);
const id = props.match.params.id; const id = props.match.params.id;
// 保存OJForm的id号指明是编辑还是新增 // 保存OJForm的id号指明是编辑还是新增
@ -55,25 +65,101 @@ const NewOrEditTask = (props) => {
return () => {} return () => {}
}, []); }, []);
// 模拟挑战
const startChallenge = () => {
// 调用 start 接口, 成功后跳转到模拟页面
startProgramQuestion(identifier, props);
}
// 取消
const handleClickCancel = () => {
// 清空当前输入值并跳转至列表页
props.clearOJFormStore();
// 清空描述信息
toStore('oj_description', '');
setInterval(function () {
props.history.push('/problems');
}, 500);
}
// 发布
const handleClickPublish = () => { const handleClickPublish = () => {
// console.log('public has click'); // console.log('public has click');
changePublishLoadingStatus(true); changePublishLoadingStatus(true);
handlePublish(props, 'publish'); handlePublish(props, 'publish');
} }
// 取消保存/取消按钮
const renderSaveOrCancel = () => {
return (
<React.Fragment>
<Button
onClick={handleClickCancel}
style={{ background: '#666666', color: '#fff', border: 'none' }}
>取消</Button>
<Button
type="primary"
loading={submitLoading}
onClick={handleSubmitForm}
>保存</Button>
</React.Fragment>
);
}
// 发布/模拟挑战
const renderPubOrFight = () => {
const pubButton = isPublish ? '' : (<Button
type="primary"
loading={publishLoading}
onClick={handleClickPublish}
>立即发布</Button>);
return (
<React.Fragment>
<Button
type="primary"
loading={submitLoading}
onClick={handleSubmitForm}
>更新</Button>
{pubButton}
<Button type="primary" onClick={startChallenge}>模拟挑战</Button>
</React.Fragment>
)
}
// 渲染退出
const renderQuit = () => {
return identifier ? (
<Button type="link"
style={{
position: 'absolute',
right: '10px',
top: '15px',
color: '#5091FF'
}}
onClick={handleClickCancel}
>退出</Button>
) : ''
}
return ( return (
<div className={'new_add_task_wrap'}> <div className={'new_add_task_wrap'}>
<div className={'task_header'}> <div className={'task_header'}>
<Link to="/problems" className={'header_btn'} > {/* <Link to="/problems" className={'header_btn'} >
<Icon type="left" style={{ marginRight: '5px'}}/>后退 <Icon type="left" style={{ marginRight: '5px'}}/>后退
</Link> </Link> */}
<UserInfo userInfo={userInfo}/>
<p className={'header_title'}>{props.name || ''}</p> <p className={'header_title'}>{props.name || ''}</p>
<Button { renderQuit() }
{/* <Link style={{
position: 'absolute',
right: '30px',
top: 0,
color: '#5091FF'
}} to="/problems">退出</Link> */}
{/* <Button
style={{ display: identifier ? 'none' : 'block'}} style={{ display: identifier ? 'none' : 'block'}}
loading={publishLoading} loading={publishLoading}
className={`header_btn`} className={`header_btn`}
type="primary" type="primary"
onClick={handleClickPublish}>立即发布</Button> onClick={handleClickPublish}>立即发布</Button> */}
</div> </div>
<div className="split-pane-area"> <div className="split-pane-area">
<SplitPane split="vertical" minSize={350} maxSize={-350} defaultSize="40%"> <SplitPane split="vertical" minSize={350} maxSize={-350} defaultSize="40%">
@ -86,18 +172,30 @@ const NewOrEditTask = (props) => {
</SplitPane> </SplitPane>
</SplitPane> </SplitPane>
</div> </div>
{/* 控制台 */}
<div className='new_add_task_ctl'>
{
/* 录入时: 取消 保存 */
/* 保存未发布: 立即发布 模拟挑战 */
}
{ !identifier ? renderSaveOrCancel() : renderPubOrFight() }
</div>
</div> </div>
) )
} }
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
const { ojForm, identifier, testCases } = state.ojFormReducer; const { ojForm, identifier, testCases, isPublish } = state.ojFormReducer;
const { publishLoading } = state.commonReducer; const { publishLoading, submitLoading } = state.commonReducer;
const { userInfo } = state.userReducer;
return { return {
name: ojForm.name, name: ojForm.name,
identifier, identifier,
testCases, testCases,
publishLoading isPublish, // 是否已发布
publishLoading,
submitLoading,
userInfo
} }
}; };
@ -122,9 +220,13 @@ const mapDispatchToProps = (dispatch) => ({
changePublishLoadingStatus: (flag) => dispatch(actions.changePublishLoadingStatus(flag)), changePublishLoadingStatus: (flag) => dispatch(actions.changePublishLoadingStatus(flag)),
// 测试用例及验证 // 测试用例及验证
updateTestAndValidate: (obj) => dispatch(actions.updateTestAndValidate(obj)), updateTestAndValidate: (obj) => dispatch(actions.updateTestAndValidate(obj)),
// 开启模拟挑战
startProgramQuestion: (id, props) => dispatch(actions.startProgramQuestion(id, props)),
// 新建时获取信息
getUserInfoForNew: () => dispatch(actions.getUserInfoForNew())
}); });
export default connect( export default withRouter(connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps
)(NewOrEditTask); )(NewOrEditTask));

@ -1,2 +1,18 @@
@import '../split_pane_resizer.scss'; @import '../split_pane_resizer.scss';
.new_add_task_wrap {
.split-pane-area{
height: calc(100vh - 121px);
}
}
.new_add_task_ctl{
display: flex;
align-items: center;
justify-content: center;
height: 56px;
background: #333333;
> button{
margin-right: 20px;
}
}

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-21 09:19:38 * @Date: 2019-11-21 09:19:38
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-04 15:44:12 * @LastEditTime: 2019-12-10 19:37:35
*/ */
import './index.scss'; import './index.scss';
import React, { useState } from 'react'; import React, { useState } from 'react';
@ -16,7 +16,7 @@ const { TextArea } = Input;
const FormItem = Form.Item; const FormItem = Form.Item;
const AddTestDemo = (props) => { const AddTestDemo = (props) => {
const { const {
key, // key,
onSubmitTest, onSubmitTest,
onDeleteTest, onDeleteTest,
testCase, testCase,
@ -158,7 +158,8 @@ const AddTestDemo = (props) => {
help={testCaseValidate.output.errMsg} help={testCaseValidate.output.errMsg}
colon={ false } colon={ false }
> >
<Input <TextArea
rows={5}
value={testCase.output} value={testCase.output}
onChange={handleOutputChange} onChange={handleOutputChange}
disabled={isDisabled(testCase)}/> disabled={isDisabled(testCase)}/>

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-20 10:35:40 * @Date: 2019-11-20 10:35:40
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 20:20:27 * @LastEditTime: 2019-12-09 10:22:03
*/ */
import 'quill/dist/quill.core.css'; import 'quill/dist/quill.core.css';
import 'quill/dist/quill.bubble.css'; import 'quill/dist/quill.bubble.css';
@ -236,22 +236,41 @@ class EditTab extends React.Component {
<div className={'editor_area'} id="textCase"> <div className={'editor_area'} id="textCase">
<Form className={'editor_form'}> <Form className={'editor_form'}>
<FormItem <FormItem
className={`input_area flex_60`} className={`input_area flex_50 flex_50_left`}
label={<span>{myLabel(jcLabel['name'])}</span>} label={<span>{myLabel(jcLabel['difficult'])}</span>}
validateStatus={ojFormValidate.name.validateStatus} validateStatus={ojFormValidate.difficult.validateStatus}
help={ojFormValidate.name.errMsg} help={ojFormValidate.difficult.errMsg}
colon={ false } colon={ false }
> >
<Input <Select onChange={this.handleChangeDifficult} value={`${ojForm.difficult}`}>
maxLength={60} {getOptions('difficult')}
placeholder="请输入任务名称" </Select>
value={ojForm.name} </FormItem>
suffix={<span style={{ fontSize: '12px', color: 'rgba(0, 0, 0, 0.45)' }}>{60 - ojForm.name.length}</span>}
onChange={this.handleNameChange} <FormItem
/> className={`input_area flex_50 flex_50_right`}
label={<span>{myLabel(jcLabel['category'], '合理的分类有利于快速检索')}</span>}
validateStatus={ojFormValidate.category.validateStatus}
help={ojFormValidate.category.errMsg}
colon={ false }
>
<Select onChange={this.handleChangeCategory} value={`${ojForm.category}`}>
{getOptions('category')}
</Select>
</FormItem>
<FormItem
className={`input_area flex_50 flex_50_left`}
label={<span>{myLabel(jcLabel['timeLimit'], '程序允许时间限制时长,单位:秒')}</span>}
validateStatus={ojFormValidate.timeLimit.validateStatus}
help={ojFormValidate.timeLimit.errMsg}
colon={ false }
>
<InputNumber value={ojForm.timeLimit} min={0} style={{ width: '100%' }} onChange={this.handleTimeLimitChange}/>
</FormItem> </FormItem>
<FormItem <FormItem
className={`input_area flex_40`} className={`input_area flex_50 flex_50_right`}
label={<span>{myLabel(jcLabel['language'])}</span>} label={<span>{myLabel(jcLabel['language'])}</span>}
validateStatus={ojFormValidate.language.validateStatus} validateStatus={ojFormValidate.language.validateStatus}
help={ojFormValidate.language.errMsg} help={ojFormValidate.language.errMsg}
@ -261,6 +280,23 @@ class EditTab extends React.Component {
{getOptions('language')} {getOptions('language')}
</Select> </Select>
</FormItem> </FormItem>
<FormItem
className={`input_area flex_100`}
label={<span>{myLabel(jcLabel['name'])}</span>}
validateStatus={ojFormValidate.name.validateStatus}
help={ojFormValidate.name.errMsg}
colon={ false }
>
<Input
maxLength={60}
placeholder="请输入任务名称"
value={ojForm.name}
suffix={<span style={{ fontSize: '12px', color: 'rgba(0, 0, 0, 0.45)' }}>{60 - ojForm.name.length}</span>}
onChange={this.handleNameChange}
/>
</FormItem>
<FormItem <FormItem
className={`input_area flex_100`} className={`input_area flex_100`}
label={<span>{myLabel(jcLabel['description'])}</span>} label={<span>{myLabel(jcLabel['description'])}</span>}
@ -276,38 +312,8 @@ class EditTab extends React.Component {
options={quillConfig} options={quillConfig}
/> />
</FormItem> </FormItem>
<FormItem
className={`input_area flex_50 flex_50_left`} {/* <FormItem
label={<span>{myLabel(jcLabel['difficult'], '任务的难易程度')}</span>}
validateStatus={ojFormValidate.difficult.validateStatus}
help={ojFormValidate.difficult.errMsg}
colon={ false }
>
<Select onChange={this.handleChangeDifficult} value={`${ojForm.difficult}`}>
{getOptions('difficult')}
</Select>
</FormItem>
<FormItem
className={`input_area flex_50 flex_50_right`}
label={<span>{myLabel(jcLabel['timeLimit'], '程序允许时间限制时长,单位:秒')}</span>}
validateStatus={ojFormValidate.timeLimit.validateStatus}
help={ojFormValidate.timeLimit.errMsg}
colon={ false }
>
<InputNumber value={ojForm.timeLimit} min={0} style={{ width: '100%' }} onChange={this.handleTimeLimitChange}/>
</FormItem>
<FormItem
className={`input_area flex_50 flex_50_left`}
label={<span>{myLabel(jcLabel['category'], '任务所属分类')}</span>}
validateStatus={ojFormValidate.category.validateStatus}
help={ojFormValidate.category.errMsg}
colon={ false }
>
<Select onChange={this.handleChangeCategory} value={`${ojForm.category}`}>
{getOptions('category')}
</Select>
</FormItem>
<FormItem
className={`input_area flex_50 flex_50_right`} className={`input_area flex_50 flex_50_right`}
label={<span>{myLabel(jcLabel['openOrNot'], '社区:您的任务将向整个社会公开')}</span>} label={<span>{myLabel(jcLabel['openOrNot'], '社区:您的任务将向整个社会公开')}</span>}
validateStatus={ojFormValidate.openOrNot.validateStatus} validateStatus={ojFormValidate.openOrNot.validateStatus}
@ -317,13 +323,13 @@ class EditTab extends React.Component {
<Select onChange={this.handleChangeOpenOrNot} value={`${ojForm.openOrNot}`}> <Select onChange={this.handleChangeOpenOrNot} value={`${ojForm.openOrNot}`}>
{getOptions('openOrNot')} {getOptions('openOrNot')}
</Select> </Select>
</FormItem> </FormItem> */}
</Form> </Form>
{/* 添加测试用例 */} {/* 添加测试用例 */}
<div className={'test_demo_title'} ref={this.headerRef}> <div className={'test_demo_title'} ref={this.headerRef}>
<h2>测试用例</h2> <h2>测试用例</h2>
<Button type="primary" onClick={handleAddTest}>添加测试用例</Button> <Button type="primary" ghost onClick={handleAddTest}>添加测试用例</Button>
</div> </div>
<div className="test_demo_ctx"> <div className="test_demo_ctx">
{ renderTestCase() } { renderTestCase() }

@ -7,44 +7,84 @@
*/ */
import './index.scss'; import './index.scss';
import React, { useState } from 'react'; import React, { useState, useMemo } from 'react';
import { Tabs } from 'antd'; // import { Tabs } from 'antd';
import EditorTab from './editorTab'; import EditorTab from './editorTab';
import PrevTab from './prevTab'; import PrevTab from './prevTab';
import CommitTab from './commitTab'; import CommitTab from './commitTab';
const { TabPane } = Tabs; // const { TabPane } = Tabs;
function LeftPane (props) { function LeftPane (props) {
const navItem = [
{
title: '编辑',
key: 'editor'
}, {
title: '预览',
key: 'prev'
}
];
const Comp = {
editor: (<EditorTab />),
prev: (<PrevTab />)
};
const [defaultActiveKey, setDefaultActiveKey] = useState('editor'); const [defaultActiveKey, setDefaultActiveKey] = useState('editor');
const tabArrs = [ // const tabArrs = [
{ title: '编辑', key: 'editor', content: (<EditorTab />) }, // { title: '编辑', key: 'editor', content: (<EditorTab />) },
{ title: '预览', key: 'prev', content: (<PrevTab />) }, // { title: '预览', key: 'prev', content: (<PrevTab />) },
// { title: '提交记录', key: 'commit', content: (<CommitTab />) }, // // { title: '提交记录', key: 'commit', content: (<CommitTab />) },
]; // ];
const tabs = tabArrs.map((tab) => { // const tabs = tabArrs.map((tab) => {
const Comp = tab.content; // const Comp = tab.content;
return ( // return (
<TabPane tab={tab.title} key={tab.key}> // <TabPane tab={tab.title} key={tab.key}>
{ Comp } // { Comp }
</TabPane> // </TabPane>
) // )
}); // });
// tab切换时 // tab切换时
const handleTabChange = (key) => { // const handleTabChange = (key) => {
setDefaultActiveKey(key); // setDefaultActiveKey(key);
} // }
// 执行表单提交函数 // 执行表单提交函数
const renderComp = useMemo(() => {
return Comp[defaultActiveKey];
}, [defaultActiveKey]);
const renderNavItem = navItem.map((item) => {
const _classes = item.key === defaultActiveKey ? 'add_editor_item active' : 'add_editor_item';
return (
<li
key={item.key}
className={_classes}
onClick={() => setDefaultActiveKey(item.key)}
>
<span className={'item-span'}>{item.title}</span>
</li>
)
});
return ( return (
<Tabs activeKey={defaultActiveKey} onChange={handleTabChange}> // <Tabs activeKey={defaultActiveKey} onChange={handleTabChange}>
{ tabs } // { tabs }
</Tabs> // </Tabs>
<React.Fragment>
<ul className={'add_editor_list_area'}>
{ renderNavItem }
</ul>
<div className="comp_ctx">
{ renderComp }
</div>
</React.Fragment>
) )
}; };

@ -4,21 +4,21 @@
* @Github: * @Github:
* @Date: 2019-12-01 10:18:35 * @Date: 2019-12-01 10:18:35
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 17:50:58 * @LastEditTime: 2019-12-09 11:38:15
*/ */
import './index.scss'; import './index.scss';
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import MyMonacoEditor from '../../components/myMonacoEditor'; import MyMonacoEditor from '../../components/myMonacoEditor';
import ControlSetting from '../../components/controlSetting'; // import ControlSetting from '../../components/controlSetting';
import actions from '../../../../redux/actions'; import actions from '../../../../redux/actions';
function RightPane (props, ref) { function RightPane (props, ref) {
const { const {
// identifier, // identifier,
code, // code,
onSubmitForm, // onSubmitForm,
saveOjFormCode saveOjFormCode
} = props; } = props;
@ -48,12 +48,12 @@ function RightPane (props, ref) {
code={props.code} code={props.code}
onCodeChange={handleCodeChange}/> onCodeChange={handleCodeChange}/>
<ControlSetting {/* <ControlSetting
// identifier={identifier} // identifier={identifier}
inputValue={props.input} inputValue={props.input}
onSubmitForm={onSubmitForm} onSubmitForm={onSubmitForm}
// onDebuggerCode={handleDebuggerCode} // onDebuggerCode={handleDebuggerCode}
/> /> */}
</div> </div>
) )
} }

@ -3,7 +3,7 @@
// justify-content: center; // justify-content: center;
background-color: #222; background-color: #222;
height: 100%; height: 100%;
// justify-content: ; // height: calc(100vh - 178px);
.code-title, .code-title,
.controller-pane, .controller-pane,
.pane_control_opts{ .pane_control_opts{

@ -1,215 +0,0 @@
/*
* @Description: 右侧代码块
* @Author: tangjiang
* @Date: 2019-11-18 08:42:04
* @Last Modified by: tangjiang
* @Last Modified time: 2019-11-20 00:00:34
*/
import './index.scss';
import React, { Fragment, useState, useRef, useEffect } from 'react';
import { Icon, Drawer, Tabs, Button, notification } from 'antd';
import _ from 'lodash';
import MonacoEditor from '@monaco-editor/react';
import { connect } from 'react-redux';
import InitTabCtx from './initTabCtx';
import SettingDrawer from '../../components/monacoSetting';
import CONST from '../../../../constants';
import actions from '../../../../redux/actions';
const { fontSetting, opacitySetting } = CONST;
const { TabPane } = Tabs;
const RightPaneCode = (props) => {
const [showDrawer, setShowDrawer] = useState(false); // 控制配置滑框
const [defaultActiveKey, setDefaultActiveKey] = useState('1'); // 当前选中的tab
const [showTextResult, setShowTextResult] = useState(false); // 是否点击控制台按钮
const [editCode, setEditCode] = useState(()=> {
return '#include <stdio.h>';
}); // monaco编辑器内容
const [language, setLanguage] = useState('C')
const [fontSize,setFontSize] = useState(12);
const editorRef = useRef(null); // 编辑器ref
useEffect(() => {
if (props.language) {
// console.log('当前输入的代码:', editCode);
// console.log('当前输入的语言:', props.language);
setLanguage(props.language)
}
}, [props.language]);
useEffect(() => {
}, [props.testCases]);
useEffect(() => {
}, [editCode]);
// 监听store中编辑器内容变化
useEffect(() => {
setEditCode(props.code);
}, [props.code]);
// 打开设置
const handleShowDrawer = (e) => {
e.preventDefault();
setShowDrawer(true);
}
// 关闭设置
const handleDrawerClose = (e) => {
e.preventDefault();
setShowDrawer(false);
}
// 切换tab
const handleTabChange = (key) => {
setDefaultActiveKey(key);
}
// 显示/隐藏tab
const handleShowControl = () => {
setShowTextResult(!showTextResult);
}
// 侧边栏改变字体大小
const handleFontSizeChange = (value) => {
setFontSize(value);
}
// 文本框内容变化时,记录文本框内容
const handleEditorChange = (origin, monaco) => {
editorRef.current = monaco; // 获取当前monaco实例
setEditCode(origin); // 保存编辑器初始值
editorRef.current.onDidChangeModelContent(e => { // 监听编辑器内容的变化
// TODO 需要优化 节流
const val = editorRef.current.getValue();
setEditCode(val);
// 保存当前代码
props.saveOjFormCode(val);
});
}
// 提交按钮点击
const handleSubmit = (e) => {
e.preventDefault();
if (!editCode) {
notification['error']({
message: '必填',
description: '代码块内容必须输入!'
});
editorRef.current.focus();
return;
}
props.changePublishLoadingStatus(true);
const { onSubmitForm } = props;
onSubmitForm(editCode);
}
// 调试测试代码
// const handleTestCode = () => {
// // 打开控制台信息
// setShowTextResult(true);
// this.formRef.handleTestCodeFormSubmit(() => {
// // 当验证通过后 切换tab 到代码执行结果
// setDefaultActiveKey('2');
// });
// }
// 控制台点击时 添加active属性
const classNames = `control_tab ${showTextResult ? 'move_up move_up_final' : 'move_down_final'}`;
// 配置编辑器属性
const editorOptions = {
selectOnLineNumbers: true,
automaticLayout: true,
fontSize: `${fontSize}px`
}
// 返回渲染值
return (
<Fragment>
<div className={'right_pane_code_wrap'}>
<div className={'code-title'}>
<span></span>
<Icon className={'code-icon'} type="setting" onClick={handleShowDrawer}/>
</div>
{/** 代码编辑器 */}
<MonacoEditor
height={showTextResult ? 'calc(100% - 382px)' : 'calc(100% - 112px)'}
width="100%"
language={language.toLowerCase()}
value={editCode}
options={editorOptions}
theme="dark"
editorDidMount={handleEditorChange}
/>
{/* 控制台信息 */}
<div className="pane_control_area">
<Tabs
className={classNames}
activeKey={defaultActiveKey}
tabBarStyle={{ backgroundColor: '#000', color: '#fff' }}
onChange={handleTabChange}
>
<TabPane tab={'自定义测试用例'} key={'1'} style={{ height: '280px', overflowY: 'auto' }}>
<InitTabCtx wrappedComponentRef={(form) => this.formRef = form }/>
</TabPane>
<TabPane tab={'代码执行结果'} key={'2'} style={{ height: '280px', overflowY: 'auto' }}>
<h2>代码执行结果</h2>
</TabPane>
</Tabs>
<div className="pane_control_opts">
<Button type="link" style={{ color: '#fff' }} onClick={handleShowControl}>控制台 <Icon type={ showTextResult ? "down" : "up" } /></Button>
<p>
{/* <Button ghost
style={{ marginRight: '10px', color: '#28BD8B', borderColor: '#28BD8B' }}
onClick={handleTestCode}
disabled={!props.identifier || props.testCases.length === 0}
>调试代码</Button> */}
<Button
loading={props.submitLoading}
type="primary"
onClick={handleSubmit}
>{props.identifier ? '更新' : '提交'}</Button>
</p>
</div>
</div>
</div>
<Drawer
className={'setting_drawer'}
placement="right"
closable={false}
onClose={handleDrawerClose}
visible={showDrawer}
>
<SettingDrawer {...fontSetting} onChangeFontSize={handleFontSizeChange}/>
<SettingDrawer {...opacitySetting}/>
</Drawer>
</Fragment>
);
}
const mapStateToProps = (state) => {
const { ojForm, testCases, identifier, code } = state.ojFormReducer;
const { submitLoading } = state.commonReducer;
return {
language: ojForm.language,
testCases,
identifier,
code,
submitLoading
}
};
const mapDispatchToProps = (dispatch) => ({
saveOjFormCode: (code) => dispatch(actions.saveOjFormCode(code)),
changePublishLoadingStatus: (flag) => dispatch(actions.changeSubmitLoadingStatus(flag))
});
//
export default connect(
mapStateToProps,
mapDispatchToProps
)(RightPaneCode);

@ -4,13 +4,14 @@
* @Github: * @Github:
* @Date: 2019-11-25 09:46:03 * @Date: 2019-11-25 09:46:03
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-04 23:09:38 * @LastEditTime: 2019-12-10 16:10:23
*/ */
// import 'quill/dist/quill.core.css'; // import 'quill/dist/quill.core.css';
// import 'quill/dist/quill.bubble.css'; // import 'quill/dist/quill.bubble.css';
// import 'quill/dist/quill.snow.css'; // import 'quill/dist/quill.snow.css';
// import 'katex/dist/katex.css'; // import 'katex/dist/katex.css';
import './index.scss'; import './index.scss';
import 'katex/dist/katex.min.css';
import React from 'react'; import React from 'react';
import katex from 'katex'; import katex from 'katex';
const Quill = require('quill'); const Quill = require('quill');
@ -120,15 +121,12 @@ class QuillEditor extends React.Component {
render () { render () {
const styles = this.props.style || {} const styles = this.props.style || {}
return ( return (
<div> <div
<div id="quill_editor"
id="quill_editor" style={styles}
style={styles} className={'quill_editor_area'}
className={'quill_editor_area'} ref={this.editorRef}>
ref={this.editorRef}>
</div>
</div> </div>
); );
} }
} }

@ -1,4 +0,0 @@
.quill_editor_area{
height: 300px;
overflow-y: auto;
}

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-12-04 08:36:21 * @Date: 2019-12-04 08:36:21
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-05 13:52:04 * @LastEditTime: 2019-12-10 18:55:02
*/ */
import './index.scss'; import './index.scss';
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
@ -14,23 +14,26 @@ import ErrorResult from '../components/errorResult';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import MonacoEditor from '@monaco-editor/react'; import MonacoEditor from '@monaco-editor/react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { getImageUrl } from 'educoder'; // import { getImageUrl } from 'educoder';
import actions from '../../../redux/actions'; import actions from '../../../redux/actions';
import CONST from '../../../constants'; import CONST from '../../../constants';
import UserInfo from '../components/userInfo';
const {reviewResult} = CONST; const {reviewResult} = CONST;
function RecordDetail (props) { function RecordDetail (props) {
const { const {
match: { params }, match: { params },
mygetHelmetapi = {},
recordDetail, recordDetail,
identifier, // identifier,
getUserCommitRecordDetail getUserCommitRecordDetail,
saveEditorCodeForDetail
} = props; } = props;
const id = params.id; const id = params.id;
const [detail, setDetail] = useState({}); const [detail, setDetail] = useState({});
const [user, setUser] = useState({});
const [identifier, setIdentifier] = useState('');
useEffect(() => { useEffect(() => {
// 根据id获取记录详情 // 根据id获取记录详情
@ -40,17 +43,27 @@ function RecordDetail (props) {
useEffect(() => { useEffect(() => {
setDetail(recordDetail); setDetail(recordDetail);
console.log('详情: ', recordDetail);
if (recordDetail) {
const { user, myproblem_identifier, code } = recordDetail;
setUser(user);
setIdentifier(myproblem_identifier);
if (code) {
saveEditorCodeForDetail(code);
}
}
}, [recordDetail]); }, [recordDetail]);
return ( return (
<div className="record_detail_area"> <div className="record_detail_area">
<div className="record_detail_header"> <div className="record_detail_header">
<div className="avator_nicker"> {/* <div className="avator_nicker">
<img alt="用户头像" className={'student_img'} src={getImageUrl((mygetHelmetapi && mygetHelmetapi.nav_logo_url) || 'images/educoder/headNavLogo.png?1526520218')} /> <img alt="用户头像" className={'student_img'} src={getImageUrl( (user && `images/${user.image_url}`)|| 'images/educoder/headNavLogo.png?1526520218')} />
<span className={'student_nicker'}> <span className={'student_nicker'}>
{(mygetHelmetapi &&mygetHelmetapi.name) || ''} {(user && user.name) || ''}
</span> </span>
</div> </div> */}
<UserInfo userInfo={user || {}}/>
<div className={'study_name'}> <div className={'study_name'}>
<span>{detail.name || 'test'}</span> <span>{detail.name || 'test'}</span>
</div> </div>
@ -82,7 +95,13 @@ function RecordDetail (props) {
</div> </div>
<div className="detail_ctx_header"> <div className="detail_ctx_header">
<h2 className="header_h2">提交内容</h2> <h2 className="header_h2">提交内容</h2>
<Button className={'header_btn'} type="primary">编辑代码</Button> <Button
className={'header_btn'}
type="primary"
>
{/* 编辑代码 */}
<Link to={`/myproblems/${identifier}`}>编辑代码</Link>
</Button>
</div> </div>
<div className="result_code_area"> <div className="result_code_area">
<MonacoEditor <MonacoEditor
@ -100,15 +119,16 @@ function RecordDetail (props) {
} }
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
const {recordDetail, user_program_identifier} = state.ojForUserReducer; const {recordDetail} = state.ojForUserReducer;
return { return {
identifier: user_program_identifier, // identifier: user_program_identifier,
recordDetail recordDetail
} }
} }
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
// 根据id号获取记录详情 // 根据id号获取记录详情
getUserCommitRecordDetail: (id, type) => dispatch(actions.getUserCommitRecordDetail(id, type)) getUserCommitRecordDetail: (id, type) => dispatch(actions.getUserCommitRecordDetail(id, type)),
saveEditorCodeForDetail: (code) => dispatch(actions.saveEditorCodeForDetail(code))
}); });
export default connect( export default connect(

@ -7,7 +7,8 @@
.student_study_header, .student_study_header,
.record_detail_header{ .record_detail_header{
height: 65px; height: 65px;
background:rgba(34,34,34,1); // background:rgba(34,34,34,1);
background: #1E1E1E;
padding:0 30px; padding:0 30px;
} }
@ -45,11 +46,6 @@
.pane_right_area .pane_right_area
{ {
position: relative; position: relative;
height: calc(100% - 65px);
.left_pane,
.right_pane{
height: 100%;
}
} }
.student_study_header, .student_study_header,
@ -89,6 +85,41 @@
} }
} }
.add_editor_list_area{
background: #fff;
padding: 0 30px;
margin: 0;
.add_editor_item{
display: inline-block;
height: 56px;
line-height: 56px;
box-sizing: border-box;
margin-right: 30px;
border-bottom: 2px solid transparent;
transition: all .3s;
cursor: pointer;
.item-span{
color: #666;
font-size: 16px;
}
// > span{
// cursor: pointer;
// }
&.active{
border-bottom-color: #5091FF;
.item-span{
color: #5091FF;
}
}
}
}
.comp_ctx{
height: calc(100vh - 178px);
overflow-y: hidden;
}
.split-pane-area, .split-pane-area,
.split-pane-left{ .split-pane-left{
.ant-tabs-nav-wrap{ .ant-tabs-nav-wrap{
@ -109,9 +140,8 @@
.editor_area, .editor_area,
.prev_area{ .prev_area{
height: calc(100vh - 110px); height: 100%;
overflow-y: auto; overflow-y: auto;
// padding: 20px 0;
} }
} }

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-23 10:53:19 * @Date: 2019-11-23 10:53:19
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 18:59:22 * @LastEditTime: 2019-12-10 19:16:18
*/ */
import './index.scss'; import './index.scss';
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
@ -12,22 +12,26 @@ import { connect } from 'react-redux';
import SplitPane from 'react-split-pane'; import SplitPane from 'react-split-pane';
import LeftPane from './leftpane'; import LeftPane from './leftpane';
import RightPane from './rightpane'; import RightPane from './rightpane';
import { Link } from 'react-router-dom'; // import { Link } from 'react-router-dom';
import { getImageUrl } from 'educoder' // import { getImageUrl } from 'educoder'
// import RightPane from '../newOrEditTask/rightpane'; // import RightPane from '../newOrEditTask/rightpane';
import { Button } from 'antd'; import { Icon } from 'antd';
import UserInfo from '../components/userInfo';
import actions from '../../../redux/actions'; import actions from '../../../redux/actions';
import { fromStore} from 'educoder';
import { withRouter } from 'react-router';
const StudentStudy = (props) => { const StudentStudy = (props) => {
const { const {
mygetHelmetapi = {} userInfo,
hack_identifier
} = props; } = props;
useEffect(() => { useEffect(() => {
const { const {
match: { params }, match: { params },
getUserProgramDetail, getUserProgramDetail,
saveUserProgramIdentifier, saveUserProgramIdentifier
} = props; } = props;
let { id } = params; let { id } = params;
@ -37,22 +41,48 @@ const StudentStudy = (props) => {
// startProgramQuestion(id); // startProgramQuestion(id);
getUserProgramDetail(id); getUserProgramDetail(id);
}, []); }, []);
const _hack_id = hack_identifier || fromStore('hack_identifier');
// 处理编辑
const handleClickEditor = () => {
props.saveEditorCodeForDetail();
props.history.push(`/problems/${_hack_id}/edit`);
}
// 处理退出
const handleClickQuit = () => {
props.saveEditorCodeForDetail();
props.history.push('/problems');
}
return ( return (
<div className={'student_study_warp'}> <div className={'student_study_warp'}>
<div className={'student_study_header'}> <div className={'student_study_header'}>
<div className={'avator_nicker'}> {/* <div className={'avator_nicker'}>
<img alt="用户头像" className={'student_img'} src={getImageUrl((mygetHelmetapi && mygetHelmetapi.nav_logo_url) || 'images/educoder/headNavLogo.png?1526520218')} /> <img alt="用户头像" className={'student_img'} src={getImageUrl((mygetHelmetapi && mygetHelmetapi.nav_logo_url) || 'images/educoder/headNavLogo.png?1526520218')} />
<span className={'student_nicker'}> <span className={'student_nicker'}>
{(mygetHelmetapi &&mygetHelmetapi.name) || ''} {(mygetHelmetapi &&mygetHelmetapi.name) || ''}
</span> </span>
</div> </div> */}
<UserInfo userInfo={userInfo}/>
<div className={'study_name'}> <div className={'study_name'}>
<span>乘积最大序列</span> <span>乘积最大序列</span>
</div> </div>
<div className={'study_quit'}> <div className={'study_quit'}>
<Button> {/* to={`/problems/${_hack_id}/edit`} */}
<Link to="/problems">退出</Link> <span onClick={handleClickEditor} className="quit-btn">
<Icon type="form" className="quit-icon"/> 编辑
</span>
{/* to="/problems" */}
<span onClick={handleClickQuit} className="quit-btn">
<Icon type="poweroff" className="quit-icon"/> 退出
</span>
{/* <Button type="link" icon="form" className='quit-btn'>
<Link to="/problems">编辑</Link>
</Button> </Button>
<Button type="link" icon="poweroff" className='quit-btn'>
<Link to="/problems">退出</Link>
</Button> */}
</div> </div>
</div> </div>
<div className="split-pane-area"> <div className="split-pane-area">
@ -70,19 +100,27 @@ const StudentStudy = (props) => {
) )
} }
const mapStateToProps = (state) => ({}); const mapStateToProps = (state) => {
const { userInfo } = state.userReducer;
const { hack_identifier } = state.ojForUserReducer;
return {
userInfo,
hack_identifier
};
};
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
// 调用开启编辑 // 调用开启编辑
// startProgramQuestion: (id) => dispatch(actions.startProgramQuestion(id)) // startProgramQuestion: (id) => dispatch(actions.startProgramQuestion(id))
// 调用编程题详情 // 调用编程题详情
getUserProgramDetail: (id) => dispatch(actions.getUserProgramDetail(id)), getUserProgramDetail: (id) => dispatch(actions.getUserProgramDetail(id)),
saveUserProgramIdentifier: (id) => dispatch(actions.saveUserProgramIdentifier(id)) saveUserProgramIdentifier: (id) => dispatch(actions.saveUserProgramIdentifier(id)),
saveEditorCodeForDetail: (code) => dispatch(actions.saveEditorCodeForDetail(code))
}); });
export default connect( export default withRouter(connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps
)(StudentStudy); )(StudentStudy));

@ -1,4 +1,7 @@
@import '../split_pane_resizer.scss'; @import '../split_pane_resizer.scss';
.split-pane-area{
height: calc(100vh - 65px);
}
.right_pane_code_wrap{ .right_pane_code_wrap{
position: relative; position: relative;

@ -1,5 +1,6 @@
.commit_record_area{ .commit_record_area{
padding: 20px 30px; // padding: 20px 30px;
padding: 0 30px;
.record_header{ .record_header{
display: flex; display: flex;
// justify-content: space-between; // justify-content: space-between;

@ -4,10 +4,10 @@
* @Github: * @Github:
* @Date: 2019-11-23 11:33:41 * @Date: 2019-11-23 11:33:41
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-03 14:13:19 * @LastEditTime: 2019-12-09 19:57:21
// */ // */
import './index.scss'; import './index.scss';
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect, useMemo } from 'react';
import { Tabs, Divider } from 'antd'; import { Tabs, Divider } from 'antd';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Comment from './comment'; import Comment from './comment';
@ -15,13 +15,14 @@ import CommitRecord from './commitRecord';
import TaskDescription from './taskDescription'; import TaskDescription from './taskDescription';
import TextNumber from './../../components/textNumber'; import TextNumber from './../../components/textNumber';
import actions from '../../../../redux/actions'; import actions from '../../../../redux/actions';
const { TabPane } = Tabs; // const { TabPane } = Tabs;
const LeftPane = (props) => { const LeftPane = (props) => {
const { hack, userCodeTab, changeUserCodeTab } = props; const { hack, userCodeTab, changeUserCodeTab } = props;
const { pass_count, submit_count } = hack; const { pass_count, submit_count } = hack;
const [defaultActiveKey, setDefaultActiveKey] = useState('task'); const [defaultActiveKey, setDefaultActiveKey] = useState('task');
console.log(pass_count, submit_count); console.log(pass_count, submit_count);
const tabArrs = [ const tabArrs = [
{ title: '任务描述', key: 'task', content: (<TaskDescription />) }, { title: '任务描述', key: 'task', content: (<TaskDescription />) },
@ -29,25 +30,58 @@ const LeftPane = (props) => {
// { title: '评论', key: 'comment', content: (<Comment />) }, // { title: '评论', key: 'comment', content: (<Comment />) },
]; ];
const navItem = [
{
title: '任务描述',
key: 'task'
},
{
title: '提交记录',
key: 'record'
}
];
const Comp = {
task: (<TaskDescription />),
record: (<CommitRecord />)
};
useEffect(() => { useEffect(() => {
setDefaultActiveKey(userCodeTab); setDefaultActiveKey(userCodeTab);
}, [userCodeTab]) }, [userCodeTab])
const tabs = tabArrs.map((tab) => { // const tabs = tabArrs.map((tab) => {
const Comp = tab.content; // const Comp = tab.content;
// return (
// <TabPane tab={tab.title} key={tab.key}>
// { Comp }
// </TabPane>
// )
// });
// // tab切换时
// const handleTabChange = (key) => {
// // setDefaultActiveKey(key);
// changeUserCodeTab(key);
// }
const renderComp = useMemo(() => {
return Comp[defaultActiveKey];
}, [defaultActiveKey]);
const renderNavItem = navItem.map((item) => {
const _classes = item.key === defaultActiveKey ? 'add_editor_item active' : 'add_editor_item';
return ( return (
<TabPane tab={tab.title} key={tab.key}> <li
{ Comp } key={item.key}
</TabPane> className={_classes}
onClick={() => setDefaultActiveKey(item.key)}
>
<span className={'item-span'}>{item.title}</span>
</li>
) )
}); });
// tab切换时
const handleTabChange = (key) => {
// setDefaultActiveKey(key);
changeUserCodeTab(key);
}
// 点击消息 // 点击消息
const handleClickMessage = () => { const handleClickMessage = () => {
console.log('点击的消息图标---------'); console.log('点击的消息图标---------');
@ -65,9 +99,27 @@ const LeftPane = (props) => {
return ( return (
<React.Fragment> <React.Fragment>
<Tabs className={'user_code_tab_area'} activeKey={defaultActiveKey} onChange={handleTabChange}> {/* <Tabs className={'user_code_tab_area'} activeKey={defaultActiveKey} onChange={handleTabChange}>
{ tabs } { tabs }
</Tabs> </Tabs>
<div className={'number_area'}>
<div className="number_flex flex_count">
<TextNumber text="通过次数" number={pass_count} position="vertical"/>
<Divider type="vertical" style={{ height: '20px', margin: '10px 20px' }}/>
<TextNumber text="提交次数" number={submit_count} position="vertical"/>
</div>
<div className="number_flex flex_info">
<TextNumber text="message" number={4235} type="icon" onIconClick={handleClickMessage}/>
<TextNumber text="like" number={4235} type="icon" onIconClick={handleClickLike}/>
<TextNumber text="dislike" type="icon" onIconClick={handleClickDisLike}/>
</div>
</div> */}
<ul className={'add_editor_list_area'}>
{ renderNavItem }
</ul>
<div className="comp_ctx">
{ renderComp }
</div>
<div className={'number_area'}> <div className={'number_area'}>
<div className="number_flex flex_count"> <div className="number_flex flex_count">
<TextNumber text="通过次数" number={pass_count} position="vertical"/> <TextNumber text="通过次数" number={pass_count} position="vertical"/>

@ -15,7 +15,8 @@
width: 100%; width: 100%;
// background: pink; // background: pink;
padding: 0 30px; padding: 0 30px;
background-color: rgba(250,250,250,1); // background-color: rgba(250,250,250,1);
background: #fff;
.flex_count, .flex_count,
.flex_info{ .flex_info{
@ -28,18 +29,23 @@
} }
} }
.task_description_area,
.commit_record_area{ .commit_record_area{
padding: 0 30px; padding: 0 30px;
height: calc(100vh - 166px); // height: calc(100vh - 178px);
overflow-y: auto; // overflow-y: auto;
} }
.task_description_area{ .task_description_area{
.task_desc_area{
height: calc(100vh - 242px);
padding: 0 0 0 15px;
}
.desc_area_header{ .desc_area_header{
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
height: 64px; height: 64px;
padding: 0 30px;
.header_flex{ .header_flex{
font-size: 14px; font-size: 14px;
.flex_label{ .flex_label{
@ -52,3 +58,25 @@
} }
} }
} }
.student_study_header{
.study_quit{
position: absolute;
right: 30px;
}
.quit-btn{
cursor: pointer;
margin-left: 30px;
color: #888888;
transition: all .3s;
&:hover{
color: #5091FF;
}
// &:last-child{
// color: #888888;
// }
.quit-icon{
margin-right: 5px;
}
}
}

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-27 09:49:30 * @Date: 2019-11-27 09:49:30
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-11-29 13:46:11 * @LastEditTime: 2019-12-09 19:21:55
*/ */
import '../index.scss'; import '../index.scss';
import React from 'react'; import React from 'react';
@ -39,12 +39,18 @@ const TaskDescription = (props) => {
<Link to="/" style={{ color: '#5091FF'}}>{username}</Link> <Link to="/" style={{ color: '#5091FF'}}>{username}</Link>
</p> </p>
</div> </div>
<QuillEditor <div className="task_desc_area">
<QuillEditor
htmlCtx={description}
readOnly={true}
/>
</div>
{/* <QuillEditor
htmlCtx={description} htmlCtx={description}
readOnly={true} readOnly={true}
options={[]} options={[]}
style={{ height: "calc(100% - 109px)" }} style={{ backgroundColor: 'gold' }}
/> /> */}
{/* <div dangerouslySetInnerHTML={{__html: description}}></div> */} {/* <div dangerouslySetInnerHTML={{__html: description}}></div> */}
</div> </div>
) )

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-27 14:59:51 * @Date: 2019-11-27 14:59:51
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 18:48:52 * @LastEditTime: 2019-12-10 19:00:30
*/ */
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
@ -21,6 +21,7 @@ const RightPane = (props) => {
input, input,
hack, hack,
updateCode, updateCode,
editor_code,
saveUserInputCode, saveUserInputCode,
restoreInitialCode, restoreInitialCode,
saveUserCodeForInterval saveUserCodeForInterval
@ -29,9 +30,12 @@ const RightPane = (props) => {
const [editorCode, setEditorCode] = useState(''); const [editorCode, setEditorCode] = useState('');
useEffect(() => { useEffect(() => {
console.log('1111111'); if (editor_code) {
setEditorCode(hack.code); setEditorCode(editor_code);
}, [hack]); } else {
setEditorCode(hack.code);
}
}, [hack, editor_code]);
const handleSubmitForm = () => { const handleSubmitForm = () => {
// 提交时, 先调用提交接口,提交成功后,循环调用测评接口 // 提交时, 先调用提交接口,提交成功后,循环调用测评接口
@ -49,7 +53,7 @@ const RightPane = (props) => {
timer = setInterval(() => { timer = setInterval(() => {
clearInterval(timer); clearInterval(timer);
timer = null; timer = null;
saveUserCodeForInterval(identifier, code); saveUserCodeForInterval && saveUserCodeForInterval(identifier, code);
}, 3000); }, 3000);
} }
// 保存用户代码块 // 保存用户代码块
@ -85,10 +89,11 @@ const RightPane = (props) => {
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
const {user_program_identifier, hack, userTestInput} = state.ojForUserReducer; const {user_program_identifier, hack, userTestInput, editor_code} = state.ojForUserReducer;
// const { language, code } = hack; // const { language, code } = hack;
return { return {
hack, hack,
editor_code,
input: userTestInput, input: userTestInput,
submitInput: hack.input, submitInput: hack.input,
identifier: user_program_identifier identifier: user_program_identifier

@ -159,7 +159,7 @@ class ShixunsHome extends Component {
} }
</style> </style>
<div className="clearfix edu-back-white pb40 pt30 mb20 banners" id="index-top" onMouseMove={this.bannaronmousemove} onMouseOut={this.bannaronmouseout}> <div className="clearfix edu-back-white pb40 pt30 mb20 banners" id="index-top" onMouseMove={this.bannaronmousemove} onMouseOut={this.bannaronmouseout}>
<div className="educontent pr educontentSlider"> <div className="educontent pr educontentSlider" style={{"width":'1200px'}}>
{homedatalist===undefined?"": {homedatalist===undefined?"":
<Slider <Slider
nextArrow={<CustomNextArrow />} nextArrow={<CustomNextArrow />}
@ -240,7 +240,7 @@ class ShixunsHome extends Component {
<p className="color-dark edu-txt-center font-24" style={{lineHeight: '30px'}}>实践课程</p> <p className="color-dark edu-txt-center font-24" style={{lineHeight: '30px'}}>实践课程</p>
<p className="color-grey-cd font-12">TRAINING COURSE</p> <p className="color-grey-cd font-12">TRAINING COURSE</p>
</div> </div>
<Link to={"/paths"} className="moreitem">更多<i className="fa fa-angle-right ml5"></i></Link> <Link to={"/paths"} className="moreitem mr18">更多<i className="fa fa-angle-right ml5"></i></Link>
<div className="square-list clearfix" style={{'width':'100%','padding-left':'25px'}}> <div className="square-list clearfix" style={{'width':'100%','padding-left':'25px'}}>
@ -319,7 +319,7 @@ class ShixunsHome extends Component {
<p className="color-dark edu-txt-center font-24" style={{lineHeight: '30px'}}>实训项目</p> <p className="color-dark edu-txt-center font-24" style={{lineHeight: '30px'}}>实训项目</p>
<p className="color-grey-cd font-12">DEVELOPMENT COMMUNITY</p> <p className="color-grey-cd font-12">DEVELOPMENT COMMUNITY</p>
</div> </div>
<Link to={"/shixuns"} className="moreitem">更多<i className="fa fa-angle-right ml5"></i></Link> <Link to={"/shixuns"} className="moreitem mr18">更多<i className="fa fa-angle-right ml5"></i></Link>
<div className="square-list clearfix" style={{'width':'100%','padding-left':'25px'}}> <div className="square-list clearfix" style={{'width':'100%','padding-left':'25px'}}>
<style> <style>

@ -0,0 +1,50 @@
import React, {Component} from 'react';
class Bottomsubmit extends Component {
constructor(props) {
super(props)
this.state = {
}
}
cannelfun=()=>{
window.location.href=this.props.url
}
render() {
return (
<div>
<style>
{
`
.newFooter{
display:none;
}
`
}
</style>
<div className="clearfix bor-bottom-greyE edu-back-white orderingbox newshixunbottombtn">
<div className=" edu-txt-center padding13-30">
<button type="button" className="ant-btn mr20 newshixunmode backgroundFFF" onClick={()=>this.cannelfun()}><span> </span></button>
<button type="button" className="ant-btn newshixunmode mr40 ant-btn-primary" type="primary" htmlType="submit" onClick={()=>this.props.onSubmits()}><span> </span></button>
</div>
</div>
</div>
);
}
}
export default Bottomsubmit;

@ -1,12 +1,13 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import {getImageUrl} from 'educoder'; import {getImageUrl} from 'educoder';
import {Modal,Input} from 'antd'; import {Modal,Input,Form,Radio} from 'antd';
class Addshixuns extends Component { class Addshixuns extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
shixunname:undefined, shixunname:undefined,
shixunzero:false shixunzero:false,
is_jupyter:"1"
} }
} }
@ -52,12 +53,22 @@ class Addshixuns extends Component {
}) })
return return
} }
this.props.Setaddshixuns(shixunname);
let is_jupyter=this.state.is_jupyter==="1"?false:true
this.props.Setaddshixuns(shixunname,is_jupyter);
this.props.modalCancel(); this.props.modalCancel();
} }
GrouponChange = e => {
this.setState({
is_jupyter: e.target.value,
});
};
render() { render() {
const formItemLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 14 },
};
return( return(
<Modal <Modal
className={this.props.className} className={this.props.className}
@ -81,6 +92,14 @@ class Addshixuns extends Component {
</style>:""} </style>:""}
<div className="task-popup-content"> <div className="task-popup-content">
<Form {...formItemLayout}>
<Form.Item label="实训类型">
<Radio.Group value={this.state.is_jupyter} onChange={this.GrouponChange}>
<Radio value="1">普通实训</Radio>
<Radio value="2">jupyter实训</Radio>
</Radio.Group>
</Form.Item>
</Form>
<p className="task-popup-text-center font-16"> <p className="task-popup-text-center font-16">
<span style={{ "line-height":"30px"}}>实训名称</span> <span style={{ "line-height":"30px"}}>实训名称</span>
<span><Input style={{ width:"80%"}} className="yslzxueshisy " placeholder="请输入60字以内的实训名称" onChange={this.handleChange} addonAfter={String(this.state.shixunname===undefined?0:this.state.shixunname.length)+"/60"} maxLength={60} /> <span><Input style={{ width:"80%"}} className="yslzxueshisy " placeholder="请输入60字以内的实训名称" onChange={this.handleChange} addonAfter={String(this.state.shixunname===undefined?0:this.state.shixunname.length)+"/60"} maxLength={60} />

@ -320,7 +320,7 @@ class DetailCardsEditAndAdd extends Component{
}) })
} }
Getaddshixuns=(value)=>{ Getaddshixuns=(value,is_jupyter)=>{
let { let {
shixuns_listeditlist, shixuns_listeditlist,
shixuns_listedit, shixuns_listedit,
@ -329,7 +329,8 @@ class DetailCardsEditAndAdd extends Component{
let list=shixuns_listeditlist let list=shixuns_listeditlist
let url='/paths/add_shixun_to_stage.json'; let url='/paths/add_shixun_to_stage.json';
axios.post(url,{ axios.post(url,{
name:value name:value,
is_jupyter:is_jupyter
}).then((response) => { }).then((response) => {
if(response){ if(response){
if(response.data){ if(response.data){
@ -383,7 +384,7 @@ class DetailCardsEditAndAdd extends Component{
{this.state.Addshixunstype===true?<Addshixuns {this.state.Addshixunstype===true?<Addshixuns
modalCancel={this.cardsModalcancel} modalCancel={this.cardsModalcancel}
Setaddshixuns={(value)=>this.Getaddshixuns(value)} Setaddshixuns={(value,is_jupyter)=>this.Getaddshixuns(value,is_jupyter)}
{...this.props} {...this.props}
{...this.state} {...this.state}
/>:""} />:""}

@ -320,7 +320,7 @@ class DetailCardsEditAndEdit extends Component{
notification.open(data); notification.open(data);
} }
Getaddshixuns=(value)=>{ Getaddshixuns=(value,is_jupyter)=>{
let { let {
shixuns_listeditlist, shixuns_listeditlist,
shixuns_listedit, shixuns_listedit,
@ -329,7 +329,8 @@ class DetailCardsEditAndEdit extends Component{
let list=shixuns_listeditlist let list=shixuns_listeditlist
let url='/paths/add_shixun_to_stage.json'; let url='/paths/add_shixun_to_stage.json';
axios.post(url,{ axios.post(url,{
name:value name:value,
is_jupyter:is_jupyter
}).then((response) => { }).then((response) => {
if(response){ if(response){
if(response.data){ if(response.data){
@ -383,7 +384,7 @@ class DetailCardsEditAndEdit extends Component{
</Modals> </Modals>
{this.state.Addshixunstype===true?<Addshixuns {this.state.Addshixunstype===true?<Addshixuns
modalCancel={this.cardsModalcancel} modalCancel={this.cardsModalcancel}
Setaddshixuns={(value)=>this.Getaddshixuns(value)} Setaddshixuns={(value,is_jupyter)=>this.Getaddshixuns(value,is_jupyter)}
{...this.props} {...this.props}
{...this.state} {...this.state}
/>:""} />:""}

@ -55,8 +55,9 @@ class TPMBanner extends Component {
isIE:false, isIE:false,
Forkvisibletype: false, Forkvisibletype: false,
isSpin:false, isSpin:false,
Senttothevcaluetype:false Senttothevcaluetype:false,
} jupyterbool:false,
}
} }
// star_info:[0, 0, 0, 0, 0, 0], // star_info:[0, 0, 0, 0, 0, 0],
@ -656,7 +657,7 @@ class TPMBanner extends Component {
{/*<span className="mt10">{shixunsDetails.experience}</span>*/} {/*<span className="mt10">{shixunsDetails.experience}</span>*/}
{/*</li>*/} {/*</li>*/}
<li> <li>
<span>难度系数</span> <span>难度级别</span>
<span className="shixunsdiffcult mt10">{shixunsDetails.diffcult}</span> <span className="shixunsdiffcult mt10">{shixunsDetails.diffcult}</span>
</li> </li>

@ -8,7 +8,7 @@ import { CircularProgress } from 'material-ui/Progress';
import './TPMShixunDiscuss.css' import './TPMShixunDiscuss.css'
import Challenges from './shixunchild/Challenges/Challenges' import Challenges from './shixunchild/Challenges/Challenges'
import Challengesjupyter from './shixunchild/Challenges/Challengesjupyter'
import TPMRightSection from './component/TPMRightSection' import TPMRightSection from './component/TPMRightSection'
import TPMNav from './component/TPMNav' import TPMNav from './component/TPMNav'
@ -20,7 +20,7 @@ class TPMChallenge extends Component {
} }
render() { render() {
const { loadingContent, shixun, user, match const { loadingContent, shixun, user, match,jupyterbool
} = this.props; } = this.props;
return ( return (
<React.Fragment> <React.Fragment>
@ -33,9 +33,16 @@ class TPMChallenge extends Component {
shixun={shixun} shixun={shixun}
{...this.props} {...this.props}
></TPMNav> ></TPMNav>
<Challenges {
{...this.props} jupyterbool===true?
/> <Challengesjupyter
{...this.props}
/>
: <Challenges
{...this.props}
/>
}
</div> </div>

@ -0,0 +1,531 @@
import React, {Component} from 'react';
import {Redirect} from 'react-router';
import {List, Typography, Tag, Modal, Radio, Checkbox, Table, Pagination,Upload,notification} from 'antd';
import { NoneData } from 'educoder'
import TPMRightSection from './component/TPMRightSection';
import TPMNav from './component/TPMNav';
import axios from 'axios';
import './tpmmodel/tpmmodel.css'
import {getUploadActionUrl} from 'educoder';
import moment from 'moment';
const confirm = Modal.confirm;
class TPMDataset extends Component {
constructor(props) {
super(props)
this.state = {
datas: [0, 1, 2, 3, 4, 5],
value: undefined,
columns: [
{
title: '文件',
dataIndex: 'number',
key: 'number',
align: 'left',
className: " font-14 wenjiantit",
width: '200px',
render: (text, record) => (
<div>
{record.title}
</div>
)
},
{
title: '最后修改时间',
dataIndex: 'number',
key: 'number',
align: 'center',
className: "edu-txt-center font-14 zuihoushijian",
width: '150px',
render: (text, record) => (
<div>
{record.timedata}
</div>
)
},
{
title: '最后修改人',
dataIndex: 'number',
key: 'number',
align: 'center',
className: "edu-txt-center font-14 ",
render: (text, record) => (
<div>
{record.author}
</div>
)
},
{
title: '文件大小',
dataIndex: 'number',
key: 'number',
align: 'center',
className: "edu-txt-center font-14 ",
render: (text, record) => (
<div>
{record.filesize}
</div>
)
},
],
page: 1,
limit: 10,
selectedRowKeys: [],
mylistansum:30,
collaboratorList:[],
fileList:[],
file:null,
datalist:[],
data_sets_count:0,
selectedRowKeysdata:[],
}
}
componentDidMount() {
this.getdatas()
}
mysonChange = (e) => {
console.log(`全选checked = ${e.target.checked}`);
if (e.target.checked === true) {
let mydata=[];
let datas=[];
for(let i=0;i<this.state.collaboratorList.data_sets.length;i++){
mydata.push(this.state.collaboratorList.data_sets[i].id);
datas.push(i);
}
this.setState({
selectedRowKeysdata:mydata,
selectedRowKeys: datas,
})
console.log(mydata);
console.log(datas);
} else {
this.setState({
selectedRowKeys: [],
})
}
}
getdatas = () => {
let id=this.props.match.params.shixunId;
let collaborators=`/shixuns/${id}/jupyter_data_sets.json`;
axios.get(collaborators,{params:{
page:1,
limit:10,
}}).then((response)=> {
if(response.status===200){
if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
}else{
let datalists=[];
for(let i=0;i<response.data.data_sets.length;i++){
const datas=response.data.data_sets;
var timedata = moment(datas[i].created_on).format('YYYY-MM-DD HH:mm');
datalists.push({
timedata:timedata,
author:datas[i].author,
filesize:datas[i].filesize,
id:datas[i].id,
title:datas[i].title,
})
}
this.setState({
collaboratorList: response.data,
data_sets_count:response.data.data_sets_count,
datalist:datalists,
});
}
}
}).catch((error)=>{
console.log(error)
});
}
getdatastwo = (page,limit) => {
let id=this.props.match.params.shixunId;
let collaborators=`/shixuns/${id}/jupyter_data_sets.json`;
axios.get(collaborators,{params:{
page:page,
limit:limit,
}}).then((response)=> {
if(response.status===200){
if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
}else{
let datalists=[];
for(let i=0;i<response.data.data_sets.length;i++){
const datas=response.data.data_sets;
var timedata = moment(datas[i].created_on).format('YYYY-MM-DD HH:mm');
datalists.push({
timedata:timedata,
author:datas[i].author,
filesize:datas[i].filesize,
id:datas[i].id,
title:datas[i].title,
})
}
this.setState({
collaboratorList: response.data,
data_sets_count:response.data.data_sets_count,
datalist:datalists,
});
}
}
}).catch((error)=>{
console.log(error)
});
}
showModal = (id, status) => {
};
handleOk = (id, editid) => {
};
handleCancel = (e) => {
};
paginationonChanges = (pageNumber) => {
// //console.log('Page: ');
this.setState({
page: pageNumber,
})
this.getdatastwo(pageNumber,10);
}
onSelectChange = (selectedRowKeys, selectedRows) => {
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
this.setState(
{
selectedRowKeys
}
);
let mydata=[];
for(let i=0;i<selectedRows.length;i++){
mydata.push(selectedRows[i].id);
}
this.setState({
selectedRowKeysdata:mydata,
})
console.log(mydata);
}
rowClassName = (record, index) => {
let className = 'light-row';
if (index % 2 === 1) className = 'dark-row';
return className;
}
// 附件相关 START
handleChange = (info) => {
if(info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
let {fileList} = this.state;
if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
console.log("handleChange1");
// if(fileList.length===0){
let fileLists = info.fileList;
this.setState({
// fileList:appendFileSizeToUploadFileAll(fileList),
fileList: fileLists,
deleteisnot: false
});
this.getdatas();
// }
}
}
}
onAttachmentRemove = (file) => {
if(!file.percent || file.percent == 100){
confirm({
title: '确定要删除这个附件吗?',
okText: '确定',
cancelText: '取消',
// content: 'Some descriptions',
onOk: () => {
console.log("665")
this.deleteAttachment(file)
},
onCancel() {
console.log('Cancel');
},
});
return false;
}
}
deleteRemovedata(){
debugger
console.log("删除");
console.log(this.state.selectedRowKeysdata);
const url = `/attachments/destroy_files.json`;
axios.delete(url, {
id:this.state.selectedRowKeysdata,
})
.then((response) => {
if (response.data) {
const { status } = response.data;
if (status == 0) {
this.props.showNotification(`删除成功`);
this.getdatas()
}
}
})
.catch(function (error) {
console.log(error);
});
}
deleteAttachment = (file) => {
console.log(file);
let id=file.response ==undefined ? file.id : file.response.id
const url = `/attachements/destroy_files.json`
axios.delete(url, {
id:[id],
})
.then((response) => {
if (response.data) {
const { status } = response.data;
if (status == 0) {
// console.log('--- success')
this.setState((state) => {
const index = state.fileList.indexOf(file);
const newFileList = state.fileList.slice();
newFileList.splice(index, 1);
return {
fileList: newFileList,
deleteisnot:true
};
});
}
}
})
.catch(function (error) {
console.log(error);
});
}
render() {
const {tpmLoading, shixun, user, match} = this.props;
const {columns, datas, page, limit, selectedRowKeys,mylistansum,fileList,datalist,data_sets_count} = this.state;
const rowSelection = {
selectedRowKeys,
onChange: this.onSelectChange,
};
// getCheckboxProps: record => ({
// disabled: record.name === 'Disabled User', // Column configuration not to be checked
// name: record.name,
// }),
let id=this.props.match.params.shixunId;
const uploadProps = {
width: 600,
fileList,
data:{
attachtype: 2,
container_id:this.props.match.params.shixunId,
container_type: "Shixun",
},
multiple: true,
// https://github.com/ant-design/ant-design/issues/15505
// showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
// showUploadList: false,
action: `${getUploadActionUrl()}`,
onChange: this.handleChange,
onRemove: this.onAttachmentRemove,
beforeUpload: (file, fileList) => {
if (this.state.fileList.length >= 1) {
return false
}
// console.log('beforeUpload', file.name);
const isLt150M = file.size / 1024 / 1024 < 50;
if (!isLt150M) {
// this.props.showNotification(`文件大小必须小于50MB`);
notification.open(
{
message: '提示',
description:
'文件大小必须小于50MB',
}
)
}
if(this.state.file !== undefined){
console.log("763")
this.setState({
file:file
})
}else {
this.setState({
file:file
})
}
console.log("handleChange2");
return isLt150M;
},
}
return (
<React.Fragment>
<div className="tpmComment educontent clearfix mt30 mb80">
<div className="with65 fl edu-back-white commentsDelegateParent">
<TPMNav
match={match}
user={user}
shixun={shixun}
{...this.props}
></TPMNav>
<div className="padding20 edu-back-white mt20 " style={{minHeight: '463px'}}>
<div className="sortinxdirection">
<div className="tpmwidth">
{ data_sets_count>0?
<Checkbox onChange={this.mysonChange}>全选</Checkbox>:""}
</div>
<div className="tpmwidth xaxisreverseorder">
<style>
{
`
.ant-upload-list{
display:none
}
`
}
</style>
<div className="deletebuttom intermediatecenter "> <Upload {...uploadProps}><p className="deletebuttomtest">
上传文件</p> </Upload></div>
{
data_sets_count>0?
<div
className={selectedRowKeys.length > 0 ? "deletebutomtextcode intermediatecenter mr21" : "deletebutom intermediatecenter mr21"} onClick={()=>this.deleteRemovedata()}>
<p className="deletebutomtext" >删除</p></div>
:""
}
</div>
</div>
<div className="mt24">
<style>{`
.ant-spin-nested-loading > div > .ant-spin .ant-spin-dot {
top: 72%;}
}
.edu-table .ant-table-tbody > tr > td {
height: 42px;
}
.edu-table .ant-table-thead > tr > th{
height: 42px;
}
.ysltableowss .ant-table-thead > tr > th{
height: 42px;
}
.ysltableowss .ant-table-tbody > tr > td{
height: 42px;
}
.ysltableowss .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 9px;
}
.mysjysltable4 .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 0px;
}
.ant-table-thead .ant-table-selection-column span{
visibility:hidden;
}
.ant-table-thead > tr > th {
background:#FFFFFF !important;
}
.ant-table table {
width: 100%;
text-align: left;
border-radius: 4px 4px 0 0;
border-collapse: separate;
border-spacing: 0;
border-left: 1px solid #eeeeee;
border-top: 1px solid #eeeeee;
border-right: 1px solid #eeeeee;
}
`}</style>
{data_sets_count===0?
<style>
{
`
.ant-table-tbody{
display:none;
}
.ant-table table {
border-bottom: 1px solid #eeeeee !important;
}
`
}
</style>
:
<div className="edu-table edu-back-white ysltableowss">
<Table
dataSource={datalist}
columns={columns}
pagination={false}
className="mysjysltable4"
rowSelection={rowSelection}
rowClassName={this.rowClassName}
/>
</div>
}
{
data_sets_count>=11?
<div className="edu-txt-center mt40 mb20">
<Pagination showQuickJumper current={page}
onChange={this.paginationonChanges} pageSize={limit}
total={data_sets_count}
></Pagination>
</div>
:""
}
{ data_sets_count===0?
<NoneData style={{width: '100%'}}></NoneData>:""
}
</div>
</div>
</div>
<div className="with35 fr pl20">
<TPMRightSection
{...this.props}
/>
</div>
</div>
</React.Fragment>
);
}
}
export default TPMDataset;

@ -114,7 +114,7 @@ body>.-task-title {
/*-------------------个人主页:右侧提示区域--------------------------*/ /*-------------------个人主页:右侧提示区域--------------------------*/
.-task-sidebar{position:fixed;width:40px;height:180px;right:0;bottom:30px;z-index: 10;} .-task-sidebar{position:fixed;width:40px;height:180px;right:0;bottom:80px !important;z-index: 10;}
.-task-sidebar>div{height: 40px;line-height: 40px;box-sizing: border-box;width:40px;background:#4CACFF;color:#fff;font-size:20px;text-align:center;margin-bottom:5px;border-radius: 4px;} .-task-sidebar>div{height: 40px;line-height: 40px;box-sizing: border-box;width:40px;background:#4CACFF;color:#fff;font-size:20px;text-align:center;margin-bottom:5px;border-radius: 4px;}
.-task-sidebar>div i{ color:#fff;} .-task-sidebar>div i{ color:#fff;}
.-task-sidebar>div i:hover{color: #fff!important;} .-task-sidebar>div i:hover{color: #fff!important;}

@ -27,7 +27,7 @@ import TPMPropaedeuticsComponent from './TPMPropaedeuticsComponent';
import TPMRanking_listComponent from './TPMRanking_listContainer'; import TPMRanking_listComponent from './TPMRanking_listContainer';
import TPMCollaboratorsComponent from './TPMCollaboratorsContainer'; import TPMCollaboratorsComponent from './TPMCollaboratorsContainer';
import Audit_situationComponent from './Audit_situationComponent'; import Audit_situationComponent from './Audit_situationComponent';
import TPMDataset from './TPMDataset';
import '../page/tpiPage.css' import '../page/tpiPage.css'
const $ = window.$ const $ = window.$
@ -142,6 +142,7 @@ class TPMIndex extends Component {
identity:undefined, identity:undefined,
TPMRightSectionData:undefined, TPMRightSectionData:undefined,
PropaedeuticsList: undefined, PropaedeuticsList: undefined,
tpmindexjupyterbool:false,
} }
} }
@ -270,10 +271,12 @@ class TPMIndex extends Component {
// } // }
render() { render() {
let url = window.location.href; let url = window.location.href;
let flag = url.indexOf("add_file")>-1; let flag = url.indexOf("add_file")>-1;
return ( return (
<div className="newMain clearfix"> <div className="newMain clearfix">
{/*头部*/}
{ {
!flag && !flag &&
<TPMBanner <TPMBanner
@ -281,6 +284,13 @@ class TPMIndex extends Component {
{...this.state} {...this.state}
></TPMBanner> ></TPMBanner>
} }
{/*筛选*/}
{/*{*/}
{/* tpmindexjupyterbool===false?*/}
{/* :""*/}
{/*}*/}
{/* */}
<Switch {...this.props}> <Switch {...this.props}>
@ -294,7 +304,7 @@ class TPMIndex extends Component {
}></Route> }></Route>
<Route exact path="/shixuns/:shixunId/challenges" render={ <Route exact path="/shixuns/:shixunId/challenges" render={
(props) => (<TPMChallengeComponent {...this.props} {...this.state} {...props} (props) => (<TPMChallengeComponent {...this.props} jupyterbool={true} {...this.state} {...props}
/>) />)
}></Route> }></Route>
@ -342,12 +352,17 @@ class TPMIndex extends Component {
(props) => (<TPMsettings {...this.props} {...this.state} {...props} />) (props) => (<TPMsettings {...this.props} {...this.state} {...props} />)
}></Route> }></Route>
{/*实训项目条目塞选*/}
<Route exact path="/shixuns/:shixunId/ranking_list" render={ <Route exact path="/shixuns/:shixunId/ranking_list" render={
(props) => (<TPMRanking_listComponent {...this.props} {...this.state} {...props} (props) => (<TPMRanking_listComponent {...this.props} {...this.state} {...props}
/>) />)
}></Route> }></Route>
<Route exact path="/shixuns/:shixunId/dataset" render={
(props) => (<TPMDataset {...this.props} {...this.state} {...props}
/>)
}></Route>
<Route exact path="/shixuns/:shixunId/audit_situation" render={ <Route exact path="/shixuns/:shixunId/audit_situation" render={
(props) => (<Audit_situationComponent {...this.props} {...this.state} {...props} (props) => (<Audit_situationComponent {...this.props} {...this.state} {...props}
/>) />)

@ -23,7 +23,7 @@ const versionNum = '0001';
// let _url_origin = getUrl() // let _url_origin = getUrl()
let _url_origin=''; let _url_origin='';
if(window.location.port === "3007"){ if(window.location.port === "3007"){
_url_origin="http://pre-newweb.educoder.net"; _url_origin="https://test-newweb.educoder.net";
} }
// let _url_origin=`https://www.educoder.net`; // let _url_origin=`https://www.educoder.net`;

@ -0,0 +1,131 @@
import React, { Component } from 'react';
import MonacoEditor from 'react-monaco-editor';
//MonacoDiffEditor 对比模式
import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Icon,DatePicker,Breadcrumb,Upload,Button,notification, Tooltip} from 'antd';
// import "antd/dist/antd.css";
import locale from 'antd/lib/date-picker/locale/zh_CN';
import moment from 'moment';
import axios from 'axios';
import './css/TPMsettings.css';
import { getImageUrl, toPath, getUrl ,appendFileSizeToUploadFileAll, getUploadActionUrl} from 'educoder';
let origin = getUrl();
let path = getUrl("/editormd/lib/")
const $ = window.$;
let timeout;
let currentValue;
const Option = Select.Option;
const RadioGroup = Radio.Group;
const confirm = Modal.confirm;
export default class Shixuninformation extends Component {
constructor(props) {
super(props)
this.state = {
}
}
render() {
let {can_copy}=this.state;
let options;
if (this.props.departmentslist != undefined) {
options = this.props.departmentslist.map((d, k) => {
return (
<Option key={d} id={k}>{d}</Option>
)
})
}
return (
<div>
<div className="clearfix ml30">
<span className="color-grey-6 mt5 fl" style={{minWidth: '95px'}}>复制:</span>
<span className="fl mt5">
<Checkbox checked={this.props.data&&this.props.data.shixun.can_copy === undefined ? false : this.props.data&&this.props.data.shixun.can_copy} onChange={this.props.data&&this.props.data.shixun.can_copy}></Checkbox>
<label style={{top:'6px'}} className="color-grey-9 ml10">(勾选则允许已认证的教师复制该实训)</label>
</span>
</div>
<div className="edu-back-white mb10 padding40-20" style={{display:this.props.identity===1?"block":this.props.data&&this.props.data.shixun.status===2&&this.props.data&&this.props.data.shixun.use_scope===0||this.props.data&&this.props.data.shixun.status===1&&this.props.data&&this.props.data.shixun.use_scope===0?"none":"block"}}>
<p className="color-grey-6 font-16 mb30">公开程度</p>
<RadioGroup onChange={this.SelectOpenpublic} value={this.props.data&&this.props.data.use_scope}>
<Radio className="radioStyle" value={0}><span>对所有公开</span> <span className="color-grey-9">()</span></Radio>
<Radio className="radioStyle" value={1}><span>对指定单位公开</span> <span className="color-grey-9">()</span></Radio>
</RadioGroup>
<div className="clearfix none" id="unit-all" style={{display: this.props.scopetype === false ? 'none' : 'block'}}>
<div className="fl ml25">
<div className="fl" id="unit-input-part" style={{width:'100%'}}>
<div id="person-unit" className="fl pr mr10">
<div className="shixunScopeInput fl" >
<Select
style={{width:'200px'}}
placeholder="请输入并选择单位名称"
onChange={(value)=>this.shixunScopeInput(value)}
onSearch={this.shixunHandleSearch}
showSearch
defaultActiveFirstOption={false}
showArrow={false}
filterOption={false}
notFoundContent={null}
className={this.props.scope_partmenttype===true?"bor-red":""}
>
{options}
</Select>
</div>
<span className="color-grey-9">(搜索并选中添加单位名称)</span>
</div>
</div>
<div style={{width:'100%'}}>
<div className="mt20 clearfix" id="task_tag_content">
{
this.props.scope_partment===undefined?"":this.props.scope_partment.map((item,key)=>{
return(
<li className="task_tag_span" key={key}><span>{item}</span>
<a style={{ color: 'rgba(0,0,0,.25)' }}
onClick={(key)=>this.deleteScopeInput(key)}
>
{this.props.identity===1?"x":this.state.status===2&&this.props.scope_partment===this.props.scope_partments||this.state.status===1&&this.props.scope_partment===this.props.scope_partments?"":"×"}
</a>
</li>
)
})
}
</div>
</div>
<span className={this.props.scope_partmenttype===true?"color-orange ml20 fl":"color-orange ml20 fl none"} id="public_unit_notice">
<i className="fa fa-exclamation-circle mr3"></i>
请选择需要公开的单位
</span>
</div>
</div>
</div>
</div>
);
}
}

@ -0,0 +1,33 @@
import React, { Component } from 'react';
import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Icon,DatePicker,Breadcrumb,Upload,Button,notification, Tooltip,Tabs} from 'antd';
import axios from 'axios';
import './css/TPMsettings.css';
import { getImageUrl, toPath, getUrl ,appendFileSizeToUploadFileAll, getUploadActionUrl} from 'educoder';
export default class Shixuninformation extends Component {
constructor(props) {
super(props)
this.state = {
}
}
render() {
return (
<div>
1111
</div>
);
}
}

@ -0,0 +1,484 @@
import React, {Component} from 'react';
import MonacoEditor from 'react-monaco-editor';
import {
Input,
Select,
Radio,
Checkbox,
Popconfirm,
message,
Modal,
Icon,
DatePicker,
Breadcrumb,
Upload,
Button,
notification,
Tooltip,
Tabs,
Form
} from 'antd';
import axios from 'axios';
import TPMMDEditor from "../challengesnew/TPMMDEditor";
import {getImageUrl, toPath, getUrl, appendFileSizeToUploadFileAll, getUploadActionUrl} from 'educoder';
import {TPMIndexHOC} from "../TPMIndexHOC";
import './css/TPMsettings.css';
import '../newshixuns/css/Newshixuns.css';
class Shixuninformation extends Component {
constructor(props) {
super(props)
this.contentMdRef = React.createRef();
this.state = {
NAME_COUNT: 60,
shixunmemoMDvalue: "",
language: "java",
}
}
getshixunmemoMDvalue = (value, e) => {
this.setState({
shixunmemoMDvalue: value
})
}
render() {
console.log(this.props.data)
const {getFieldDecorator} = this.props.form;
const {newshixunlist, languagewrite, systemenvironment, testcoderunmode, fileList, postapplytitle, postapplyvisible, shixunmemoMDvalue} = this.state;
const {shixun_service_configs}=this.props;
let operateauthority = this.props.identity === 1 ? true : this.props.identity < 5 && this.state.status == 0 ? true : false;
const uploadProps = {
width: 600,
fileList,
multiple: true,
// https://github.com/ant-design/ant-design/issues/15505
// showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
// showUploadList: false,
action: `${getUploadActionUrl()}`,
onChange: this.handleChange,
onRemove: this.onAttachmentRemove,
beforeUpload: (file, fileList) => {
if (this.state.fileList.length >= 1) {
return false
}
// console.log('beforeUpload', file.name);
const isLt150M = file.size / 1024 / 1024 < 50;
if (!isLt150M) {
// this.props.showNotification(`文件大小必须小于50MB`);
notification.open(
{
message: '提示',
description:
'文件大小必须小于50MB',
}
)
}
if (this.state.file !== undefined) {
console.log("763")
this.setState({
file: file
})
} else {
this.setState({
file: file
})
}
console.log("handleChange2");
return isLt150M;
},
}
return (
<div>
<Form>
<Form.Item
label="名称"
style={{"borderBottom": 'none'}}
className="mt15"
>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请输入选题名称',
}, {
max: 60, message: '请输入名称最大限制60个字符',
}, {
whitespace: true, message: '请勿输入空格'
}],
})(
<Input placeholder="请输入名称最大限制60个字符"
className={"input-100-45 greyInput"}
onInput={this.shixunNameInput} autoComplete="off"
addonAfter={`${String(!this.state.shixunName ? 0 : this.state.shixunName.length)}/${this.state.NAME_COUNT}`}
className="newViewAfter"/>
)}
</Form.Item>
<Form.Item
label="简介"
style={{"borderBottom": 'none', 'marginBottom': '0px'}}
className="chooseDes pr"
>
<TPMMDEditor ref={this.contentMdRef} placeholder="请输入简介" mdID={'courseContentMD'}
refreshTimeout={1500}
className="courseMessageMD"
// initValue={this.state.description === null ? "" : this.state.description}
></TPMMDEditor>
</Form.Item>
<Form.Item
label={"难易度"}
style={{"borderBottom": 'none'}}
className="chooseDes pr"
>
{getFieldDecorator('select', {
rules: [{required: true, message: '请选择难易度'}],
})(
<div className="with15 fl pr">
<Select placeholder="请选择难易度"
style={{width: 180}}
onChange={this.Selectthestudent}
>
<Option value={1}>初级</Option>
<Option value={2}>中级</Option>
<Option value={3}>中高级</Option>
<Option value={4}>高级</Option>
</Select>
</div>
)}
<span className="fl ml20 color-grey">实训的难易程度</span>
</Form.Item>
<Form.Item
label={"实验环境"}
style={{"borderBottom": 'none', 'width': '18%', 'float': 'left'}}
className="chooseDes pr"
>
<div>
{getFieldDecorator('selectleft', {
rules: [{required: true, message: '请选择主类别'}],
})(
<div className="width100 fl mr20">
<Select placeholder="请选择主类别"
style={{width: 180}}
onChange={this.selectleft}
defaultOpen={false}
>
{
newshixunlist === undefined ? "" : newshixunlist.main_type.map((item, key) => {
return (
<Option value={item.id} key={key}>
<Tooltip placement="right"
title={item.description === "" ? "无描述" : item.description}>
{item.type_name}
</Tooltip>
</Option>
)
})
}
</Select>
</div>
)}
</div>
</Form.Item>
<Form.Item
style={{"borderBottom": 'none', 'width': '61%', 'float': 'left', 'marginTop': '40px'}}
className="chooseDes pr"
>
<div className=" fl pr mr20">
{getFieldDecorator('selectright', {
rules: [{required: true, message: '请选择小类别'}],
})(
<div className=" fl pr mr20">
<Select placeholder="请选择小类别"
style={{width: 180}}
onChange={this.selectright}
defaultOpen={false}
>
{
newshixunlist === undefined ? "" : newshixunlist.small_type.map((item, key) => {
return (
<Option value={item.id} key={key}>
<Tooltip placement="right"
title={item.description === "" ? "无描述" : item.description}>
{item.type_name}
</Tooltip>
</Option>
)
})
}
</Select>
</div>
)}
<span className="fl ml20 color-grey lineh-20">
<div>
<div className={"font-12"}>
已安装软件hadoop3.1.0jdk1.8
</div>
<div className={"font-12"}>
说明添加了hadoop3.1.0jdk1.8的源码包添加了hadoop3.1.0jdk1.8的源码包
</div>
</div>
</span>
</div>
</Form.Item>
<div className={"both"}></div>
<div className=" color-grey lineh-20 mb20">
没有实验环境
<a className="color-blue" onClick={this.post_apply}> 申请新建</a>
</div>
<Form.Item
label={"评测脚本"}
style={{"borderBottom": 'none'}}
className="chooseDes pr"
>
{getFieldDecorator('select', {
rules: [{required: true, message: '请选择评测脚本'}],
})(
<div className="with15 fl pr">
<Select placeholder="请选择评测脚本"
style={{width: 180}}
onChange={this.Selectthestudent}
>
<Option value={1}>初级</Option>
<Option value={2}>中级</Option>
<Option value={3}>中高级</Option>
<Option value={4}>高级</Option>
</Select>
</div>
)}
<span className="fl ml20 color-blue">
使用自定义脚本
<span className={"color-grey ml10"}>
<Icon type="exclamation-circle"/>
</span>
</span>
</Form.Item>
<div className="mt30 clearfix df">
<div
className={operateauthority === false ? 'nonemodel' : ""}
></div>
<div className="flex1">
<div className="fl" style={{border: '1px solid #ccc'}}>
<MonacoEditor
height="450"
width="1100"
language={this.state.language}
value={shixunmemoMDvalue}
options={{
selectOnLineNumbers: true
}}
onChange={this.getshixunmemoMDvalue}
// onChange={this.getshixunmemoMDvalue}
/>
</div>
</div>
</div>
</Form>
<span className="ant-form-text mt20" >私密版本库
<Checkbox>若需要对学员隐藏部分版本库内容时请选中选中即启用私密版本库请将需要对学员隐藏的文件存储在私密版本库</Checkbox>
</span>
{this.props.identity<3?<div className="edu-back-white padding40-20 mb20">
<p className="color-grey-6 font-16 mb30">服务配置</p>
{ shixun_service_configs&&shixun_service_configs.map((item,key)=>{
return(
<div key={key}>
<div id="5">
<div className="color-grey-6 font-16 mt30 mb20" id="shixun_scenario_type_name">
<span className={"fl"}>{item.name}</span>
{/*<span className={"fr mr40"} onClick={()=>this.Deselectlittle(item.mirror_repository_id)}><i className="fa fa-times-circle color-grey-c font-16 fl"></i></span>*/}
</div>
<div className="clearfix mb5">
<label className="panel-form-label fl">CPU()</label>
<div className="pr fl with80 status_con">
<input type="text" value={item.cpu_limit} onInput={(e)=>this.setConfigsInputs(e,key,1)}
className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" />
</div>
<div className="cl"></div>
</div>
<div className="clearfix mb5">
<label className="panel-form-label fl">最低CPU()</label>
<div className="pr fl with80 status_con">
<input type="text" value={item.lower_cpu_limit} onInput={(e)=>this.setConfigsInputs(e,key,2)}
className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" />
</div>
<div className="cl"></div>
</div>
<div className="clearfix mb5">
<label className="panel-form-label fl">内存限制(M)</label>
<div className="pr fl with80 status_con">
<input type="text" value={item.memory_limit} onInput={(e)=>this.setConfigsInputs(e,key,3)}
className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" />
</div>
<div className="cl"></div>
</div>
<div className="clearfix mb5">
<label className="panel-form-label fl">内存要求(M)</label>
<div className="pr fl with20 status_con">
<input type="text" value={item.request_limit} onInput={(e)=>this.setConfigsInputs(e,key,4)}
className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" />
</div>
<label className="panel-form-label fl" style={{width: '48%'}}>温馨提示纯编程类型实训建议使用默认值对于大数据等建议使用最大内存的30%</label>
<div className="cl"></div>
</div>
</div>
</div>
)
})}
</div> :""}
{postapplyvisible === true ? <style>
{
`
body{
overflow: hidden !important;
}
`
}
</style> : ""}
<Modal
keyboard={false}
title="申请新建"
visible={postapplyvisible}
closable={false}
footer={null}
width={850}
heigth={720}
>
<div>
<li className="clearfix ml82">
<label className="fl mt10 "><span
className="color-red fl mt3">*</span>&nbsp;&nbsp;</label>
<textarea
className={this.state.languagewritetype === true ? "fl task-form-80 task-height-150 bor-reds" : "fl task-form-80 task-height-150"}
style={{width: '89%', height: '100px'}}
onInput={this.setlanguagewrite}
value={languagewrite}
placeholder="请填写该镜像是基于什么语言示例Python"
id="demand_info"></textarea>
</li>
<div className={"color-red shixunspanred"}>{this.state.languagewritetype === true ? "请填写该镜像语言" : ""}</div>
<li className="clearfix ml1">
<label className="panel-form-label fl ml50"><span
className="color-red fl mt3">*</span>&nbsp;&nbsp;</label>
<textarea
className={this.state.systemenvironmenttype === true ? "fl task-form-80 task-height-150 bor-reds" : "fl task-form-80 task-height-150"}
onInput={this.setsystemenvironment}
style={{height: '100px'}}
value={systemenvironment}
placeholder="请填写该镜像是基于什么linux系统环境,代码运行环境"
id="demand_info"></textarea>
</li>
<div
className={"color-red shixunspanred"}>{this.state.systemenvironmenttype === true ? "请填写该镜像语言系统环境" : ""}</div>
<li className="clearfix">
<label className="fl mt10"><span
className="color-red fl mt3">*</span>&nbsp;&nbsp;</label>
<textarea
className={this.state.testcoderunmodetype === true ? "fl task-form-80 task-height-150 bor-reds" : "fl task-form-80 task-height-150"}
onInput={this.settestcoderunmode}
value={testcoderunmode}
style={{height: '100px'}}
placeholder="请填写该镜像中测试代码运行方式"
id="demand_info"></textarea>
</li>
<div
className={"color-red shixunspanred"}>{this.state.testcoderunmodetype === true ? "请填写该镜像测试代码运行方式" : ""}</div>
<li className="clearfix ml50">
<label className="panel-form-label fl mt-5"><span
className="color-red fl">*</span>&nbsp;&nbsp;</label>
<div className="mt10" style={{
display: "inline-block"
}}>
<Upload {...uploadProps}>
<Icon type="upload" className="fl mt3"> </Icon>
<span className="color-blue fl cdefault">上传附件</span>
<span className="color-grey-c fl ml10 ">(单个文件50M以内)</span>
</Upload>
</div>
</li>
<div className={"color-red shixunspanred"}>
{this.state.attachmentidstype === true ? "请上传附件" : ""}
</div>
<li className="edu-txt-center clearfix ">
<a className="pop_close task-btn mr30"
onClick={() => this.sendhideModaly()}
>取消</a>
<Button type="primary" onClick={() => this.sendsure_apply()}
className="task-btn task-btn-orange">确定</Button>
</li>
<div className="cl"></div>
</div>
{/*</Form>*/}
</Modal>
<Modal
keyboard={false}
title="提示"
visible={postapplytitle}
closable={false}
footer={null}
>
<div>
<div className="task-popup-content"><p
className="task-popup-text-center font-16"><span
className="font-17 mt10">新建申请已提交请等待管理员的审核</span></p>
<li className="font-14 mt15 color-grey-6 edu-txt-center">我们将在1-2个工作日内与您联系
</li>
</div>
<div className="task-popup-OK clearfix">
<a className="task-btn task-btn-orange"
onClick={this.yeshidemodel}>知道啦</a>
</div>
</div>
</Modal>
</div>
);
}
}
const TopShixuninformation = Form.create({name: 'newshixun'})(Shixuninformation);
export default TopShixuninformation;

File diff suppressed because it is too large Load Diff

@ -111,3 +111,18 @@ a.newuse_scope-btn {
.ml82{ .ml82{
margin-left:82px; margin-left:82px;
} }
.Permanentban{
color:#5091FF !important;
border-color: #5091FF !important;
}
/*tab*/
.ant-tabs-nav{
padding-bottom:18px;
padding-top: 18px;
}
.ant-tabs-extra-content{
margin-top: 18px;
}

File diff suppressed because it is too large Load Diff

@ -344,7 +344,7 @@ export default class TPMMDEditor extends Component {
</div> </div>
</div> </div>
<div className={"fr rememberTip"}> <div className={"fr rememberTip"}>
{noStorage == true ? ' ' : <p id={`e_tips_mdEditor_${mdID}`} className="edu-txt-right color-grey-cd font-12"> </p>} {noStorage == true ? ' ' : <div id={`e_tips_mdEditor_${mdID}`} className="edu-txt-right color-grey-cd font-12"> </div>}
{/* {noStorage == true ? ' ' : <p id={`e_tips_mdEditor_${mdID}`} className="edu-txt-right color-grey-cd font-12"> </p>} */} {/* {noStorage == true ? ' ' : <p id={`e_tips_mdEditor_${mdID}`} className="edu-txt-right color-grey-cd font-12"> </p>} */}
</div> </div>
</React.Fragment> </React.Fragment>

@ -36,6 +36,10 @@ class TPMNav extends Component {
<Link to={`/shixuns/${shixunId}/collaborators`} <Link to={`/shixuns/${shixunId}/collaborators`}
className={`${match.url.indexOf('collaborators') != -1 ? 'active' : ''} fl mr40`}>合作者</Link> className={`${match.url.indexOf('collaborators') != -1 ? 'active' : ''} fl mr40`}>合作者</Link>
{/*jupyter*/}
<Link to={`/shixuns/${shixunId}/dataset`}
className={`${match.url.indexOf('dataset') != -1 ? 'active' : ''} fl mr40`}>数据集</Link>
<Link to={`/shixuns/${shixunId}/shixun_discuss`} <Link to={`/shixuns/${shixunId}/shixun_discuss`}
className={`${match.url.indexOf('shixun_discuss') != -1 ? 'active' : ''} fl mr40`}>评论</Link> className={`${match.url.indexOf('shixun_discuss') != -1 ? 'active' : ''} fl mr40`}>评论</Link>
@ -45,10 +49,8 @@ class TPMNav extends Component {
{this.props.identity >2||this.props.identity===undefined?"":<Link to={`/shixuns/${shixunId}/audit_situation`} {this.props.identity >2||this.props.identity===undefined?"":<Link to={`/shixuns/${shixunId}/audit_situation`}
className={`${match.url.indexOf('audit_situation') != -1 ? 'active' : ''} fl`}>审核情况</Link>} className={`${match.url.indexOf('audit_situation') != -1 ? 'active' : ''} fl`}>审核情况</Link>}
<a {this.props.identity >4||this.props.identity===undefined ? "":<Link to={`/shixuns/${shixunId}/settings`} className="edu-default-btn edu-blueline-btn ml20 fr"
href={`/shixuns/${shixunId}/settings`} className="edu-default-btn edu-blueline-btn ml20 fr" >配置</Link>}
style={{display: this.props.identity >4||this.props.identity===undefined ? "none" : 'block'}}
>配置</a>
</div> </div>
); );
} }

@ -0,0 +1,47 @@
/*
* @Description: jupyter tpi
* @Author: tangjiang
* @Github:
* @Date: 2019-12-11 08:35:23
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-11 09:13:09
*/
import './index.scss';
import React from 'react';
import SplitPane from 'react-split-pane';
import { Button } from 'antd';
import UserInfo from '../../developer/components/userInfo';
function JupyterTPI (props) {
return (
<div className="jupyter_area">
<div className="jupyter_header">
<UserInfo userInfo={{}} />
<p className="jupyter_title">
<span className="title_desc">MySQL数据库编程开发实训(基础篇)</span>
<span className="title_time">时间</span>
</p>
<p className="jupyter_btn">
{/* sync | poweroff */}
<Button className="btn_common" type="link" icon="sync">重置实训</Button>
<Button className="btn_common" type="link" icon="poweroff">退出实训</Button>
</p>
</div>
<div className="jupyter_ctx">
<SplitPane split="vertical" minSize={350} maxSize={-350} defaultSize="30%">
<div className={'split-pane-left'}>
左侧内容
</div>
<SplitPane split="vertical" defaultSize="100%" allowResize={false}>
<div>右侧内容</div>
<div />
</SplitPane>
</SplitPane>
</div>
</div>
);
}
export default JupyterTPI;

@ -0,0 +1,93 @@
.Resizer {
background: #000;
opacity: 0.2;
z-index: 1;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-moz-background-clip: padding;
-webkit-background-clip: padding;
background-clip: padding-box;
}
.Resizer:hover {
-webkit-transition: all 2s ease;
transition: all 2s ease;
}
.Resizer.horizontal {
height: 11px;
margin: -5px 0;
border-top: 5px solid rgba(255, 255, 255, 0);
border-bottom: 5px solid rgba(255, 255, 255, 0);
cursor: row-resize;
width: 100%;
}
.Resizer.horizontal:hover {
border-top: 5px solid rgba(0, 0, 0, 0.5);
border-bottom: 5px solid rgba(0, 0, 0, 0.5);
}
.Resizer.vertical {
width: 11px;
margin: 0 -5px;
border-left: 5px solid rgba(255, 255, 255, 0);
border-right: 5px solid rgba(255, 255, 255, 0);
cursor: col-resize;
}
.Resizer.vertical:hover {
border-left: 5px solid rgba(0, 0, 0, 0.5);
border-right: 5px solid rgba(0, 0, 0, 0.5);
}
.Resizer.disabled {
cursor: not-allowed;
}
.Resizer.disabled:hover {
border-color: transparent;
}
.jupyter_area{
.jupyter_header{
position: relative;
height: 60px;
line-height: 60px;
background-color: #070F1A;
.jupyter_title{
display: flex;
flex-direction: column;
// justify-content: space-around;
align-items: center;
height: 100%;
color: #fff;
.title_desc{
margin-top: 12px;
font-size: 16px;
}
.title_time{
font-size: 12px;
}
// text-align: center;
}
.jupyter_btn{
position: absolute;
right: 10px;
top: 14px;
.btn_common:hover{
// background-color: #29BD8B;
color: #29BD8B;
}
}
}
.jupyter_ctx{
position: relative;
height: calc(100vh - 60px);
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,111 @@
import React, { Component } from 'react';
import {Button,Form,Input} from 'antd';
import axios from 'axios';
import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
class Osshackathonmd extends Component{
constructor(props) {
super(props)
this.contentMdRef = React.createRef();
this.state={
title_num: 0,
title_value: undefined
}
}
componentDidUpdate =(prevState)=>{
// if(prevState!=this.props){
// let url=`/osshackathon/edit_hackathon.json`;
// axios.get(url).then((result)=>{
// if(result.status==200){
// this.setState({
// title_value:result.data.name
// })
// this.contentMdRef.current.setValue(result.data.description);
// }
// })
// }
}
componentDidMount(){
let url=`/osshackathon/edit_hackathon.json`;
axios.get(url).then((result)=>{
if(result.status==200){
this.setState({
title_value:result.data.name
})
this.contentMdRef.current.setValue(result.data.description === null ? "" : result.data.description);
}
})
}
// 输入title
changeTitle = (e) => {
// title_num: 60 - parseInt(e.target.value.length),
this.setState({
title_num: e.target.value.length,
title_value: e.target.value
})
}
handleSubmit = () => {
let {title_value}=this.state;
const mdContnet = this.contentMdRef.current.getValue().trim();
// if(mdContnet.length>10000){
// this.props.showNotification("内容超过10000个字");
// return
// }
let url=`/osshackathon/update_hackathon.json`;
axios.post(url,{
name:title_value,
description:mdContnet,
}
).then((response) => {
if(response.data.status===0){
this.props.getosshackathon()
this.props.hidehackathonedit()
this.props.showNotification(`提交成功`);
}
}).catch((error) => {
console.log(error)
})
}
render() {
// console.log(this.props.tabkey)
// console.log(chart_rules)
return (
<div className={"mt20"}>
<Form>
<Form.Item label="标题">
<Input placeholder="请输入标题"
value={this.state.title_value}
onInput={this.changeTitle}
className="searchView searchViewAfter h45input" style={{"width": "100%"}} maxLength="60"
addonAfter={String(this.state.title_value === undefined || this.state.title_value === null ? 0 : this.state.title_value.length) + "/60"}
/>
</Form.Item>
<Form.Item label="描述">
<TPMMDEditor ref={this.contentMdRef} placeholder="请输入描述" mdID={'courseContentMD'} refreshTimeout={1500}
className="courseMessageMD"
initValue={this.state.description === null ? "" : this.state.description}></TPMMDEditor>
</Form.Item>
</Form>
<div className="clearfix mt30 mb30">
<div className={"fr"}>
<Button type="primary" onClick={this.handleSubmit} className="defalutSubmitbtn fl mr20">提交</Button>
<a className="defalutCancelbtn fl" onClick={() => this.props.hidehackathonedit()}>取消</ a>
</div>
</div>
</div>
)
}
}
export default Osshackathonmd;

@ -395,3 +395,439 @@ a.white-btn.use_scope-btn:hover{
.ant-btn:hover, .ant-btn:focus, .ant-btn:active, .ant-btn.active{ .ant-btn:hover, .ant-btn:focus, .ant-btn:active, .ant-btn.active{
background-color: #4CACFF; background-color: #4CACFF;
} }
.newViewAfter .ant-input{
line-height: 40px !important;
height: 40px !important;
box-shadow: none!important;
}
.width30{
width: 30%;
}
.newshixunheadersear{
display: -ms-flexbox;
display: flex;
-ms-flex-pack: center;
justify-content: center;
margin: 0 auto;
}
.packinput .ant-input{
height: 55px;
width:663px !important;
font-size: 14px;
/*color: #681616 !important;*/
border-color: #E1EDF8 !important;
padding-left: 20px;
}
.packinput .ant-input-group-addon .ant-btn{
width:137px !important;
font-size: 18px;
height: 53px;
background:rgba(76,172,255,1);
}
.tabtitle{
height: 62px !important;
-webkit-box-shadow: 3px 10px 21px 0px rgba(76, 76, 76, 0.15);
box-shadow: 3px 10px 21px 0px rgba(76, 76, 76, 0.15);
border-radius: 6px;
background: #fff;
display: -ms-flexbox;
display: flex;
-ms-flex-pack: center;
justify-content: center;
}
.tabtitles2{
background: #fff;
height: 62px !important;
width: 1200px;
}
.tabtitless{
height: 62px !important;
line-height: 62px !important;
}
.tabtitle1{
}
.tabtitle2{
margin-left: 30px !important;
}
.counttit{
display: -ms-flexbox;
display: flex;
-ms-flex-pack: center;
justify-content: center;
}
.counttittext{
text-align: left;
width: 1200px;
height: 18px;
color: #888888;
font-size: 13px;
margin-top: 24px;
}
.counttittexts{
color: #4CACFF !important;
font-size: 13px;
}
.mainx{
display: -ms-flexbox;
display: flex;
-ms-flex-pack: center;
justify-content: center;
margin-top: 17px;
}
.project-packages-list{
}
.project-package-item{
display: -ms-flexbox;
display: flex;
-ms-flex-direction:column;
flex-direction:column;
margin-bottom: 20px;
padding: 20px;
background: white;
/* box-shadow: 1px 3px 3px 1px rgba(156,156,156,0.16); */
}
.xuxianpro{
height: 20px;
border-bottom: 1px dashed;
border-color: #EAEAEA;
margin-bottom: 18px;
}
.magr11{
margin-top: 11px;
}
.highlight{
color: #4CACFF;
}
.fonttext{
font-size: 20px;
font-weight:bold;
}
.fontextcolor{
color: #777777;
}
.tzbq{
margin-left: 68px;
}
.tzbqx{
/* margin-left: 24px; */
}
.bjyss{
background: #F8F8F8;
}
.zj{
overflow:hidden;
-o-text-overflow:ellipsis;
text-overflow:ellipsis;
white-space:nowrap
}
.ziticor{
color: #777777;
font-size: 13px;
}
.foohter{
margin-top: 20px;
display: -ms-flexbox;
display: flex;
-ms-flex-direction:row;
flex-direction:row;
}
.maxwidth1100{
max-width: 1100px;
overflow:hidden;
-o-text-overflow:ellipsis;
text-overflow:ellipsis;
white-space:nowrap;
font-size: 18px !important;
font-weight: 500;
color: rgba(51,51,51,1) !important;
}
.newshixunmodelmidfont{
font-size: 14px;
font-weight: 400;
color: #999999;
margin-top: 15px;
margin-left: 30px;
max-width: 1100px;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
}
.newshixunmodelbotfont{
font-size:12px;
font-weight:400;
color:rgba(102,102,102,1);
margin-top: 15px;
margin-left: 30px;
}
.newshixunlist{
max-height:227px;
width: 1200px;
}
.xuxianpro {
height: 20px;
border-bottom: 1px dashed;
border-color: #eaeaea;
margin-bottom: 18px;
}
.newshixunpd030{
padding: 0px 30px;
}
.pd303010{
padding: 30px 30px 10px;
}
.newshixunfont12{
font-size: 12px;
color: rgba(76,172,255,1);
line-height: 21px;
}
.newshixunmode{
width: 100px;
height: 38px;
border-radius: 3px;
/*border: 1px solid rgba(191,191,191,1);*/
}
.ntopsj {
position: absolute;
top: -4px;
}
.nyslbottomsj {
position: absolute;
bottom: -6px;
}
.inherits .ant-dropdown-menu-item{
cursor: inherit !important;
}
.menus{
width: 91px;
text-align: center;
}
.newshixunmodelbotfont span{
display: inline-block;
margin-right: 34px;
}
.minhegiht300{
min-height: 300px;
}
.newshixunlist:hover{
-webkit-box-shadow: 1px 6px 16px rgba(156,156,156,0.16);
box-shadow: 1px 6px 16px rgba(156,156,156,0.16);
opacity: 1;
border-radius: 2px;
}
.newshixun500{
max-width: 500px;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
white-space: nowrap;
}
.mt3 {
margin-top: 3px !important;
}
.highlight{
color: #4CACFF;
}
.newshixunbottombtn{
position: fixed;
z-index: 1000;
bottom: 0px;
width: 100%;
height: 63px;
background: rgba(255,255,255,1);
-webkit-box-shadow: 0px -4px 4px 0px rgba(0,0,0,0.05);
box-shadow: 0px -4px 4px 0px rgba(0,0,0,0.05);
}
.mb60shixun{
margin-bottom: 60px !important;
}
.padding13-30 {
padding: 13px 30px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.displaymodulat {
display: -ms-flexbox;
display: flex;
display: -webkit-flex;
-ms-flex-direction: column;
flex-direction: column;
-ms-flex-align: center;
align-items: center;
}
.WordNumberTextarea {
outline: none; /* 去掉输入字符时的默认样式 */
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background-color: white;
text-shadow: none;
-webkit-writing-mode: horizontal-tb !important;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
resize: none; /*禁止拉伸*/
border: none; /*去掉默认边框*/
width: 100%;
height: 130px;
border: none;
display: block;
}
.WordNumbernote {
padding: 0;
margin: 0;
list-style: none;
text-decoration: none;
-webkit-box-sizing: border-box;
box-sizing: border-box;
overflow: hidden;
height: auto;
border: 1px solid rgba(234, 234, 234, 1);
border-radius: 0.125rem;
margin: 10px 10px 0px 10px;
padding: 10px 10px 5px 10px;
backgroud: rgba(234, 234, 234, 1);
width: 530px;
margin-left: 10px;
margin-top: 25px;
height: 214px !important;
}
.WordNumbernote .WordNumberTextarea {
outline: none;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background-color: white;
text-shadow: none;
-webkit-writing-mode: horizontal-tb !important;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
resize: none;
border: none;
width: 100%;
height: 169px !important;
border: none;
display: block;
}
.WordNumberTextarea-count {
display: inline-block;
float: right;
font-size: 16px;
color: #adadad;
padding-right: 0.25rem;
}
.borerinput {
border: 1px solid #DD1717 !important;
}
.borerinputs {
border: 1px solid #eee !important;
}
.mexertwo {
display: -ms-flexbox;
display: flex;
-ms-flex-direction: initial;
flex-direction: initial;
}
.mexeheigth {
line-height: 40px;
}
.mexeheigth2 {
line-height: 40px;
width: 74px;
}
.minbuttionte {
/* display: flex; */
margin-top: 20px;
width: 100%;
/* align-items: center; */
margin-bottom: 17px;
display: -ms-flexbox;
display: flex;
-ms-flex-direction: column;
flex-direction: column;
-ms-flex-align: center;
align-items: center;
-ms-flex-pack: center;
justify-content: center;
-ms-flex-direction: initial;
flex-direction: initial;
}
.initialflex{
display: -ms-flexbox;
display: flex;
-ms-flex-direction:initial;
flex-direction:initial;
}
.newshixunheadersear{
margin: 0 auto;
}
.newshixunmodels{
margin: 0 auto;
}
.backgroundFFF{
background: #FFF !important;
}
.relative{
position: relative;
}
.pd40px{
padding-bottom: 40px;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,281 @@
import React, { Component } from 'react';
import { Redirect } from 'react-router';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { getImageUrl ,markdownToHTML, configShareForCustom} from 'educoder'
import { CircularProgress } from 'material-ui/Progress';
import { Modal, Spin, Tooltip ,message,Icon} from 'antd';
import 'antd/lib/pagination/style/index.css';
import '../shixunchildCss/Challenges.css'
import ReactDOM from 'react-dom';
import axios from 'axios';
import AccountProfile from"../../../user/AccountProfile";
const $ = window.$;
class Challengesjupyter extends Component {
constructor(props) {
super(props)
this.state = {
ChallengesDataList: undefined,
operate: true,
startbtns: false,
iFrameHeight: '0px',
jupyter_port:0,
jupyter_url:null,
}
}
ChallengesList = () => {
let id = this.props.match.params.shixunId;
let ChallengesURL = `/shixuns/` + id + `/challenges.json`;
axios.get(ChallengesURL).then((response) => {
if (response.status === 200) {
if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
}else{
configShareForCustom(this.props.shixunsDetails.name, response.data.description)
this.setState({
ChallengesDataList: response.data,
sumidtype: false,
});
}
}
}).catch((error) => {
console.log(error)
});
}
componentDidMount() {
setTimeout(this.ChallengesList(), 1000);
console.log("componentDidMount");
console.log("Challengesjupyter");
console.log(this.props);
}
updatamakedown = (id) => {
}
// 关卡的上移下移操作
operations = (sumid, type) => {
}
delOperations = (sumid) => {
}
clonedelOperationss = () => {
}
delOperationss = () => {
}
startgameid=(id)=>{
}
hidestartshixunsreplace=(url)=>{
}
//编辑实训题目选择题
EditTraining=(type, ids, path)=>{
}
//开始实战按钮
startshixunCombat = (type, ids, id) => {
}
hidestartshixunCombattype=()=>{
}
hideAccountProfile=()=>{
};
modifyjupyter=(propsysl)=>{
console.log("propsysl");
console.log(propsysl);
let id=this.props.match.params.shixunId;
const url=`/shixuns/${id}/update_jupyter.json`;
const data={
identifier:id,
jupyter_port:propsysl.shixunsDetails.jupyter_port
}
axios.post(url, data)
.then((result) => {
if (result.data.status == 0) {
this.props.showNotification(`应用成功`);
}
}).catch((error) => {
})
}
sendToken=()=>{
// console.log("sendToken");
// const iframe = document.getElementById('iframe');
// console.log("modifyjupyter");
// const frameWindow = iframe.contentWindow;
// console.log("frameWindow");
// console.log(frameWindow);
}
render() {
let{ChallengesDataList}=this.state;
let id = this.props.match.params.shixunId;
// var deptObjs=document.getElementById("IFRAMEID").contentWindow.document.getElementById("TAGID");
// //判断此元素是否存在
// if(deptObjs!=null){
// //设置该元素的样式或其他属性
// deptObjs.setAttribute('style',' height: 20px !important;'); //!important用来提升指定样式条目的应用优先权
// }
// var submitObj = document.getElementById('submit');
// if(submitObj){
// submitObj.style.color = 'green';
// }
// const dom = document.getElementById('shutdown');
// ReactDOM.unmountComponentAtNode(dom)
// // window.$('#picture_display').hide();
// window.$('.data-tip-right').hide()
// window.onload=()=>{
// debugger
// var _iframe = document.getElementById('header');
// console.log(_iframe);
// // .contentWindow.document.getElementById('shutdown_widget') //get iframe下的id
// // _iframe.style.display= "none"; //修改样式
// }
return (
<React.Fragment>
<div className="mt30 pl20 pr20" >
<p className="clearfix mb20">
<span className="font-16 fl">简介</span>
<Tooltip placement="bottom" title={"编辑"}>
<a style={{ display: this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status < 3 ? "block" : 'none' }}
href={"/shixuns/" + id + "/settings?edit=1"} className="ring-green fr">
<img src={getImageUrl("images/educoder/icon/edit.svg")} className="fl mt3 ml2" />
</a>
</Tooltip>
</p>
<div className="justify break_full_word new_li "
id="challenge_editorMd_description">
<p id="ReactMarkdown" style={{overflow:'hidden'}}>
{ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"":
<div className={"markdown-body"} dangerouslySetInnerHTML={{__html: markdownToHTML(ChallengesDataList.description).replace(/▁/g,"▁▁▁")}}></div>
}
</p>
<style>
{
`
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.sortinxdirection{
display: flex;
flex-direction:row;
}
.xaxisreverseorder{
display: flex;
flex-direction:row-reverse;
}
`
}
</style>
<div className="sortinxdirection mt60">
<div className="renwuxiangssi sortinxdirection">
<div><p className="renwuxiangqdiv">任务详情</p></div> <div><p className="renwuxiangqdivtest ml24"></p></div>
</div>
<div className="renwuxiangssit xaxisreverseorder"><div className="challenbaocun" onClick={()=>this.modifyjupyter(this.props)}><p className="challenbaocuntest">应用到实训</p></div></div>
</div>
<style>
{
`
iframe {
border-width: 0px;
border-style: inset;
border-color: initial;
border-image: initial;
}
iframe {
border-left: 1px solid #eeeeee;
border-top: 1px solid #eeeeee;
border-right: 1px solid #eeeeee;
border-bottom: 1px solid #eeeeee;
}
#header{
visibility:hidden;
}
`
}
</style>
<div className="mt35">
{/*https://48888.jupyter.educoder.net/tree?*/}
<div className="pb47">
{
this.props.shixunsDetails===null || this.props.shixunsDetails===undefined||JSON.stringify(this.props.shixunsDetails)==="{}"?
""
:
(
this.props&&this.props.shixunsDetails&&this.props.shixunsDetails.jupyter_url?
<iframe src={this.props.shixunsDetails.jupyter_url}
sandbox="allow-same-origin allow-scripts allow-top-navigation " scrolling="no" id="frame"
name="framename" width="100%" height="700" frameBorder="0"
></iframe>
:""
)
}
</div>
</div>
</div>
</div>
</React.Fragment>
)
}
}
export default Challengesjupyter;

@ -7,3 +7,125 @@
line-height: 27px; line-height: 27px;
vertical-align: 1px; vertical-align: 1px;
} }
/* 中间居中 */
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
/* 简单居中 */
.intermediatecenterysls{
display: flex;
align-items: center;
}
.spacearound{
display: flex;
justify-content: space-around;
}
.spacebetween{
display: flex;
justify-content: space-between;
}
/* 头顶部居中 */
.topcenter{
display: -webkit-flex;
flex-direction: column;
align-items: center;
}
/* x轴正方向排序 */
/* 一 二 三 四 五 六 七 八 */
.sortinxdirection{
display: flex;
flex-direction:row;
}
/* x轴反方向排序 */
/* 八 七 六 五 四 三 二 一 */
.xaxisreverseorder{
display: flex;
flex-direction:row-reverse;
}
/* 垂直布局 正方向*/
/*
*/
.verticallayout{
display: flex;
flex-direction:column;
}
/* 垂直布局 反方向*/
.reversedirection{
display: flex;
flex-direction:column-reverse;
}
.yslwushiwidth{
width: 50%;
}
.yslwushiwidth90{
width: 90%;
}
.yslwushiwidth10{
width: 10%;
}
.yslwushiwidthbuton{
width: 110px;
}
.yslwushiwidthcolortest{
color: #A8A8A8;
font-size:16px;
}
.yslusername{
color: #000000;
font-size: 18px;
}
.yslusercjz{
width:60px;
height:28px;
border-radius:3px;
border:1px solid #F38B03;
}
.yslusercjztest{
width:60px;
height:28px;
font-size:16px;
color:#F38B03;
line-height:28px;
text-align: center;
}
.w18{
width: 18px;
}
.maxnamewidth150{
width: 150px;
max-width: 150px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
cursor: default;
}
.fabushixunwidth{
color: #000000;
font-size: 16px;
}
.fabushixunwidthcolor{
color: #4CACFF;
font-size: 16px;
}
.divfontexdivs{
border-left: 1px solid #eeeeee;
border-top: 1px solid #eeeeee;
border-right: 1px solid #eeeeee;
border-bottom: 1px solid #eeeeee;
}

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { Redirect } from 'react-router'; import { Redirect } from 'react-router';
import {Modal, Button, Radio, Input, Checkbox,message,Spin, Icon} from 'antd'; import {Modal, Button, Radio, Input, Checkbox,message,Spin, Icon,Pagination} from 'antd';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
@ -48,7 +48,9 @@ class Collaborators extends Component {
user_name:undefined, user_name:undefined,
school_name:undefined, school_name:undefined,
spinnings:false, spinnings:false,
useristrue:false useristrue:false,
mylistansum:6,
limit:20,
} }
} }
componentDidMount() { componentDidMount() {
@ -434,7 +436,10 @@ class Collaborators extends Component {
collaboratorListsumtype, collaboratorListsumtype,
user_name, user_name,
school_name, school_name,
useristrue useristrue,
mylistansum,
page,
limit
} = this.state; } = this.state;
let {loadingContent} = this.props; let {loadingContent} = this.props;
const radioStyle = { const radioStyle = {
@ -448,18 +453,26 @@ class Collaborators extends Component {
console.log(Searchadmin) console.log(Searchadmin)
return ( return (
<React.Fragment> <React.Fragment>
<p className="clearfix mt30" <p className=" mt30 sortinxdirection"
style={{display:this.props.identity<5?"block":"none"}} style={{display:this.props.identity<5?"flex":"none"}}
> >
<a onClick={() => this.showCollaboratorsvisible("cooperation")} <div className="yslwushiwidth">
className="edu-default-btn edu-greenback-btn fr mr20 height40" <p className="edu-default-btn edu-greenback-btn ml20 height40 yslwushiwidthcolortest">共12人</p>
data-remote="true"> </div>
<span className={"line27"}>+ </span>
</a> <div className="yslwushiwidth xaxisreverseorder">
<a onClick={() => this.showCollaboratorsvisible("admin")} <a onClick={() => this.showCollaboratorsvisible("cooperation")}
style={{display:this.props.identity===1?"block":"none"}} className="edu-default-btn edu-greenback-btn mr20 height40 yslwushiwidthbuton"
data-remote="true" data-remote="true">
className="edu-default-btn edu-greenback-btn fr mr20 height40">更换管理员</a> <span className={"line27"}>+ </span>
</a>
<a onClick={() => this.showCollaboratorsvisible("admin")}
style={{display:this.props.identity===1?"flex":"none"}}
data-remote="true"
className="edu-default-btn edu-greenback-btn mr20 height40 yslwushiwidthbuton">更换管理员</a>
</div>
</p> </p>
<Modal <Modal
@ -537,6 +550,8 @@ class Collaborators extends Component {
<span className="fl edu-txt-w100 task-hide font-bd">职业</span> <span className="fl edu-txt-w100 task-hide font-bd">职业</span>
<span className="fl edu-txt-w180 task-hide font-bd ml80">单位</span> <span className="fl edu-txt-w180 task-hide font-bd ml80">单位</span>
</p> </p>
<div className="mt5" style={{background: '#f7f9fd'}}> <div className="mt5" style={{background: '#f7f9fd'}}>
<Spin indicator={antIcon} spinning={this.state.spinnings}> <Spin indicator={antIcon} spinning={this.state.spinnings}>
<div className="clearfix"> <div className="clearfix">
@ -584,39 +599,58 @@ class Collaborators extends Component {
onClick={() => this.submit_add_collaborators_form()}>确定</a> onClick={() => this.submit_add_collaborators_form()}>确定</a>
</div> </div>
</Modal>:""} </Modal>:""}
<style>
{
`
.collaborators-item-middles{width: 100% !important; margin-left: 20px;}
.ysltithead{
padding-bottom: 20px;
}
`
}
</style>
<div className="pl20" id="collaborators_list_info"> <div className="pl20" id="collaborators_list_info">
{ {
collaboratorList===undefined?"":collaboratorList.map((item,key)=>{ collaboratorList===undefined?"":collaboratorList.map((item,key)=>{
if(key<collaboratorListsum){ if(key<collaboratorListsum){
return( return(
<div className="collaborators-item clearfix" key={key}> <div className="collaborators-item clearfix sortinxdirection ysltithead" key={key}>
<a href={item.user.user_url} target="_blank" className="mr20 fl"> <a href={item.user.user_url} target="_blank" className="mr20 fl">
<img alt="用户头像" className="radius" height="80" src={getImageUrl("images/"+item.user.image_url)} width="80"/></a> <img alt="用户头像" className="radius" height="80" src={getImageUrl("images/"+item.user.image_url)} width="80"/></a>
<div className="fl collaborators-item-middle">
<p className="mb10">
<a href={item.user.user_url} target="_blank">{item.user.name}</a>
<span className="ml20" style={{display:this.props.power===false?"none":"inline-block"}}>{item.user.shixun_manager === true ? "(管理员)" : ""}</span>
</p>
<p className="color-grey-B2 font-12 mb10"><span className="mr20">{item.user.identity}</span><span>{item.user.school_name}</span></p>
<p className="mb10"> <div className="fl collaborators-item-middles">
<span className="mr20">发布&nbsp;&nbsp;{item.user.user_shixuns_count}</span> <p className="mb10 ">
{/*<span>粉丝&nbsp;&nbsp;*/} <a href={item.user.user_url} target="_blank" className="yslusername">{item.user.name}</a>
{/*<span id="user_h_fan_count">{item.user.fans_count}</span>*/}
{/*</span>*/}
</p>
{/* <p className="color-grey-B2 task-hide">{item.user.brief_introduction}</p> */} <span className={item&&item.user&&item.user.shixun_manager === true?"ml20 yslusercjz ":"ml20"} style={{display:this.props.power===false?"none":"inline-block"}}><p className="yslusercjztest">{item.user.shixun_manager === true ? "创建者" : ""}</p></span>
</p>
<p className="color-grey-B2 font-12 mb10 sortinxdirection mt14">
<p className="yslwushiwidth90 sortinxdirection">
<p className="mr20 font-16 w70">{item.user.identity}</p>
<p className={item.user.school_name===null||item.user.school_name===""?"":"mr40 font-16 maxnamewidth150"}>{item.user.school_name}</p>
<p className="fabushixunwidth">发布实训项目&nbsp;&nbsp;<span className="fabushixunwidthcolor ml2">{item.user.user_shixuns_count}</span></p>
</p>
<div className="xaxisreverseorder yslwushiwidth10">
{item.user.shixun_manager === true ? "" :
<i className="iconfont icon-shanchu newbianji1 color-grey-c font-16 w40"
style={{display: this.props.power === false ? "none" : "block"}}
onClick={() => this.collaborators_delete(item.user.user_id)}>
</i>
}
</div>
</p>
{/*<p className="mb10">*/}
{/* */}
{/* /!*<span>粉丝&nbsp;&nbsp;*!/*/}
{/* /!*<span id="user_h_fan_count">{item.user.fans_count}</span>*!/*/}
{/* /!*</span>*!/*/}
{/*</p>*/}
{/* <p className="color-grey-B2 task-hide">{item.user.brief_introduction}</p> */}
</div> </div>
{item.user.shixun_manager === true ? "" : <a className="fr color-grey-c mr40 mt35 font-16"
style={{display: this.props.power === false ? "none" : "block"}}
onClick={() => this.collaborators_delete(item.user.user_id)}>删除</a>}
{/*<a href="/watchers/unwatch?object_id=3039&amp;object_type=user&amp;shixun_id=61&amp;target_id=3039" className="fr user_default_btn user_private_btn mt30 font-16 mr20" data-method="post" data-remote="true" rel="nofollow">取消关注</a>*/} {/*<a href="/watchers/unwatch?object_id=3039&amp;object_type=user&amp;shixun_id=61&amp;target_id=3039" className="fr user_default_btn user_private_btn mt30 font-16 mr20" data-method="post" data-remote="true" rel="nofollow">取消关注</a>*/}
</div> </div>
@ -647,7 +681,18 @@ class Collaborators extends Component {
className={collaboratorList.length>10&&collaboratorListsumtype===true?"":"none"} className={collaboratorList.length>10&&collaboratorListsumtype===true?"":"none"}
style={{textAlign:'center',borderTop:'1px solid #eee'}}> style={{textAlign:'center',borderTop:'1px solid #eee'}}>
<a className="loadMore" onClick={this.loadMore}>加载更多</a> <a className="loadMore" onClick={this.loadMore}>加载更多</a>
</div> {/*{*/}
{/* mylistansum>5?*/}
{/* <div className="edu-txt-center mt40 mb40">*/}
{/* <Pagination showQuickJumper current={page}*/}
{/* onChange={this.paginationonChanges} pageSize={limit}*/}
{/* total={mylistansum}*/}
{/* ></Pagination>*/}
{/* </div>*/}
{/* :""*/}
{/*}*/}
</div>
</React.Fragment> </React.Fragment>

@ -26,3 +26,43 @@
height: 27px; height: 27px;
line-height: 25px; line-height: 25px;
} }
.challenbaocun{
width:103px;
height:30px;
background:#29BD8B;
border-radius:3px;
}
.challenbaocuntest{
width:103px;
height:30px;
font-size:16px;
color:#FFFFFF;
text-align: center;
line-height:30px;
}
.renwuxiangqdiv{
width:72px;
height:30px;
font-size:18px;
color:#000000;
line-height:30px;
}
.renwuxiangqdivtest{
width:32px;
height:30px;
font-size:16px;
font-family:MicrosoftYaHei;
color:#4CACFF;
line-height:30px;
}
.renwuxiangssi{
width: 30%;
}
.renwuxiangssit{
width: 70%;
}
.pb47{
padding-bottom: 47px;
}

@ -95,6 +95,33 @@ class ShixunCard extends Component {
left: 10px; left: 10px;
bottom: 125px; bottom: 125px;
} }
.tag-org{
position: absolute;
left: 0px;
top: 20px;
}
.tag-org-name{
width:66px;
height:28px;
background:#FF6802;
width:66px;
height:28px;
border-radius:0px 20px 20px 0px;
}
.tag-org-name-test{
width:45px;
height:23px;
font-size:14px;
color:#FFFFFF;
line-height:19px;
margin-right: 6px;
}
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
` `
} }
</style> </style>
@ -105,6 +132,14 @@ class ShixunCard extends Component {
{/*<img style={{display:'block',height: '28px'}} src={require(`./shixunCss/tag2.png`)}/>*/} {/*<img style={{display:'block',height: '28px'}} src={require(`./shixunCss/tag2.png`)}/>*/}
</div> </div>
} }
{
item.is_jupyter===true?
<div className="tag-org">
<p className="tag-org-name intermediatecenter"> <span className="tag-org-name-test">Jupyter</span></p>
{/*<img style={{display:'block',height: '28px'}} src={require(`./shixunCss/tag2.png`)}/>*/}
</div>
:""}
<div className={item.power === false ? "closeSquare" : "none"}> <div className={item.power === false ? "closeSquare" : "none"}>
<img src={getImageUrl("images/educoder/icon/lockclose.svg")} <img src={getImageUrl("images/educoder/icon/lockclose.svg")}
className="mt80 mb25"/> className="mt80 mb25"/>

@ -404,7 +404,7 @@ class ShixunsIndex extends Component {
{...this.state} {...this.state}
OnSearchInput={this.OnSearchInput.bind(this)} OnSearchInput={this.OnSearchInput.bind(this)}
/> />
{/*下方图片*/}
<ShixunCard <ShixunCard
typepvisible={typepvisible} typepvisible={typepvisible}
middleshixundata={middleshixundata.shixuns} middleshixundata={middleshixundata.shixuns}

@ -0,0 +1,121 @@
.tpmborder{
border: 1px solid;
}
/* 中间居中 */
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
/* 简单居中 */
.intermediatecenterysls{
display: flex;
align-items: center;
}
.spacearound{
display: flex;
justify-content: space-around;
}
.spacebetween{
display: flex;
justify-content: space-between;
}
/* 头顶部居中 */
.topcenter{
display: -webkit-flex;
flex-direction: column;
align-items: center;
}
/* x轴正方向排序 */
/* 一 二 三 四 五 六 七 八 */
.sortinxdirection{
display: flex;
flex-direction:row;
}
/* x轴反方向排序 */
/* 八 七 六 五 四 三 二 一 */
.xaxisreverseorder{
display: flex;
flex-direction:row-reverse;
}
/* 垂直布局 正方向*/
/*
*/
.verticallayout{
display: flex;
flex-direction:column;
}
/* 垂直布局 反方向*/
.reversedirection{
display: flex;
flex-direction:column-reverse;
}
.deletebutom{
width:85px;
height:30px;
background:#C4C4C4;
border-radius:3px;
}
.deletebutomtext{
width:28px;
height:19px;
font-size:14px;
color:#FFFFFF;
line-height:19px;
}
.deletebuttom{
width:85px;
height:30px;
background:#29BD8B;
border-radius:3px;
}
.deletebuttomtest{
width:56px;
height:19px;
font-size:14px;
color:#FFFFFF;
line-height:19px;
}
.tpmwidth{
width: 50%;
}
.mr21{
margin-right: 21px;
}
.wenjiantit{
width: 300px;
}
.zuihoushijian{
width: 125px;
}
.zuihouxiugairen{
width: 70px;
}
.wenjiandaxiao{
width: 56px;
}
.deletebutomtextcode{
width:85px;
height:30px;
background:#FF5555;
border-radius:3px;
}
.light-row{
background: #F7F7F8;
}
.dark-row{
background: #FFFFFF;
}

@ -48,6 +48,8 @@ const types = {
GET_COMMIT_RECORD_DETAIL_BY_ID: 'GET_COMMIT_RECORD_DETAIL_BY_ID', // 根据id号获取提交记录详情 GET_COMMIT_RECORD_DETAIL_BY_ID: 'GET_COMMIT_RECORD_DETAIL_BY_ID', // 根据id号获取提交记录详情
RESTORE_INITIAL_CODE: 'RESTORE_INITIAL_CODE', // 恢复初始代码 RESTORE_INITIAL_CODE: 'RESTORE_INITIAL_CODE', // 恢复初始代码
SAVE_USER_INFO: 'SAVE_USER_INFO', // 只在用户信息 SAVE_USER_INFO: 'SAVE_USER_INFO', // 只在用户信息
SAVE_HACK_IDENTIFIER: 'SAVE_HACK_IDENTIFIER', // 用户界面跑到编辑界面需要用的id值
SAVE_EDITOR_CODE: 'SAVE_EDITOR_CODE', // 保存详情页面中编辑时的代码
} }
export default types; export default types;

@ -7,7 +7,11 @@
*/ */
import toggleTodo from './testAction.js'; import toggleTodo from './testAction.js';
import {getOJList, changePaginationInfo} from './ojList'; import {
getOJList,
changePaginationInfo,
deleteItem
} from './ojList';
import { import {
validateOjForm, validateOjForm,
saveOjFormCode, saveOjFormCode,
@ -41,6 +45,8 @@ import {
getUserProgramDetail, getUserProgramDetail,
saveUserProgramIdentifier, saveUserProgramIdentifier,
restoreInitialCode, restoreInitialCode,
saveUserCodeForInterval,
saveEditorCodeForDetail,
// isUpdateCodeCtx // isUpdateCodeCtx
} from './ojForUser'; } from './ojForUser';
@ -52,9 +58,14 @@ import {
isMyPublish, isMyPublish,
} from './common'; } from './common';
import {
getUserInfoForNew
} from './user';
export default { export default {
toggleTodo, toggleTodo,
getOJList, getOJList,
deleteItem,
changePaginationInfo, changePaginationInfo,
getOJFormById, getOJFormById,
saveOJFormId, saveOJFormId,
@ -90,5 +101,8 @@ export default {
updateOpenTestCaseIndex, updateOpenTestCaseIndex,
saveUserProgramIdentifier, saveUserProgramIdentifier,
restoreInitialCode, restoreInitialCode,
getUserInfoForNew,
saveUserCodeForInterval,
saveEditorCodeForDetail
// isUpdateCodeCtx // isUpdateCodeCtx
} }

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-27 13:42:11 * @Date: 2019-11-27 13:42:11
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 17:56:02 * @LastEditTime: 2019-12-10 19:05:36
*/ */
import types from "./actionTypes"; import types from "./actionTypes";
import { Base64 } from 'js-base64'; import { Base64 } from 'js-base64';
@ -31,6 +31,11 @@ export const startProgramQuestion = (id, props) => {
type: types.SAVE_USER_PROGRAM_ID, type: types.SAVE_USER_PROGRAM_ID,
payload: identifier payload: identifier
}); });
// 保存id值
dispatch({
type: types.SAVE_HACK_IDENTIFIER,
payload: id
});
// 跳转至开启编程 // 跳转至开启编程
if (identifier) { if (identifier) {
// let data = Object.assign({}, props); // let data = Object.assign({}, props);
@ -74,8 +79,13 @@ export const getUserProgramDetail = (identifier, type) => {
dispatch({ dispatch({
type: types.GET_COMMIT_RECORD_DETAIL_BY_ID, type: types.GET_COMMIT_RECORD_DETAIL_BY_ID,
payload: data payload: data
}) });
} }
// 保存用户登录信息
dispatch({
type: types.SAVE_USER_INFO,
payload: data.user
});
} }
}); });
} }
@ -277,10 +287,12 @@ export const getUserCommitRecordDetail = (identifier) => {
return (dispatch) => { return (dispatch) => {
fetchUserCommitRecordDetail(identifier).then(res => { fetchUserCommitRecordDetail(identifier).then(res => {
console.log('提交记录详情======》》》》', res); console.log('提交记录详情======》》》》', res);
const { data } = res;
if (data.status === 401) return;
dispatch({ dispatch({
type: types.GET_COMMIT_RECORD_DETAIL_BY_ID, type: types.GET_COMMIT_RECORD_DETAIL_BY_ID,
payload: res.data payload: data
}) });
}); });
} }
} }
@ -327,6 +339,11 @@ export const submitUserCode = (identifier, inputValue, type) => {
}); });
return; return;
}; };
// 将编辑代码清空
dispatch({
type: types.SAVE_EDITOR_CODE,
payload: ''
});
dispatch(debuggerCode(identifier, inputValue, type || 'submit')); dispatch(debuggerCode(identifier, inputValue, type || 'submit'));
} }
}).catch(() => { }).catch(() => {
@ -383,3 +400,10 @@ export const restoreInitialCode = (identifier) => {
} }
} }
// 保存详情页面中的编辑代码
export const saveEditorCodeForDetail = (code) => {
return {
type: types.SAVE_EDITOR_CODE,
payload: code
}
}

@ -4,13 +4,13 @@
* @Github: * @Github:
* @Date: 2019-11-20 16:35:46 * @Date: 2019-11-20 16:35:46
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 20:24:11 * @LastEditTime: 2019-12-10 19:54:56
*/ */
import types from './actionTypes'; import types from './actionTypes';
import CONST from '../../constants'; import CONST from '../../constants';
import { fetchPostOjForm, fetchGetOjById, publishTask } from '../../services/ojService'; import { fetchPostOjForm, fetchGetOjById, publishTask } from '../../services/ojService';
import { Base64 } from 'js-base64'; import { Base64 } from 'js-base64';
import { message, notification } from 'antd'; import { message, notification, Modal } from 'antd';
import { toStore } from 'educoder'; import { toStore } from 'educoder';
const { jcLabel } = CONST; const { jcLabel } = CONST;
// 表单字段映射 // 表单字段映射
@ -85,6 +85,7 @@ export const validateOjForm = (props, type) => {
return (dispatch, getState) => { return (dispatch, getState) => {
const {ojForm, testCases, identifier, code } = getState().ojFormReducer; const {ojForm, testCases, identifier, code } = getState().ojFormReducer;
// console.log('code', code); // console.log('code', code);
/** 表单验证开始 */
let keys = Object.keys(ojForm); let keys = Object.keys(ojForm);
// 循环判断每个字段是否为空 // 循环判断每个字段是否为空
let hasSuccess = true; let hasSuccess = true;
@ -104,14 +105,35 @@ export const validateOjForm = (props, type) => {
}); });
// 验证测试用例中的数组是否都有对应的值 // 验证测试用例中的数组是否都有对应的值
const tcValidResult = []; const tcValidResult = [];
testCases.forEach(obj => { // 验证测试用例: 1.必须要有输出值 2. 输入值与输出值必须唯一
testCases.forEach((obj, i) => {
let tempObj = {}; let tempObj = {};
['input', 'output'].forEach(key => { ['input', 'output'].forEach(key => {
const value = obj[key]; const value = obj[key];
const validateResult = emptyValidate(key, value); // 非空校验
let validateResult = emptyValidate(key, value);
const errMsg = validateResult[key].errMsg; const errMsg = validateResult[key].errMsg;
if (errMsg) { if (errMsg) {
hasSuccess = false; hasSuccess = false;
} else {
// 唯一性校验
const bool = testCases.some((item, j) => {
if (i !== j) {
return (item[key] === value);
} else {
return false;
}
});
if (bool) {
hasSuccess = false;
validateResult = {
[key]: {
validateStatus: 'error',
errMsg: key === 'input' ? '输入值必须是唯一的' : '输出值必须是唯一的'
}
};
}
} }
Object.assign(tempObj, validateResult); Object.assign(tempObj, validateResult);
}); });
@ -151,6 +173,8 @@ export const validateOjForm = (props, type) => {
payload: false payload: false
}); });
} }
/** 表单验证结束 */
/** 表单验证通过后,调用保存 or 更新 or 发布 */
if (hasSuccess) { if (hasSuccess) {
// console.log('表单保存的数据为: ', getState()); // console.log('表单保存的数据为: ', getState());
const {ojFormReducer} = getState(); const {ojFormReducer} = getState();
@ -205,6 +229,7 @@ export const validateOjForm = (props, type) => {
paramsObj['identifier'] = identifier; paramsObj['identifier'] = identifier;
} }
// 接口调用成功后,跳转至列表页
function linkToDev () { function linkToDev () {
toStore('oj_description', ''); toStore('oj_description', '');
dispatch({ dispatch({
@ -216,51 +241,61 @@ export const validateOjForm = (props, type) => {
}, 1000); }, 1000);
} }
fetchPostOjForm(paramsObj).then(res => { // 调用保存或更新
// TODO if (type === 'publish') {
if (res.status === 200) { // 保存成功后,重新跳转至列表页 // 提示发布信息
const {identifier} = res.data Modal.confirm({
if (type === 'publish') { // 存在发布时,直接调用发布接口 title: '提示',
if (identifier) { content: `
publishTask(identifier).then(res => { 发布后即可应用到自己管理的课堂,
if (res.data.status === 0) { 是否确定发布?`,
message.success('发布成功!'); okText: '确定',
linkToDev(); cancelText: '取消',
} onOk () {
dispatch({ publishTask(identifier).then(res => {
type: types.PUBLISH_LOADING_STATUS, if (res.data.status === 0) {
payload: false message.success('发布成功!');
}); linkToDev();
}).catch(() => { }
dispatch({ dispatch({
type: types.PUBLISH_LOADING_STATUS, type: types.PUBLISH_LOADING_STATUS,
payload: false payload: false
});
}); });
} else { }).catch(() => {
dispatch({ dispatch({
type: types.PUBLISH_LOADING_STATUS, type: types.PUBLISH_LOADING_STATUS,
payload: false payload: false
}); });
} });
} else { },
onCancel () {
dispatch({
type: types.PUBLISH_LOADING_STATUS,
payload: false
});
}
});
} else {
// 调用更新
fetchPostOjForm(paramsObj).then(res => {
if (res.status === 200) { // 保存成功后,重新跳转至列表页
if (res.data.identifier) { if (res.data.identifier) {
message.success('保存成功!'); message.success('保存成功!');
linkToDev(); linkToDev();
} }
dispatch({
type: types.SUBMIT_LOADING_STATUS,
payload: false
});
}
}).catch(err => {
dispatch({ dispatch({
type: types.SUBMIT_LOADING_STATUS, type: types.SUBMIT_LOADING_STATUS,
payload: false payload: false
}); });
} }
} );
}
}).catch(err => {
dispatch({
type: types.SUBMIT_LOADING_STATUS,
payload: false
});
});
} }
} }
}; };
@ -361,6 +396,11 @@ export const getOJFormById = (id) => {
type: types.SAVE_EDIT_OJ_FORM_AND_TEST_CASE, type: types.SAVE_EDIT_OJ_FORM_AND_TEST_CASE,
payload: res.data payload: res.data
}); });
// 保存用户信息
dispatch({
type: types.SAVE_USER_INFO,
payload: res.data.user
});
}); });
} }
} }
@ -371,7 +411,7 @@ export const saveOJFormId = (id) => {
payload: id payload: id
} }
} }
// 清空测试用例集合 // 清空
export const clearOJFormStore = () => { export const clearOJFormStore = () => {
return { return {
type: types.CLEAR_JSFORM_STORE type: types.CLEAR_JSFORM_STORE
@ -380,27 +420,76 @@ export const clearOJFormStore = () => {
// 测试用例输入值改变时 // 测试用例输入值改变时
export const testCaseInputChange = (value, index) => { export const testCaseInputChange = (value, index) => {
const validate = emptyValidate('input', value)['input']; return (dispatch, getState) => {
return { // 非空校验
type: types.TEST_CASE_INPUT_CHANGE, let validate = emptyValidate('input', value)['input'];
payload: { if (!validate.errMsg) {
input: validate, // 唯一性校验
value, const {testCases} = getState().ojFormReducer;
index const bool = testCases.some((item, i) => {
if (i !== index) {
return item['input'] === value;
} else {
return false;
}
});
if (bool) {
validate = {
validateStatus: 'error',
errMsg: '输入值必须唯一'
};
}
} }
dispatch({
type: types.TEST_CASE_INPUT_CHANGE,
payload: {
input: validate,
value,
index
}
});
} }
} }
// 测试用例输出值改变时 // 测试用例输出值改变时
export const testCaseOutputChange = (value, index) => { export const testCaseOutputChange = (value, index) => {
const validate = emptyValidate('output', value)['output']; // const validate = emptyValidate('output', value)['output'];
return { // return {
type: types.TEST_CASE_OUTPUT_CHANGE, // type: types.TEST_CASE_OUTPUT_CHANGE,
payload: { // payload: {
output: validate, // output: validate,
value, // value,
index // index
// }
// }
return (dispatch, getState) => {
// 非空校验
let validate = emptyValidate('output', value)['output'];
if (!validate.errMsg) {
// 唯一性校验
const {testCases} = getState().ojFormReducer;
const bool = testCases.some((item, i) => {
if (i !== index) {
return item['output'] === value;
} else {
return false;
}
});
if (bool) {
validate = {
validateStatus: 'error',
errMsg: '输入值必须唯一'
};
}
} }
dispatch({
type: types.TEST_CASE_OUTPUT_CHANGE,
payload: {
output: validate,
value,
index
}
});
} }
} }

@ -4,10 +4,10 @@
* @Github: * @Github:
* @Date: 2019-11-20 10:48:24 * @Date: 2019-11-20 10:48:24
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-11-29 11:09:54 * @LastEditTime: 2019-12-10 20:40:55
*/ */
import types from './actionTypes'; import types from './actionTypes';
import { fetchOJList } from '../../services/ojService'; import { fetchOJList, fetchDeleteOJItem } from '../../services/ojService';
export const getOJList = (params) => { export const getOJList = (params) => {
return (dispatch) => { return (dispatch) => {
@ -35,3 +35,15 @@ export const changePaginationInfo = (obj) => {
payload: obj payload: obj
} }
} }
// 删除
export const deleteItem = (identifier) => {
return (dispatch, getState) => {
const {pagination} = getState().ojListReducer;
fetchDeleteOJItem(identifier).then(res => {
if (res.status === 200) {
dispatch(getOJList(pagination));
}
});
}
}

@ -4,13 +4,24 @@
* @Github: * @Github:
* @Date: 2019-12-06 15:09:22 * @Date: 2019-12-06 15:09:22
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-06 15:15:00 * @LastEditTime: 2019-12-09 20:34:50
*/ */
import types from './actionTypes'; import types from './actionTypes';
import { fetchUserInfoForNew } from '../../services/ojService';
// 获取用户信息 // 获取用户信息
export default function getUserInfo () { export const getUserInfoForNew = () => {
return (dispatch) => { return (dispatch) => {
// 调用获取用户信息, 如果没有登录直接调用登录,成功后保存当前用户信息 // 调用获取用户信息, 如果没有登录直接调用登录,成功后保存当前用户信息
fetchUserInfoForNew().then(res => {
// console.log('获取用户信息成功: ', res);
const { data } = res;
if (data.status === 401) return;
dispatch({
type: types.SAVE_USER_INFO,
payload: data.user
});
})
} }
} }

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-27 13:41:48 * @Date: 2019-11-27 13:41:48
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-05 13:37:17 * @LastEditTime: 2019-12-10 10:09:59
*/ */
import types from "../actions/actionTypes"; import types from "../actions/actionTypes";
import { Base64 } from 'js-base64'; import { Base64 } from 'js-base64';
@ -20,6 +20,8 @@ const initialState = {
userCodeTab: 'task', // 学员测评tab位置: task | record | comment userCodeTab: 'task', // 学员测评tab位置: task | record | comment
userTestInput: '', // 用户自定义输入值 userTestInput: '', // 用户自定义输入值
recordDetail: {}, // 根据id号获取的记录详情 recordDetail: {}, // 根据id号获取的记录详情
hack_identifier: '', // 用户界面编辑时
editor_code: '' // 保存编辑代码
}; };
const ojForUserReducer = (state = initialState, action) => { const ojForUserReducer = (state = initialState, action) => {
@ -109,6 +111,16 @@ const ojForUserReducer = (state = initialState, action) => {
...state, ...state,
hack: Object.assign({}, curHack) hack: Object.assign({}, curHack)
} }
case types.SAVE_HACK_IDENTIFIER:
return {
...state,
hack_identifier: action.payload
}
case types.SAVE_EDITOR_CODE:
return {
...state,
editor_code: action.payload
}
default: default:
return state; return state;
} }

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-20 16:40:32 * @Date: 2019-11-20 16:40:32
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-05 09:35:29 * @LastEditTime: 2019-12-09 16:30:46
*/ */
import { Base64 } from 'js-base64'; import { Base64 } from 'js-base64';
import types from '../actions/actionTypes'; import types from '../actions/actionTypes';
@ -16,8 +16,8 @@ const init = {
description: '', description: '',
difficult: 1, difficult: 1,
category: 1, category: 1,
openOrNot: 1, // openOrNot: 1,
timeLimit: '' timeLimit: 3
}, },
ojFormValidate: { ojFormValidate: {
name: { name: {
@ -40,10 +40,10 @@ const init = {
validateStatus: '', validateStatus: '',
errMsg: '' errMsg: ''
}, },
openOrNot: { // openOrNot: {
validateStatus: '', // validateStatus: '',
errMsg: '' // errMsg: ''
}, // },
timeLimit: { timeLimit: {
validateStatus: '', validateStatus: '',
errMsg: '' errMsg: ''
@ -64,7 +64,8 @@ const init = {
identifier: '', // OJ表单id identifier: '', // OJ表单id
loading: false, // 僵尸loading标志 loading: false, // 僵尸loading标志
testCodeStatus: 'default', // 调试代码状态 default(默认值) | loading(加载中) | loaded(加载完成) | userCase(用户自定义测试用例) | finish(测试完成) testCodeStatus: 'default', // 调试代码状态 default(默认值) | loading(加载中) | loaded(加载完成) | userCase(用户自定义测试用例) | finish(测试完成)
openTestCodeIndex: [0] // 展开的测试用例: 数组, 当出错时,展开所有出错的测试用例, 默认展开第一个 openTestCodeIndex: [0], // 展开的测试用例: 数组, 当出错时,展开所有出错的测试用例, 默认展开第一个
isPublish: 0, // 是否是发布状态: 0 未发布 1 已发布
} }
const tcValidateObj = { const tcValidateObj = {
@ -167,7 +168,7 @@ const ojFormReducer = (state = initialState, action) => {
* 6. 更改测试用例状态 * 6. 更改测试用例状态
* 7. 添加测试用例验证 * 7. 添加测试用例验证
*/ */
const { code = '', description, language, name, hack_sets = [], time_limit, difficult, category } = action.payload; const { code = '', description, language, name, hack_sets = [], time_limit, difficult, category, status } = action.payload;
const currentOjForm = { const currentOjForm = {
name, // 任务名称 name, // 任务名称
language, language,
@ -203,7 +204,8 @@ const ojFormReducer = (state = initialState, action) => {
code: cbcode, code: cbcode,
testCases: curTestCases, testCases: curTestCases,
testCasesValidate: curTcValidates, testCasesValidate: curTcValidates,
testCodeStatus: hack_sets.length > 0 ? 'userCase' : 'default' testCodeStatus: hack_sets.length > 0 ? 'userCase' : 'default',
isPublish: status
} }
case types.CLEAR_JSFORM_STORE: case types.CLEAR_JSFORM_STORE:
state = Object.assign({}, init); state = Object.assign({}, init);

@ -20,12 +20,13 @@ class SearchPage extends Component{
page:1, page:1,
perpages:20, perpages:20,
data:[], data:[],
jupyterbool:false,
} }
} }
//切换tab //切换tab
changeTab=(e)=>{ changeTab=(e)=>{
// course 课堂, shixun 开发社区 subject 实践课程 memo 交流问答 // course 2 课堂, shixun 0 实训项目 subject 1 实践课程 memo 3交流问答
let types =""; let types ="";
if(parseInt(e.key)===0){ if(parseInt(e.key)===0){
@ -178,7 +179,19 @@ class SearchPage extends Component{
<div className="mainx"> <div className="mainx">
<style>
{
`
.maxnamewidth92{
max-width: 92%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: default;
}
`
}
</style>
<div className="educontent project-packages-list mb30"> <div className="educontent project-packages-list mb30">
{data === undefined ? "" : data.map((item, key) => { {data === undefined ? "" : data.map((item, key) => {
return ( return (
@ -193,10 +206,28 @@ class SearchPage extends Component{
<div className={"font-16 color-dark fl "} style={{width:"100%"}} > <div className={"font-16 color-dark fl "} style={{width:"100%"}} >
{/*标题*/} {/*标题*/}
<span className={"markdown-body fonttext"} <div className="sortinxdirection jupytertextheig" style={{width:"100%"}}>
dangerouslySetInnerHTML={{__html:item.title}}/>
<span className={"markdown-body fonttext maxnamewidth92"}
dangerouslySetInnerHTML={{__html:item.title}}/>
{
type==="shixun"?
(
item.is_jupyter===true?
<div className="jupytertext intermediatecenter ml15"><p className="jupytertextp">Jupyter</p></div>
:""
)
:""
}
</div>
{/*描述*/} {/*描述*/}
<div> <div>
{item.content.content === undefined || item.content.content===0?"": item.content.content.map((item4, key4) => { {item.content.content === undefined || item.content.content===0?"": item.content.content.map((item4, key4) => {
return ( return (
<span className={"markdown-body magr11 fontextcolor"} <span className={"markdown-body magr11 fontextcolor"}
@ -354,7 +385,7 @@ class SearchPage extends Component{
{ {
count && count && count> perpages ? count && count && count> perpages ?
<div className="edu-txt-center" style={{paddingBottom:"30px"}}> <div className="edu-txt-center" style={{marginBottom:"30px",paddingBottom:"30px"}}>
<Pagination showQuickJumper current={page} <Pagination showQuickJumper current={page}
onChange={this.paginationonChanges} pageSize={perpages} onChange={this.paginationonChanges} pageSize={perpages}
total={count}></Pagination> total={count}></Pagination>

@ -132,3 +132,44 @@
display: flex; display: flex;
flex-direction:row; flex-direction:row;
} }
.jupytertext{
width:54px;
height:24px;
background:#FF6802;
border-radius:2px 10px 10px 2px;
margin-top: 2px;
text-align: center;
}
.jupytertextp{
width:39px;
height:16px;
font-size:12px;
color:#FFFFFF;
line-height:16px;
}
/* x轴正方向排序 */
/* 一 二 三 四 五 六 七 八 */
.sortinxdirection{
display: flex;
flex-direction:row;
}
/* x轴反方向排序 */
/* 八 七 六 五 四 三 二 一 */
.xaxisreverseorder{
display: flex;
flex-direction:row-reverse;
}
.intermediatecenter{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.jupytertextheig{
height: 32px;
line-height: 32px;
}
.ml9{
margin-left: 9px;
}

@ -4,7 +4,7 @@
* @Github: * @Github:
* @Date: 2019-11-20 10:55:38 * @Date: 2019-11-20 10:55:38
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-04 18:05:10 * @LastEditTime: 2019-12-10 20:46:16
*/ */
import axios from 'axios'; import axios from 'axios';
@ -20,6 +20,12 @@ export async function fetchOJList (params) {
return axios.get('/problems.json', { params: obj }); return axios.get('/problems.json', { params: obj });
} }
// 删除OJ列表
export async function fetchDeleteOJItem (identifier) {
const url = `/problems/${identifier}.json`;
return axios.delete(url);
}
// 提交 // 提交
export async function fetchPostOjForm (paramsObj) { export async function fetchPostOjForm (paramsObj) {
const { params, submitType, identifier } = paramsObj; const { params, submitType, identifier } = paramsObj;
@ -106,3 +112,9 @@ export async function fetchRestoreInitialCode (identifier) {
const url = `/myproblems/${identifier}/restore_initial_code.json`; const url = `/myproblems/${identifier}/restore_initial_code.json`;
return axios.post(url); return axios.post(url);
} }
// 新建时调用获取用户信息接口
export async function fetchUserInfoForNew () {
const url = `/problems/new.json`;
return axios.get(url);
}

@ -674,7 +674,7 @@ input.radio-width90{ width: 90px; }
.ringauto{width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 50%;background-color: #F4FAFF;margin-right:5px;} .ringauto{width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 50%;background-color: #F4FAFF;margin-right:5px;}
/*-------------------个人主页:右侧提示区域--------------------------*/ /*-------------------个人主页:右侧提示区域--------------------------*/
.-task-sidebar{position:fixed;width:40px;height:180px;right:0;bottom:30px;z-index: 10;} .-task-sidebar{position:fixed;width:40px;height:180px;right:0;bottom:80px;z-index: 10;}
.-task-sidebar div{height: 40px;line-height: 40px;box-sizing: border-box;width:40px;background:#4CACFF;color:#fff;font-size:20px;text-align:center;margin-bottom:5px;border-radius: 4px;} .-task-sidebar div{height: 40px;line-height: 40px;box-sizing: border-box;width:40px;background:#4CACFF;color:#fff;font-size:20px;text-align:center;margin-bottom:5px;border-radius: 4px;}
.-task-sidebar div i{ color:#fff;} .-task-sidebar div i{ color:#fff;}
.-task-sidebar div i:hover{color: #fff!important;} .-task-sidebar div i:hover{color: #fff!important;}

Loading…
Cancel
Save