chromesetting
tangjiang 5 years ago
parent da1ae67a08
commit 1d9e17a8bb

@ -4,19 +4,19 @@
* @Github:
* @Date: 2019-12-11 08:35:23
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-12 11:26:33
* @LastEditTime: 2019-12-12 18:00:03
*/
import './index.scss';
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import SplitPane from 'react-split-pane';
import { Button } from 'antd';
import { Button, Modal } from 'antd';
import {
connect
} from 'react-redux';
import UserInfo from '../../developer/components/userInfo';
import actions from '../../../redux/actions';
import LeftPane from './leftPane';
import RightPane from './rightPane';
function JupyterTPI (props) {
// 获取 identifier 值
@ -24,31 +24,128 @@ function JupyterTPI (props) {
match: {
params = {}
},
getJupyterTpiDataSet,
getJupyterTpiUrl
url,
loading, // 保存按钮状态
jupyter_info,
getJupyterInfo,
syncJupyterCode,
jupyter_tpi_url_state,
// getJupyterTpiDataSet,
getJupyterTpiUrl,
saveJupyterTpi,
changeLoadingState,
changeGetJupyterUrlState
} = props;
const {identifier} = params;
console.log('props: ====>>>>', identifier);
const {identifier} = params;
const [userInfo, setUserInfo] = useState({});
const [jupyterInfo, setJupyterInfo] = useState({});
const [updateTip, setUpdateTip] = useState(true);
const [myIdentifier, setMyIdentifier] = useState('');
useEffect(() => {
// 获取数据集
console.log('useEffect: ====>>>>', identifier);
getJupyterTpiDataSet(identifier);
// 获取jupyter地址
/* 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">
<p className="update_txt">关卡任务的代码文件有更新啦</p>
<p className="update_txt">更新操作将保留已完成的评测记录和成绩</p>
<p className="update_txt">还未完成评测的任务代码请自行保存</p>
</div>),
okText: '确定',
cancelText: '取消',
onOk () {
syncJupyterCode(myshixun_identifier, '同步成功');
}
})
}
}, [props]);
// 重置实训
const handleClickResetTpi = () => {
Modal.confirm({
title: '重置实训',
content: (
<p style={{ lineHeight: '24px' }}>
你在本文件中修改的内容将丢失,<br />
是否确定重新加载初始代码
</p>
),
okText: '确定',
cancelText: '取消',
onOk () {
console.log('调用重置代码....', myIdentifier);
if (myIdentifier) {
syncJupyterCode(myIdentifier, '重置成功');
}
}
})
}
// 退出实训
const handleClickQuitTpi = () => {
// console.log(jupyterInfo);
const { identifier } = jupyterInfo;
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();
}
return (
<div className="jupyter_area">
<div className="jupyter_header">
<UserInfo userInfo={{}} />
<UserInfo userInfo={userInfo} />
<p className="jupyter_title">
<span className="title_desc">MySQL数据库编程开发实训(基础篇)</span>
<span className="title_time">时间</span>
<span className="title_desc" style={{ marginTop: '20px' }}>{jupyterInfo.name}</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>
<Button
className="btn_common"
type="link"
icon="sync"
onClick={handleClickResetTpi}
>重置实训</Button>
<Button
className="btn_common"
type="link"
icon="poweroff"
onClick={handleClickQuitTpi}
>退出实训</Button>
</p>
</div>
<div className="jupyter_ctx">
@ -57,7 +154,14 @@ function JupyterTPI (props) {
<LeftPane dataSets={[]} />
</div>
<SplitPane split="vertical" defaultSize="100%" allowResize={false}>
<div>右侧内容</div>
<RightPane
identifier={myIdentifier}
status={jupyter_tpi_url_state}
url={url}
loading={loading}
onReloadUrl={handleOnReloadUrl}
onSave={handleOnSave}
/>
<div />
</SplitPane>
</SplitPane>
@ -67,17 +171,31 @@ function JupyterTPI (props) {
}
const mapStateToProps = (state) => {
const {jupyter_tpi_url, jupyter_data_set, jupyter_identifier} = state.jupyterReducer;
const {
jupyter_info,
jupyter_tpi_url,
jupyter_data_set,
jupyter_tpi_url_state
} = state.jupyterReducer;
const { loading } = state.commonReducer;
return {
loading,
jupyter_info,
url: jupyter_tpi_url,
dataSets: jupyter_data_set,
identifier: jupyter_identifier
jupyter_tpi_url_state
};
}
const mapDispatchToProps = (dispatch) => ({
getJupyterTpiDataSet: (identifier) => dispatch(actions.getJupyterTpiDataSet(identifier)),
getJupyterTpiUrl: (identifier) => dispatch(actions.getJupyterTpiUrl(identifier))
changeGetJupyterUrlState: (status) => dispatch(actions.changeGetJupyterUrlState(status)),
getJupyterInfo: (identifier) => dispatch(actions.getJupyterInfo(identifier)),
// 重置代码
syncJupyterCode: (identifier, msg) => dispatch(actions.syncJupyterCode(identifier, msg)),
// getJupyterTpiDataSet: (identifier) => dispatch(actions.getJupyterTpiDataSet(identifier)),
getJupyterTpiUrl: (identifier) => dispatch(actions.getJupyterTpiUrl(identifier)),
saveJupyterTpi: () => dispatch(actions.saveJupyterTpi()),
changeLoadingState: (flag) => dispatch(actions.changeLoadingState(flag))
});
export default connect(

@ -55,7 +55,7 @@
height: 60px;
line-height: 60px;
background-color: #070F1A;
padding-left: 30px;
.jupyter_title{
display: flex;
flex-direction: column;
@ -90,4 +90,12 @@
position: relative;
height: calc(100vh - 60px);
}
.update_notice{
text-align: center;
.update_txt{
line-height: 18px;
font-size: 14px;
}
}
}

@ -0,0 +1,90 @@
/*
* @Description:
* @Author: tangjiang
* @Github:
* @Date: 2019-12-12 15:04:20
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-12 17:41:41
*/
import './index.scss';
import React, { useEffect, useState } from 'react';
import { Spin, Button } from 'antd';
function RightPane (props) {
const {
status,
url,
onReloadUrl,
onSave,
loading
} = props;
const [renderCtx, setRenderCtx] = useState(() => loadInit);
// 重新获取 url
const handleClickReload = () => {
onReloadUrl && onReloadUrl();
}
const loadInit = (
<div className="jupyter_loading_init">
<Spin tip="加载中..."></Spin>
</div>
);
const loadError = (
<div className="jupyter_load_url_error">
<p className="jupyter_error_txt">
加载实训出错是否
<span
className="jupyter_reload"
onClick={handleClickReload}
>重新加载</span>
</p>
</div>
);
// 保存
const handleClickSubmit = () => {
console.log('调用了保存接口....');
onSave && onSave();
}
useEffect(() => {
if (status === -1) {
setRenderCtx(() => loadInit);
} else if (status === 0 && url) {
setRenderCtx(() => (
<div className="jupyter_result">
<div className="jupyter_iframe">
<iframe
title=" "
width="100%"
height="100%"
src={url}
className='jupyter_iframe_style'
></iframe>
</div>
<div className="jupyter_submit">
<Button
loading={loading}
type="primary"
onClick={handleClickSubmit}
>保存</Button>
</div>
</div>
));
} else {
setRenderCtx(() => loadError);
}
}, [status, url, loading]);
return (
<div className="jupyter_right_pane_area">
{ renderCtx }
</div>
)
}
export default RightPane;

@ -0,0 +1,62 @@
.jupyter_right_pane_area{
position: relative;
height: calc(100vh - 60px);
// background: pink;
.jupyter_load_url_error,
.jupyter_loading_init{
display: flex;
position: relative;
align-items: center;
justify-content: center;
height: 100%;
&::before{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
content: '';
}
}
.jupyter_loading_init{
&::before{
background-color: rgba(0,0,0,.2);
}
}
.jupyter_load_url_error{
// &::before{
// background-color: rgba(0,0,0,.2);
// }
.jupyter_error_txt{
position: relative;
z-index: 1;
.jupyter_reload{
cursor: pointer;
color: #1890ff;
}
}
}
.jupyter_result{
height: 100%;
.jupyter_iframe{
height: calc(100% - 56px);
// background: pink;
.jupyter_iframe_style{
border: none;
outline: none;
}
}
.jupyter_submit{
display: flex;
align-items: center;
height: 56px;
justify-content: flex-end;
padding-right: 30px;
}
}
}

@ -54,6 +54,9 @@ const types = {
GET_JUPYTER_DATA_SETS: 'GET_JUPYTER_DATA_SETS', // jupyter 数据集
GET_JUPYTER_TPI_URL: 'GET_JUPYTER_TPI_URL', // 获取 jupyter url
SAVE_JUPYTER_IDENTIFIER: 'SAVE_JUPYTER_IDENTIFIER', // 保存jupyter identifier
SAVE_JUPYTER_INFO: 'SAVE_JUPYTER_INFO', // 保存 jupyter 信息
CHANGE_JUPYTER_URL_STATE: 'CHANGE_JUPYTER_URL_STATE', // 获取url返回的状态值
SAVE_JUPYTER_TPI: 'SAVE_JUPYTER_TPI', // 保存 jupyter tpi
}
export default types;

@ -64,7 +64,11 @@ import {
import {
getJupyterTpiDataSet,
getJupyterTpiUrl
getJupyterTpiUrl,
getJupyterInfo,
syncJupyterCode,
changeGetJupyterUrlState,
saveJupyterTpi
} from './jupyter';
export default {
@ -111,6 +115,10 @@ export default {
saveEditorCodeForDetail,
// jupyter
getJupyterTpiDataSet,
getJupyterTpiUrl
getJupyterTpiUrl,
getJupyterInfo,
syncJupyterCode,
changeGetJupyterUrlState,
saveJupyterTpi
// isUpdateCodeCtx
}

@ -4,31 +4,81 @@
* @Github:
* @Date: 2019-12-12 09:01:30
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-12 09:30:53
* @LastEditTime: 2019-12-12 17:58:38
*/
import types from "./actionTypes";
import { fetchJupyterTpiDataSet, fetchJupyterTpiUrl } from "../../services/jupyterServer";
import { message } from 'antd';
import {
fetchJupyterTpiDataSet,
fetchJupyterTpiUrl,
fetchJupyterInfo,
fetchSyncJupyterCode,
fetchSaveJupyterTpi
} from "../../services/jupyterServer";
// 获取 jupyter 相关信息
export const getJupyterInfo = (id) => {
return (dispatch) => {
fetchJupyterInfo(id).then(res => {
if (res.data.status === 401) return;
if (res.status === 200) {
const { data } = res;
console.log(data);
if (data.status === 0) {
dispatch({
type: types.SAVE_JUPYTER_INFO,
payload: data
});
const { identifier, myshixun_identifier } = data;
// 调用获取数据集接口
dispatch(getJupyterTpiDataSet(identifier));
// 调用获取url接口
dispatch(getJupyterTpiUrl({identifier: myshixun_identifier}));
}
}
})
}
}
// 获取 jupyter tpi 数据集
export const getJupyterTpiDataSet = (identifier) => {
return (dispatch) => {
fetchJupyterTpiDataSet(identifier).then(res => {
if (res.data.status === 401) return; // 用户未登录
console.log('数据集:', res);
if (res.status === 200) {
const {data_sets} = res.data;
dispatch({
type: types.GET_JUPYTER_DATA_SETS,
payload: data_sets
});
}
});
}
}
// 获取 jupyter tpi 地址
export const getJupyterTpiUrl = (identifier) => {
return (dispatch) => {
fetchJupyterTpiUrl(identifier).then(res => {
export const getJupyterTpiUrl = (obj) => {
return (dispatch, getState) => {
const {jupyter_info} = getState().jupyterReducer;
console.log(obj.identifier, jupyter_info.myshixun_identifier);
if (!obj.identifier && !jupyter_info.myshixun_identifier) return;
const id = obj.identifier || jupyter_info.myshixun_identifier;
fetchJupyterTpiUrl({identifier: id}).then(res => {
if (res.data.status === 401) return; // 用户未登录
console.log('获取url', res);
if (res.status === 200) {
const { status, url = '', port } = res.data;
dispatch({
type: types.GET_JUPYTER_TPI_URL,
payload: {
status,
url,
port
}
})
}
})
}
}
// 保存 jupyter identifer
export const saveJupyterIdentifier = (identifier) => {
return {
@ -36,3 +86,54 @@ export const saveJupyterIdentifier = (identifier) => {
payload: identifier
}
}
// 重置代码
export const syncJupyterCode = (identifier, msg) => {
return (dispatch) => {
fetchSyncJupyterCode(identifier).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);
}
})
}
}
// 改变状态值
export const changeGetJupyterUrlState = (status) => {
return {
type: types.CHANGE_JUPYTER_URL_STATE,
payload: status
}
}
// 保存 jupyter tpi
export const saveJupyterTpi = () => {
return (dispatch, getState) => {
const { jupyter_tpi_code, jupyter_info }= getState().jupyterReducer;
// console.log(jupyter_info.myshixun_identifier, jupyter_tpi_code);
if (!jupyter_info.myshixun_identifier) return;
const params = {
identifier: jupyter_info.myshixun_identifier,
jupyter_port: jupyter_tpi_code
};
console.log(params);
fetchSaveJupyterTpi(params).then(res => {
dispatch({
type: types.LOADING_STATUS,
payload: false
});
if (res.status === 200) {
const { data } = res;
if (data.status === 0) {
message.success('保存成功!')
}
}
}).catch(() => {
dispatch({
type: types.LOADING_STATUS,
payload: false
});
});
}
}

@ -4,7 +4,7 @@
* @Github:
* @Date: 2019-11-27 16:27:09
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-03 11:00:19
* @LastEditTime: 2019-12-12 17:36:51
*/
import types from "../actions/actionTypes";

@ -4,14 +4,17 @@
* @Github:
* @Date: 2019-12-12 09:01:39
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-12 09:29:49
* @LastEditTime: 2019-12-12 17:23:54
*/
import types from "../actions/actionTypes";
const initState = {
jupyter_tpi_url: '',
jupyter_info: {}, // 保存用户信息及实训相关的内容
jupyter_data_set: [],
jupyter_identifier: ''
jupyter_identifier: '',
jupyter_tpi_url_state: -1, // 获取 url 状态值: 0 成功, 其它 失败
jupyter_tpi_code: '' // 端口号
};
const JupyterReducer = (state = initState, action) => {
@ -22,15 +25,28 @@ const JupyterReducer = (state = initState, action) => {
jupyter_data_set: action.payload
}
case types.GET_JUPYTER_TPI_URL:
const {url, status, port} = action.payload;
return {
...state,
jupyter_tpi_url: action.payload
jupyter_tpi_url: url,
jupyter_tpi_url_state: status,
jupyter_tpi_code: port
}
case types.SAVE_JUPYTER_IDENTIFIER:
return {
...state,
jupyter_identifier: action.payload
}
case types.SAVE_JUPYTER_INFO:
return {
...state,
jupyter_info: action.payload
}
case types.CHANGE_JUPYTER_URL_STATE:
return {
...state,
jupyter_tpi_url_state: action.payload
}
default:
return {
...state

@ -4,10 +4,15 @@
* @Github:
* @Date: 2019-12-12 09:07:07
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-12 09:10:58
* @LastEditTime: 2019-12-12 17:46:17
*/
import axios from 'axios';
// 获取 jupyter实训相关的内容
export async function fetchJupyterInfo (identifier) {
const url = `/tasks/${identifier}/jupyter.json`;
return axios.get(url);
}
// 获取数据集
export async function fetchJupyterTpiDataSet (identifier) {
const url = `/shixuns/${identifier}/jupyter_data_sets.json`;
@ -18,3 +23,13 @@ export async function fetchJupyterTpiUrl (params) {
const url = `/jupyters/get_info_with_tpi.json`;
return axios.get(url, { params });
}
// 同步代码功能
export async function fetchSyncJupyterCode (identifier) {
const url = `/myshixuns/${identifier}/sync_code.json`;
return axios.post(url);
}
// jupyter 保存
export async function fetchSaveJupyterTpi (params) {
const url = `/jupyters/save_with_tpi.json`;
return axios.get(url, { params });
}
Loading…
Cancel
Save