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

chromesetting
杨树明 5 years ago
commit 2eea1a3d69

@ -1,9 +1,35 @@
require 'base64'
class JupytersController < ApplicationController
include JupyterService
before_action :shixun, only: [:open, :open1, :test, :save]
def import_with_tpm
shixun = Shixun.find_by(identifier: params[:identifier])
upload_file = params["file"] || params["#{params[:file_param_name]}"] # 这里的file_param_name是为了方便其他插件名称
uid_logger("#########################file_params####{params["#{params[:file]}"]}")
raise "未上传文件" unless upload_file
content = Base64.encode64(upload_file.tempfile.read)
# upload to server
shixun_tomcat = edu_setting('cloud_bridge')
uri = "#{shixun_tomcat}/bridge/jupyter/update"
tpiID = "tpm#{shixun.id}"
params = {tpiID: tpiID, content: content}
logger.info "test_juypter: uri->#{uri}, params->#{params}"
res = uri_post uri, params
if res && res['code'].to_i != 0
raise("实训云平台繁忙繁忙等级100")
end
render json: {status: 0}
end
def save_with_tpi
myshixun = Myshixun.find_by(identifier: params[:identifier])
jupyter_save_with_game(myshixun, params[:jupyter_port])
@ -42,5 +68,16 @@ class JupytersController < ApplicationController
render json: {status: 0, url: info[:url], port: info[:port]}
end
def active_with_tpm
shixun = Shixun.find_by(identifier: params[:identifier])
jupyter_active_tpm(shixun)
render json: {status: 0}
end
def active_with_tpi
myshixun = Myshixun.find_by(identifier: params[:identifier])
jupyter_active_tpm(myshixun)
render json: {status: 0}
end
end

@ -191,5 +191,26 @@ module JupyterService
edu_setting('jupyter_service').gsub("PORT", jupyter_port)
end
def _jupyter_active(tpiID)
shixun_tomcat = edu_setting('cloud_bridge')
uri = "#{shixun_tomcat}/bridge/jupyter/active"
params = {:tpiID => tpiID}
res = uri_post uri, params
if res && res['code'].to_i != 0
raise("实训云平台繁忙繁忙等级120")
end
end
# tpm 延时
def jupyter_active_tpm(shixun)
tpiID = "tpm#{shixun.id}"
_jupyter_active(tpiID)
end
# tpi 延时
def jupyter_active_tpi(myshixun)
tpiID = myshixun.id
_jupyter_active(tpiID)
end
end

@ -33,6 +33,10 @@ Rails.application.routes.draw do
get :get_info_with_tpm
get :reset_with_tpi
get :reset_with_tpm
get :active_with_tpm
get :active_with_tpi
post :import_with_tpm
end
end

@ -0,0 +1,51 @@
//用于嵌入到jupyter pod中的js
//guange 2019.12.18
var timebool=false;
window.onload=function(){
console.log("开始发送消息了");
timebool=true;
// runEvery10Sec();
}
function runEvery10Sec() {
// 1000 * 10 = 10 秒钟
// console.log("每隔10秒中一次");
require(["base/js/namespace"],function(Jupyter) {
Jupyter.notebook.save_checkpoint();
});
window.parent.postMessage('jupytermessage','*');
// if(timebool===true){
// setTimeout( runEvery10Sec, 1000 * 10 );
// }
}
window.onload=function(){
document.addEventListener('keydown', (e) => {
if (e.keyCode == 83 && (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey)){
e.preventDefault();
console.log("ctrl+s");
window.parent.postMessage('jupytermessage','*');
}
});
window.addEventListener('message', (e) => {
if(e){
if(e.data){
if(e.data==="stopParent"){
//重置停止
timebool=false;
console.log("父窗口调用停止");
}else if(e.data==="clonsParent"){
console.log("父窗口调用启动");
//取消启动
timebool=true;
// runEvery10Sec();
}
}
}
});
}

File diff suppressed because one or more lines are too long

@ -0,0 +1,35 @@
/*
* @Author: your name
* @Date: 2019-12-20 11:40:56
* @LastEditTime : 2019-12-20 13:38:49
* @LastEditors : Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: /notebook/Users/yangshuming/Desktop/new__educode/educoder/public/react/public/js/jupyter.js
*/
window.onload=function(){
require(["base/js/namespace"],function(Jupyter) {
Jupyter.notebook.save_checkpoint();
});
}
// //子目标父窗口接收子窗口发送的消息
// let message = {type: 'open', link:'需要发送的消息'};
//子窗口向父窗口发送消息,消息中包含我们想跳转的链接
window.parent.postMessage('jupytermessage','需要发送的消息');
// //目标父窗口接收子窗口发送的消息
// window.addEventListener('message', (e)=>{
// let origin = event.origin || event.originalEvent.origin;
// if (origin !== '需要发送的消息') {
// return;
// }else {
// //更换iframe的src,实现iframe页面跳转
// 执行方法
// }
// },false);

@ -52,7 +52,7 @@ export function initAxiosInterceptors(props) {
//proxy="http://47.96.87.25:48080"
proxy="https://pre-newweb.educoder.net"
proxy="https://test-newweb.educoder.net"
//proxy="https://test-jupyterweb.educoder.net"
proxy="https://test-jupyterweb.educoder.net"
//proxy="http://192.168.2.63:3001"
// 在这里使用requestMap控制避免用户通过双击等操作发出重复的请求

@ -75,6 +75,10 @@ export function getUploadActionUrltwo(id) {
return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json${isDev ? `?debug=${window._debugType || 'admin'}` : ''}`
}
export function getUploadActionUrlthree() {
return `${getUrlmys()}/api/jupyters/import_with_tpm.json${isDev ? `?debug=${window._debugType || 'admin'}` : ''}`
}
export function getUploadActionUrlOfAuth(id) {
return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json${isDev ? `?debug=${window._debugType || 'admin'}` : ''}`
}

@ -3,7 +3,7 @@
// export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil';
export { getImageUrl as getImageUrl, getUrl as getUrl, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl,getUploadActionUrltwo as getUploadActionUrltwo , getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getUploadActionUrl as getUploadActionUrl,getUploadActionUrltwo as getUploadActionUrltwo ,getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST ,htmlEncode as htmlEncode } from './UrlTool';
export { default as queryString } from './UrlTool2';

@ -15,3 +15,28 @@
left: 13px;
user-select: none;
}
.jupyter_float_button {
background-image: url(./images/float_switch.jpg);
height: 112px;
width: 38px;
position: absolute;
right: 0px;
top: 32%;
cursor: pointer;
left:auto;
z-index: 99999999;
}
.jupyter_float_button .text {
position: relative;
writing-mode: vertical-rl;
top: 36px;
color: #fff;
left: 13px;
user-select: none;
}
.newjupyter_float_button{
right: 330px;
}

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import '../VNC.css'
const $ = window.$;
class FloatButton extends Component {
componentDidMount() {

@ -149,6 +149,8 @@ class TPMBanner extends Component {
}
}
}
@ -866,8 +868,8 @@ class TPMBanner extends Component {
</li>
</ul>
{
this.props.is_jupyter===true?"":
{/*{*/}
{/* this.props.is_jupyter===true?"":*/}
<Popover placement="right" content={
<div style={{"width": "530px"}} >
@ -932,7 +934,7 @@ class TPMBanner extends Component {
</div>
</Popover>
}
{/*// }*/}
{

@ -9,14 +9,35 @@
import './index.scss';
import React, { useEffect, useState } from 'react';
import SplitPane from 'react-split-pane';
import { Button, Modal } from 'antd';
import { Button, Modal,Drawer ,Pagination,Empty,Tooltip,Icon,message,Statistic} from 'antd';
import {
connect
} from 'react-redux';
import FloatButton from '../../page/component/FloatButton';
import UserInfo from '../../developer/components/userInfo';
import actions from '../../../redux/actions';
import LeftPane from './leftPane';
import RightPane from './rightPane';
import MyIcon from "../../../common/components/MyIcon";
function jsCopy(s) {
var copyEle = document.getElementById(s);
const range = document.createRange(); // 创造range
window.getSelection().removeAllRanges(); //清除页面中已有的selection
range.selectNode(copyEle); // 选中需要复制的节点
window.getSelection().addRange(range); // 执行选中元素
const copyStatus = document.execCommand("Copy"); // 执行copy操作
// 对成功与否定进行提示
copyStatuss(copyStatus)
}
function copyStatuss(copyStatus){
if (copyStatus) {
message.success('复制成功');
} else {
message.error('复制失败');
}
}
function JupyterTPI (props) {
// 获取 identifier 值
@ -39,14 +60,61 @@ function JupyterTPI (props) {
changeLoadingState,
changeGetJupyterUrlState,
jupyter_identifier,
changeCurrentPage
changeCurrentPage,
changeshowDrawer,
drawervisible,
reset_with_tpi,
jupytertime,
active_with_tpi
} = props;
const emptyCtx = (
<div className="jupyter_empty">
<Empty />
</div>
);
const { Countdown } = Statistic;
const {identifier} = params;
const [userInfo, setUserInfo] = useState({});
const [jupyterInfo, setJupyterInfo] = useState({});
const [updateTip, setUpdateTip] = useState(true);
const [myIdentifier, setMyIdentifier] = useState('');
const [renderCtx, setRenderCtx] = useState(() => (emptyCtx));
// 保存代码
const addEventListeners = () => {
window.addEventListener('message', (e) => {
console.log("触发了jupytermessage");
if(e){
if(e.data){
if(e.data==="jupytermessage"){
saveJupyterTpi();
}
}
}
})
}
const stopposttpip=(sum)=>{
var _iframe = document.getElementById("rightPaneframe");
if(_iframe == null || _iframe == undefined || _iframe == ""){
return;
}
if(sum===1){
_iframe.contentWindow.postMessage("stopParent", "*");
}else{
_iframe.contentWindow.postMessage("clonsParent", "*");
}
}
useEffect(() => {
addEventListeners()
}, []);
useEffect(() => {
/* jupyter TPI
* 获取 用户信息,
@ -56,6 +124,7 @@ function JupyterTPI (props) {
}, [identifier]);
useEffect(() => {
// 设置jupyter信息
setJupyterInfo(jupyter_info || {});
const {user, tpm_modified, myshixun_identifier} = jupyter_info;
@ -69,10 +138,12 @@ function JupyterTPI (props) {
// 同步代码
if (tpm_modified && updateTip && myshixun_identifier) {
setUpdateTip(false);
Modal.confirm({
title: '更新通知',
content: (<div className="update_notice">
{stopposttpip(1)}
<p className="update_txt">关卡任务的代码文件有更新啦</p>
<p className="update_txt">更新操作将保留已完成的评测记录和成绩</p>
<p className="update_txt">还未完成评测的任务代码请自行保存</p>
@ -81,13 +152,17 @@ function JupyterTPI (props) {
cancelText: '取消',
onOk () {
syncJupyterCode(myshixun_identifier, '同步成功');
}
},onCancel() {
stopposttpip(2)
},
})
}
}, [props]);
// 重置实训
const handleClickResetTpi = () => {
stopposttpip(1)
Modal.confirm({
title: '重置实训',
content: (
@ -103,7 +178,37 @@ function JupyterTPI (props) {
if (myIdentifier) {
syncJupyterCode(myIdentifier, '重置成功');
}
},
onCancel() {
stopposttpip(2)
},
})
}
// 重置环境
const handleEnvironmentTpi = () => {
stopposttpip(1)
Modal.confirm({
title: '重置环境',
content: (
<p style={{ lineHeight: '24px' }}>
你在本文件中修改的内容将丢失,<br />
是否确定重置环境
</p>
),
okText: '确定',
cancelText: '取消',
onOk () {
console.log('调用重置代码....', myIdentifier);
// if (myIdentifier) {
//
// }
reset_with_tpi(myIdentifier, '重置成功');
},
onCancel() {
stopposttpip(2)
},
})
}
@ -138,22 +243,97 @@ function JupyterTPI (props) {
getJupyterTpiDataSet(jupyter_identifier);
}
const swtichFirstDrawer = () => {
changeshowDrawer(!drawervisible)
}
const firstDrawerWidth = ()=>{
return 260
};
// 分页处理
const handleChangePage = (page) => {
handlePageChange(page);
}
// const listCtx = ;
useEffect(() => {
if (dataSets.length > 0) {
console.log('数据集的个数: ', dataSets.length);
const oList = dataSets.map((item, i) => {
return (
<li className="jupyter_item" key={`key_${i}`}>
<Tooltip
placement="right"
// title={item.file_path}
mouseLeaveDelay={0.3}
>
<div className="sortinxdirection">
<Icon type="file-text" className="jupyter_icon fl lineheighttaj" />
<a className="jupyter_name ml10 maxnamewidth150 lineheighttaj colorlineheighttaj" title={item.title}>{item.title}</a>
<a className={"fr color-blue lineheighttaj"}
onClick={() => {
jsCopy("file_path"+i)
}}>复制地址</a>
</div>
<input id={"file_path"+i} className={"file_path_input"} value={item.file_path}/>
</Tooltip>
</li>
);
});
const oUl = (
<ul className="jupyter_data_list">
{ oList }
</ul>
);
setRenderCtx(oUl);
}
}, [props]);
const onFinish= () =>{
Modal.confirm({
title: '倒计时截止',
content: (
<p style={{ lineHeight: '24px' }}>
Jupyter将中断服务是否需要延长使用时间
</p>
),
okText: '确定',
cancelText: '取消',
onOk () {
active_with_tpi(myIdentifier, '重置成功');
}
})
}
return (
<div className="jupyter_area">
<div className="jupyter_header">
<UserInfo userInfo={userInfo} />
<p className="jupyter_title">
<span className="title_desc" style={{ marginTop: '20px' }}>{jupyterInfo.name}</span>
<span className="title_time"></span>
<span className="title_desc" style={{ marginTop: '10px' }}>{jupyterInfo.name}</span>
<span className="title_time jupytertitle_time">
<Countdown value={jupytertime} format="HH:mm:ss" onFinish={onFinish}/>
</span>
</p>
<p className="jupyter_btn">
{/* sync | poweroff */}
<Button
className="btn_common"
type="link"
icon="sync"
icon="history"
onClick={handleClickResetTpi}
>重置实训</Button>
<Button
className="btn_common"
type="link"
icon="sync"
onClick={handleEnvironmentTpi}
>重置环境</Button>
<Button
className="btn_common"
type="link"
@ -162,16 +342,17 @@ function JupyterTPI (props) {
>退出实训</Button>
</p>
</div>
<div className="jupyter_ctx">
<SplitPane split="vertical" minSize={350} maxSize={-350} defaultSize="30%">
<div className={'split-pane-left'}>
<LeftPane
dataSets={dataSets}
total={total}
pagination={pagination}
onPageChange={handlePageChange}
/>
</div>
<SplitPane split="vertical" minSize={350} maxSize={-350} defaultSize="100%">
{/*<div className={'split-pane-left'}>*/}
{/* <LeftPane*/}
{/* dataSets={dataSets}*/}
{/* total={total}*/}
{/* pagination={pagination}*/}
{/* onPageChange={handlePageChange}*/}
{/* />*/}
{/*</div>*/}
<SplitPane split="vertical" defaultSize="100%" allowResize={false}>
<RightPane
identifier={myIdentifier}
@ -181,9 +362,38 @@ function JupyterTPI (props) {
onReloadUrl={handleOnReloadUrl}
onSave={handleOnSave}
/>
<div />
<FloatButton onClick={swtichFirstDrawer} className={drawervisible===false?"jupyter_float_button":"jupyter_float_button newjupyter_float_button"}>{"数据集"}</FloatButton>
</SplitPane>
</SplitPane>
<Drawer
placement={"right"}
closable={false}
mask={false}
// onClose={this.onClose}
visible={drawervisible}
className={"RightPaneDrawer"}
>
{/*<p className={"RightPaneDrawertop"}></p>*/}
<div className="jupyter_data_sets_area newjupyter_data_sets_area">
<h2 className="jupyter_h2_title">
{/*<MyIcon type="iconwenti" className="jupyter_data_icon"/>*/}
<i className={"iconfont icon-base"}></i>
{/* <span className="iconfont icon-java jupyter_data_icon"></span>数据集 */}
</h2>
{ renderCtx }
<div className='jupyter_pagination'>
{total<20?"":<Pagination
simple
current={pagination.page}
pageSize={pagination.limit}
total={total}
onChange={handleChangePage}
/>}
</div>
</div>
</Drawer>
</div>
</div>
);
@ -199,7 +409,7 @@ const mapStateToProps = (state) => {
jupyter_pagination,
jupyter_identifier
} = state.jupyterReducer;
const { loading } = state.commonReducer;
const { loading ,drawervisible,jupytertime} = state.commonReducer;
return {
loading,
jupyter_info,
@ -208,7 +418,9 @@ const mapStateToProps = (state) => {
jupyter_tpi_url_state,
total: jupyter_data_set_count,
pagination: jupyter_pagination,
jupyter_identifier
jupyter_identifier,
drawervisible,
jupytertime
};
}
@ -217,11 +429,19 @@ const mapDispatchToProps = (dispatch) => ({
getJupyterInfo: (identifier) => dispatch(actions.getJupyterInfo(identifier)),
// 重置代码
syncJupyterCode: (identifier, msg) => dispatch(actions.syncJupyterCode(identifier, msg)),
// 重置代码
reset_with_tpi: (identifier, msg) => dispatch(actions.reset_with_tpi(identifier, msg)),
getJupyterTpiDataSet: (identifier, current) => dispatch(actions.getJupyterTpiDataSet(identifier, current)),
getJupyterTpiUrl: (identifier) => dispatch(actions.getJupyterTpiUrl(identifier)),
saveJupyterTpi: () => dispatch(actions.saveJupyterTpi()),
changeLoadingState: (flag) => dispatch(actions.changeLoadingState(flag)),
changeCurrentPage: (current) => dispatch(actions.changeCurrentPage(current))
changeCurrentPage: (current) => dispatch(actions.changeCurrentPage(current)),
//展开Drawer
changeshowDrawer: (type) => dispatch(actions.changeshowDrawer(type)),
//倒计时增加
addjypertime: (type) => dispatch(actions.addjypertime(type)),
//延时
active_with_tpi:(identifier, msg) => dispatch(actions.active_with_tpi(identifier, msg)),
});
export default connect(

@ -56,6 +56,7 @@
line-height: 60px;
background-color: #070F1A;
padding-left: 30px;
z-index:999999;
.jupyter_title{
display: flex;
flex-direction: column;
@ -103,3 +104,86 @@
}
}
}
.RightPaneDrawer{
.RightPaneDrawertop{
width:330px;
height:29px;
background:rgba(17,28,36,1);
}
.ant-drawer-content-wrapper{
width:330px !important;
box-shadow: -2px 0 8px #070F1A !important;
}
.ant-drawer-body{
padding: 0px;
}
.ant-drawer-wrapper-body{
padding-top: 60px;
background: #070F1A;
}
.ant-pagination{
color:#fff !important;
}
}
.newjupyter_data_sets_area{
background:#070F1A !important;
.jupyter_h2_title {
height:49px;
line-height: 49px;
background: #070F1A !important;
border-bottom: 1px solid #17212F !important;
color:#FFFFFF !important;
border-top: 1px solid #17212F !important;
}
.iconfont{
color:#28b887!important;
font-size: 30px !important;
margin-right: 20px;
}
.jupyter_pagination{
border-top: 1px solid #070F1A !important;
}
.jupyter_name{
color:#FFFFFF !important;
}
.file_path_input{
position: absolute;
right: -50%;
}
}
.maxnamewidth150 {
max-width: 150px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: default;
width: 150px;
}
.sortinxdirection{
display: flex;
flex-direction:row;
}
.lineheighttaj{
line-height: 50px !important;
}
.colorlineheighttaj{
color: #ffffff;
}
.jupytertitle_time{
.ant-statistic-content{
font-size: 20px !important;
}
.ant-statistic-content-value{
color:#fff !important;
font-size: 17px !important;
}
}

@ -2,15 +2,15 @@
height: 100%;
background: #fff;
.jupyter_h2_title{
height: 44px;
line-height: 44px;
//height: 44px;
//line-height: 44px;
// background-color: #EEEEEE;
background: #fff;
padding: 0 20px;
font-size: 16px;
// box-size: border-box;
box-sizing: border-box;
border-bottom: 1px solid rgba(238,238,238,1);
//border-bottom: 1px solid rgba(238,238,238,1);
.jupyter_data_icon{
// color: #7286ff;
color: #1890ff;
@ -24,15 +24,16 @@
.jupyter_data_list,
.jupyter_empty{
height: calc(100vh - 160px);
//height: calc(100vh - 160px);
min-height: 350px;
overflow-y: auto;
}
.jupyter_data_list{
.jupyter_item{
line-height:45px;
border-bottom: 1px solid rgba(238,238,238, 1);
padding: 0 30px 0 60px;
//border-bottom: 1px solid rgba(238,238,238, 1);
padding: 0 30px 0 45px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;

@ -58,6 +58,7 @@ function RightPane (props) {
<div className="jupyter_result">
<div className="jupyter_iframe">
<iframe
id={"rightPaneframe"}
title=" "
width="100%"
height="100%"
@ -65,13 +66,13 @@ function RightPane (props) {
className='jupyter_iframe_style'
></iframe>
</div>
<div className="jupyter_submit">
<Button
loading={loading}
type="primary"
onClick={handleClickSubmit}
>保存</Button>
</div>
{/*<div className="jupyter_submit">*/}
{/* <Button*/}
{/* loading={loading}*/}
{/* type="primary"*/}
{/* onClick={handleClickSubmit}*/}
{/* >保存</Button>*/}
{/*</div>*/}
</div>
));

@ -10,8 +10,6 @@ import { Modal, Spin, Tooltip ,message,Icon,Button,Divider} from 'antd';
import axios from 'axios';
import 'antd/lib/pagination/style/index.css';
import '../shixunchildCss/Challenges.css';
import AccountProfile from"../../../user/AccountProfile";

@ -1,7 +1,7 @@
import React, { Component } from 'react';
import { Link } from "react-router-dom";
import { markdownToHTML, configShareForCustom,getImageUrl} from 'educoder'
import { Divider, Tooltip } from 'antd';
import { markdownToHTML, configShareForCustom,getImageUrl,getUploadActionUrlthree,appendFileSizeToUploadFileAll} from 'educoder'
import { Divider, Tooltip,Upload} from 'antd';
import LoadingSpin from '../../../../common/LoadingSpin';
import 'antd/lib/pagination/style/index.css';
import '../shixunchildCss/Challenges.css';
@ -25,6 +25,8 @@ class Challengesjupyter extends Component {
boxoffsetHeigh:0,
opentitletype:true,
isopentitletype:"Less",
enlarge:false,
fileList:[],
}
}
@ -100,6 +102,7 @@ class Challengesjupyter extends Component {
}
componentDidMount() {
var that=this;
setTimeout(this.ChallengesList(), 1000);
let id = this.props.match.params.shixunId;
let ChallengesURL = `/jupyters/get_info_with_tpm.json`;
@ -115,7 +118,6 @@ class Challengesjupyter extends Component {
}, 600)
}else{
if(response.data.status===0){
setTimeout(() => {
this.setState({
jupyter_url:response.data.url,
@ -123,14 +125,12 @@ class Challengesjupyter extends Component {
booljupyterurls:true,
})
}, 800)
}else{
setTimeout(() => {
this.setState({
booljupyterurls:true,
})
}, 600)
}
}
@ -145,6 +145,20 @@ class Challengesjupyter extends Component {
});
setTimeout(this.getjianjiesize(), 1000);
window.addEventListener('message', (e) => {
console.log(e);
if(e){
if(e.data){
if(e.data==="jupytermessage"){
that.modifyjupyter();
}
}
}
});
}
updatamakedowns = () => {
@ -213,7 +227,8 @@ class Challengesjupyter extends Component {
axios.get(url, {params: data})
.then((result) => {
if (result.data.status === 0) {
this.props.showNotification(`应用成功`);
// this.props.showNotification(`应用成功`);
console.log("应用成功了");
}
}).catch((error) => {
})
@ -224,10 +239,51 @@ class Challengesjupyter extends Component {
opentitletype:!this.state.opentitletype
})
}
onclki=(bool)=>{
this.setState({
enlarge:bool
})
}
Importingfiles=()=>{
// 导入文件
}
handleChange = (info) => {
if(info.file.status == "done" || info.file.status == "uploading" || info.file.status === 'removed'){
let fileList = info.fileList;
this.setState({
fileList: appendFileSizeToUploadFileAll(fileList),
});
if(info.file.status === 'done'){
if(info.file.response){
if(info.file.response.status===-1||info.file.response.status==="-1"){
}else{
}
}
}
if(info.file.response){
if(info.file.response.status===-1||info.file.response.status==="-1"){
}else{
if(info.file.response.status===0){
try {
this.props.showNotification('上传文件成功!');
}catch (e) {
}
}
}
}
}
}
render() {
let{ChallengesDataList,booljupyterurls}=this.state;
let{ChallengesDataList,booljupyterurls,enlarge,fileList}=this.state;
let id = this.props.match.params.shixunId;
//老师
const is_teacher = this.props&&this.props.current_user&&this.props.current_user.is_teacher?this.props.current_user.is_teacher:false;
@ -242,7 +298,35 @@ class Challengesjupyter extends Component {
}catch (e) {
}
const uploadProps = {
width: 600,
fileList,
multiple: true,
data:{
identifier:id,
},
//multiple 是否支持多选 查重的时候不能多选 不然弹许多框出来
// https://github.com/ant-design/ant-design/issues/15505
// showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
// showUploadList: false,
action: `${getUploadActionUrlthree()}`,
showUploadList:false,
onChange: this.handleChange,
beforeUpload: (file) => {
//上传前的操作
// console.log('beforeUpload', file.name);
if(file.name.indexOf('.ipynb') === -1){
this.props.showNotification('请上传正确格式文件!');
return false
}
const isLt10M = file.size / 1024 / 1024 < 10;
if (!isLt10M) {
this.props.showNotification('文件大小必须小于10MB!');
}
return isLt10M;
},
};
return (
<React.Fragment>
<div className="">
@ -366,16 +450,46 @@ class Challengesjupyter extends Component {
:
(
admin===true||business===true||mysidentity===true?
<div className={"shixunjianjiecballenges edu-back-white sortinxdirection mt20"}>
<div style={{
height: '63px',
}} className={enlarge?"shixunjianjiecballenges edu-back-white intermediatecenter fangdaone":"shixunjianjiecballenges edu-back-white mt20"}>
<div className={enlarge?"sortinxdirection jupyterswidth":"sortinxdirection"} >
<div className="renwuxiangssi sortinxdirection">
<div><p className="renwuxiangqdiv">任务详情</p></div>
<div><p className="renwuxiangqdivtest ml1 shixunbingbaocun">请将实训题目写在下方并保存</p></div>
</div>
<div className="renwuxiangssit xaxisreverseorder">
<div className="challenbaocun" onClick={() => this.modifyjupyter(this.state)}><p
className="challenbaocuntest">应用到实训</p></div>
{
enlarge===true?
<i className="iconfont icon-suoxiao2 font-18 ml2 ysliconfont" style={{
marginLeft: '30px',
}} onClick={()=>this.onclki(false)}></i>
:
<i className="iconfont icon-fangda font-18 ml2 ysliconfont" style={{
marginLeft: '30px',
}} onClick={()=>this.onclki(true)}></i>
}
<style>
{
`
.ant-upload-list{
display:none
}
`
}
</style>
<Upload {...uploadProps}>
<div className="challenbaocun" type="upload">
<p
className="challenbaocuntest" type="upload" >导入</p>
</div>
</Upload>
</div>
</div>
</div>
:
""
)
@ -393,7 +507,6 @@ class Challengesjupyter extends Component {
}
iframe {
border-left: 1px solid #eeeeee;
border-top: 1px solid #eeeeee;
border-right: 1px solid #eeeeee;
border-bottom: 1px solid #eeeeee;
}
@ -419,8 +532,8 @@ class Challengesjupyter extends Component {
:""
)
:
<iframe src={this.state.jupyter_url}
sandbox="allow-same-origin allow-scripts allow-top-navigation " scrolling="no" id="frame"
<iframe src={this.state.jupyter_url} className={enlarge?"fangdatwo":""}
scrolling="no" id="frame"
name="framename" width="100%" height="700" frameBorder="0"
></iframe>
}

@ -27,14 +27,14 @@
line-height: 25px;
}
.challenbaocun{
width:103px;
width:60px;
height:30px;
background:#29BD8B;
border-radius:3px;
cursor:pointer
}
.challenbaocuntest{
width:103px;
width:60px;
height:30px;
font-size:16px;
color:#FFFFFF;
@ -131,7 +131,6 @@
height: 76px;
line-height: 35px;
padding: 20px;
border-bottom: 1px solid #eeee;
}
.padding1020pxshixun{
@ -185,4 +184,34 @@
.icon-shanchu_Hover:hover{
color:rgb(255, 85, 85) !important;
}
.ysliconfont{
text-align: center;
line-height: 29px;
color: #8a8a8a;
}
.fangdaone{
height: 63px;
width: 100%;
position: fixed;
top: 0px;
left: 0px;
z-index: 999999;
right: 0px;
}
.fangdatwo{
height: 100%;
width: 100%;
position: fixed;
top:0px;
margin-top: 63px;
bottom: 0px;
left: 0px;
z-index: 999999;
right: 0px;
}
.jupyterswidth{
width: 1140px;
}

@ -63,6 +63,9 @@ const types = {
CHANGE_JUPYTER_CURRENT_PAGE: 'CHANGE_JUPYTER_CURRENT_PAGE',
SAVE_NOTICE_COUNT: 'SAVE_NOTICE_COUNT', // 保存代码块是否更新
AUTO_UPDATE_CODE: 'AUTO_UPDATE_CODE', // 自动更新代码
CHANGE_SHOW_DRAWER: 'CHANGE_SHOW_DRAWER',
CHANGE_JYPYTER_TIME: 'CHANGE_JYPYTER_TIME',//增加15分钟
CHANGE_EXTENDED_TIME: 'CHANGE_EXTENDED_TIME',//延时
}
export default types;

@ -72,7 +72,11 @@ import {
syncJupyterCode,
changeGetJupyterUrlState,
saveJupyterTpi,
changeCurrentPage
changeCurrentPage,
changeshowDrawer,
reset_with_tpi,
addjypertime,
active_with_tpi
} from './jupyter';
export default {
@ -127,6 +131,10 @@ export default {
syncJupyterCode,
changeGetJupyterUrlState,
saveJupyterTpi,
changeCurrentPage
changeCurrentPage,
changeshowDrawer,
reset_with_tpi,
addjypertime,
active_with_tpi,
// isUpdateCodeCtx
}

@ -13,7 +13,9 @@ import {
fetchJupyterTpiUrl,
fetchJupyterInfo,
fetchSyncJupyterCode,
fetchSaveJupyterTpi
fetchreset_with_tpi,
fetchSaveJupyterTpi,
fetactive_with_tpi
} from "../../services/jupyterServer";
// 获取 jupyter 相关信息
@ -110,6 +112,54 @@ export const syncJupyterCode = (identifier, msg) => {
})
}
}
// 重置环境
export const reset_with_tpi = (identifier, msg) => {
return (dispatch,getState) => {
const {jupyter_info }= getState().jupyterReducer;
if (!jupyter_info.myshixun_identifier) return;
const params = {
identifier: jupyter_info.myshixun_identifier,
};
fetchreset_with_tpi(params).then(res => {
// console.log('同步代码成功: ', res);
if (res.data.status === 401) return;
if (res.status === 200) {
const {status} = res.data
if (status === 0) {
message.success(msg);
setTimeout(() => {
window.location.reload();
}, 300);
}
}
})
}
}
// 延时
export const active_with_tpi = (identifier, msg) => {
return (dispatch,getState) => {
const {jupyter_info }= getState().jupyterReducer;
if (!jupyter_info.myshixun_identifier) return;
const params = {
identifier: jupyter_info.myshixun_identifier,
};
fetactive_with_tpi(params).then(res => {
// console.log('同步代码成功: ', res);
if (res.data.status === 401) return;
if (res.status === 200) {
const {status} = res.data
if (status === 0) {
message.success(msg);
addjypertime(Date.now() + 900 * 1000);
}
}
})
}
}
// 改变状态值
export const changeGetJupyterUrlState = (status) => {
return {
@ -155,3 +205,20 @@ export const changeCurrentPage = (current) => {
payload: current
}
}
// 改变当前页数
export const changeshowDrawer = (type) => {
return {
type: types.CHANGE_SHOW_DRAWER,
payload: type
}
}
//增加倒计时
export const addjypertime=(time)=>{
return {
type: types.CHANGE_JYPYTER_TIME,
payload: time
}
}

@ -14,7 +14,9 @@ const initialState = {
excuteState: '', // 代码执行状态
submitLoading: false, // 提交按钮状态
publishLoading: false, // 发布
isMySource: false
isMySource: false,
drawervisible:false,
jupytertime:Date.now() + 3600 * 1000,
}
const commonReducer = (state = initialState, action) => {
@ -50,6 +52,16 @@ const commonReducer = (state = initialState, action) => {
...state,
isMySource: action.payload
}
case types.CHANGE_SHOW_DRAWER:
return {
...state,
drawervisible: action.payload
}
case types.CHANGE_JYPYTER_TIME:
return {
...state,
jupytertime: action.payload
}
default:
return state;
}

@ -33,3 +33,15 @@ export async function fetchSaveJupyterTpi (params) {
const url = `/jupyters/save_with_tpi.json`;
return axios.get(url, { params });
}
//重置jupyter 环境
export async function fetchreset_with_tpi (params) {
const url = `/jupyters/reset_with_tpi.json`;
return axios.get(url, { params });
}
//延时jupyter
export async function fetactive_with_tpi(params) {
const url = `/jupyters/active_with_tpi.json`;
return axios.get(url, { params });
}

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save