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

428 lines
12 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} 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';
const { Countdown } = Statistic;
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 值
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,
} = props;
const emptyCtx = (
<div className="jupyter_empty">
<Empty />
</div>
);
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 接口,
* 获取 用户信息,
* 实训的 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);
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>
</div>),
okText: '确定',
cancelText: '取消',
onOk () {
syncJupyterCode(myshixun_identifier, '同步成功');
},onCancel() {
stopposttpip(2)
},
})
}
}, [props]);
// 重置实训
const handleClickResetTpi = () => {
stopposttpip(1)
Modal.confirm({
title: '重置实训',
content: (
<p style={{ lineHeight: '24px' }}>
你在本文件中修改的内容将丢失,<br />
是否确定重新加载初始代码
</p>
),
okText: '确定',
cancelText: '取消',
onOk () {
console.log('调用重置代码....', myIdentifier);
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)
},
})
}
// 退出实训
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
};
// 分页处理
const handleChangePage = (page) => {
// console.log(page, pageSize);
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 deadline = Date.now() + 7200 * 1000; // Moment is also OK
return (
<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={deadline} format="HH:mm:ss" />
</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">
{/*<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>
);
}
const mapStateToProps = (state) => {
const {
jupyter_info,
jupyter_tpi_url,
jupyter_data_set,
jupyter_tpi_url_state,
jupyter_data_set_count,
jupyter_pagination,
jupyter_identifier
} = state.jupyterReducer;
const { loading ,drawervisible} = 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_identifier,
drawervisible,
};
}
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))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(JupyterTPI);