You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
educoder/public/react/src/modules/tpm/jupyter/index.js

521 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* @Description: jupyter tpi
* @Author: tangjiang
* @Github:
* @Date: 2019-12-11 08:35:23
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-13 15:25:50
*/
import './index.scss';
import React, { useEffect, useState } from 'react';
import SplitPane from 'react-split-pane';
import { Button, Modal,Drawer ,Pagination,Empty,Tooltip,Icon,message,Statistic,Spin} 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 RightPane from './rightPane';
import MyIcon from "../../../common/components/MyIcon";
function clearSlct() {
if("getSelection" in window){
window.getSelection().removeAllRanges();
}else{
document.selection.empty();
};
}
function jsCopy(s) {
clearSlct();
const copyEle = document.getElementById(s);
copyEle.select();
const copyStatus=document.execCommand("Copy");
// 对成功与否定进行提示
copyStatuss(copyStatus)
}
function copyStatuss(copyStatus){
if (copyStatus) {
message.success('复制成功');
} else {
message.error('复制失败');
}
}
function JupyterTPI (props) {
// 获取 identifier 值
const {
match: {
params = {}
},
url,
loading, // 保存按钮状态
total,
pagination,
dataSets, // 数据集
jupyter_info,
getJupyterInfo,
syncJupyterCode,
jupyter_tpi_url_state,
getJupyterTpiDataSet,
getJupyterTpiUrl,
saveJupyterTpi,
changeLoadingState,
changeGetJupyterUrlState,
jupyter_identifier,
changeCurrentPage,
changeshowDrawer,
drawervisible,
reset_with_tpi,
jupytertime,
endjupytertime,
active_with_tpi,
spinning,
updataspinning,
jupyter_folder_name
} = props;
const emptyCtx = (
<div className="jupyter_empty">
<style>
{ `
.ant-empty{
margin-top:80px;
color:#fff;
}
`
}
</style>
<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));
let newHandletype=false
const newHandle = function (event) {
if(newHandletype===false){
newHandletype=true
saveJupyterTpi(event);
setTimeout(()=>{newHandletype=false},500)
}
}
// 保存代码
const addEventListeners = () => {
window.addEventListener('message', (e) => {
// console.log("触发了jupytermessage");
if(e){
if(e.data){
if(e.data==="jupytermessage"){
newHandle()
}
}
}
})
}
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 接口,
* 获取 用户信息,
* 实训的 identifier, 状态, 名称, 是否被修改等信息
*/
getJupyterInfo(identifier);
}, [identifier]);
useEffect(() => {
// 设置jupyter信息
setJupyterInfo(jupyter_info || {});
const {user, tpm_modified, myshixun_identifier} = jupyter_info;
if (user) {
setUserInfo(user);
}
if (myshixun_identifier) {
setMyIdentifier(myshixun_identifier);
}
// 同步代码
if (tpm_modified && updateTip && myshixun_identifier) {
setUpdateTip(false);
updataspinning(true)
Modal.confirm({
title: '更新通知',
content: (<div className="update_notice">
{stopposttpip(1)}
<p className="update_txt">该实训已更新您选择更新后之前编写的实训代码将会丢失如有需要请先使用jupyter中-文件-下载保存代码再进行更新</p>
{/*<p className="update_txt">还未完成评测的任务代码,请自行保存</p>*/}
</div>),
okText: '立即更新',
cancelText: '稍后再说',
onOk () {
syncJupyterCode(myshixun_identifier, '同步成功');
},onCancel() {
updataspinning(false)
stopposttpip(2)
},
})
}
}, [props]);
// 重置实训
const handleClickResetTpi = () => {
stopposttpip(1)
updataspinning(true)
Modal.confirm({
title: '重置实训',
content: (
<p style={{ lineHeight: '24px' }}>
你在本文件中修改的内容将丢失,<br />
是否确定重新加载初始代码
</p>
),
okText: '确定',
cancelText: '取消',
onOk () {
console.log('调用重置代码....', myIdentifier);
if (myIdentifier) {
syncJupyterCode(myIdentifier, '重置成功');
}
},
onCancel() {
stopposttpip(2)
updataspinning(false)
},
})
}
// 重置环境
const handleEnvironmentTpi = () => {
stopposttpip(1)
updataspinning(true)
Modal.confirm({
title: '重置环境',
content: (
<p style={{ lineHeight: '24px' }}>
是否确定重置环境
</p>
),
okText: '确定',
cancelText: '取消',
onOk () {
console.log('调用重置代码....', myIdentifier);
// if (myIdentifier) {
//
// }
reset_with_tpi(myIdentifier, '重置成功');
},
onCancel() {
updataspinning(false)
stopposttpip(2)
},
})
}
// 退出实训
const handleClickQuitTpi = () => {
// console.log(jupyterInfo);
const { identifier } = jupyterInfo;
if (!identifier) return;
props.history.push(`/shixuns/${identifier}/challenges`);
}
// 重新获取 jupyter url
const handleOnReloadUrl = (id) => {
// console.log('jupyter 信息: ', jupyterInfo);
// 改变加载状态值
changeGetJupyterUrlState(-1);
getJupyterTpiUrl({identifier: myIdentifier});
}
// 保存代码
const handleOnSave = () => {
// 改变按钮状态
changeLoadingState(true);
saveJupyterTpi();
}
// 分页信息改变时
const handlePageChange = (current) => {
// 改变当前页
changeCurrentPage(current);
// 分页查找数据
getJupyterTpiDataSet(jupyter_identifier);
}
const swtichFirstDrawer = () => {
changeshowDrawer(!drawervisible)
}
const firstDrawerWidth = ()=>{
return 260
};
let newPage=false
// 分页处理
const handleChangePage = (e,page) => {
//滑动到底判断
let newscrollTop=parseInt(e.currentTarget.scrollTop);
let allclientHeight=e.currentTarget.clientHeight+newscrollTop;
if(dataSets.length<total){
if(e.currentTarget.scrollHeight-allclientHeight===0||e.currentTarget.scrollHeight-allclientHeight===1||e.currentTarget.scrollHeight-allclientHeight===-1){
handlePageChange(page+1);
}
}
}
// 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 filestyles" />
<a className="jupyter_name ml10 maxnamewidth152 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" onScroll={(event)=>handleChangePage(event,pagination.page)} >
{ oList }
</ul>
);
setRenderCtx(oUl);
}
}, [props]);
const onFinish= () =>{
Modal.destroyAll();
Modal.confirm({
title: '倒计时截止',
content: (
<p style={{ lineHeight: '24px' }}>
服务已中断是否确认重置实验环境
</p>
),
okText: '确定',
cancelText: '取消',
onOk () {
reset_with_tpi(myIdentifier, '重置成功');
}
})
}
const endonFinish= () =>{
Modal.confirm({
title: '服务中断提醒',
content: (
<p style={{ lineHeight: '24px' }}>
jupyter将于<span className={"Countdownfonttpi"}><Countdown value={jupytertime} format="HH:mm:ss"/></span>使
</p>
),
okText: '立即延长',
cancelText: '不需要',
onOk () {
active_with_tpi(myIdentifier, '延长成功');
}
})
}
return (
<Spin tip="加载中..." spinning={spinning}>
<div className="jupyter_area">
<div className="jupyter_header">
<UserInfo userInfo={userInfo} />
<p className="jupyter_title">
<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 className={"Countdowntypes"}>
{endjupytertime===false?"":<Countdown value={endjupytertime} format="HH:mm:ss" onFinish={endonFinish}/>}
</span>
</span>
</p>
<p className="jupyter_btn">
{/*sync | poweroff */}
<Button
className="btn_common"
type="link"
icon="history"
onClick={handleClickResetTpi}
>重置实训</Button>
<Button
className="btn_common"
type="link"
icon="sync"
onClick={handleEnvironmentTpi}
>重置环境</Button>
<Button
className="btn_common"
type="link"
icon="poweroff"
onClick={handleClickQuitTpi}
>退出实训</Button>
</p>
</div>
<div className="jupyter_ctx">
<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}
status={jupyter_tpi_url_state}
url={url}
loading={loading}
onReloadUrl={handleOnReloadUrl}
onSave={handleOnSave}
/>
<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 bortop17212F">
{/*<MyIcon type="iconwenti" className="jupyter_data_icon"/>*/}
<i className={"iconfont icon-base"}></i>
{/* <span className="iconfont icon-java jupyter_data_icon"></span>数据集 */}
</h2>
{dataSets&&dataSets.length===0?"":<h2 className="borbottom17212F jupyterfilepaths bortop17212F pt5">
<span className={"ml50"}>文件路径</span>
<div className="sortinxdirection">
<a className="jupyter_name ml50 maxnamewidth186JUPYTER colorlineheightta height45lineheight45">{jupyter_folder_name}</a>
<a className={"fr color-blue font-14 height45lineheight45"}
onClick={() => {
jsCopy("jupyter_folder_name")
}}>复制地址</a>
</div>
<input id="jupyter_folder_name" className={"file_path_input"} value={jupyter_folder_name}/>
</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>
</Spin>
);
}
const mapStateToProps = (state) => {
const {
jupyter_info,
jupyter_tpi_url,
jupyter_data_set,
jupyter_tpi_url_state,
jupyter_data_set_count,
jupyter_folder_name,
jupyter_pagination,
jupyter_identifier
} = state.jupyterReducer;
const { loading ,drawervisible,jupytertime,spinning,endjupytertime} = state.commonReducer;
return {
loading,
jupyter_info,
url: jupyter_tpi_url,
dataSets: jupyter_data_set,
jupyter_tpi_url_state,
total: jupyter_data_set_count,
pagination: jupyter_pagination,
jupyter_folder_name:jupyter_folder_name,
jupyter_identifier,
drawervisible,
jupytertime,
endjupytertime,
spinning
};
}
const mapDispatchToProps = (dispatch) => ({
changeGetJupyterUrlState: (status) => dispatch(actions.changeGetJupyterUrlState(status)),
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)),
//展开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)),
updataspinning:(identifier, msg) => dispatch(actions.updataspinning(identifier, msg)),
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(JupyterTPI);