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/page/VNCContainer.js

367 lines
11 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.

import React, { Component } from 'react';
import axios from 'axios'
import { Spin, Icon } from 'antd'
import ClipboardJS from 'clipboard'
import VNCDisplay from './VNCDisplay'
import FloatButton from './component/FloatButton'
import SecondDrawer from './component/SecondDrawer'
import RepoTree from './component/repo/RepoTree'
import TPIMonaco from './component/monaco/TPIMonaco'
import notEditablePathImg from '../../images/tpi/notEditablePath.png'
import { Drawer } from "antd";
import './VNC.css'
const $ = window.$;
const firstDrawerWidth = 260;
class VNCContainer extends Component {
constructor(props) {
super(props)
this.state = {
fileTreeSelectedKeys: [],
repositoryCode: '',
displayKey: 1,
vnc_reseting: false,
saving: false,
}
}
componentDidMount() {
if (!this.clipboard) {
const clipboard = new ClipboardJS('.copybtn');
clipboard.on('success', (e) => {
this.props.showSnackbar('复制成功')
});
this.clipboard = clipboard
}
}
// shouldComponentUpdate () {
// return false;
// }
getSecondDrawerWidth = () => {
return $('#game_right_contents').width() - firstDrawerWidth
}
onEditBlur = () => {
console.log('blurblur')
this.doFileUpdateRequestOnCodeMirrorBlur()
}
doFileUpdateRequestOnCodeMirrorBlur = () => {
if (!this.currentPath) {
console.error('未找到文件path')
return;
}
const { myshixun, game } = this.props
var url = `/myshixuns/${myshixun.identifier}/update_file.json`
const codeContent = window.editor_monaco.getValue()
this.setState({saving: true})
axios.post(url, {
content: codeContent,
// 评测的时候传1其它情况不用传主要是为了区分是用户自己提交还是自动提交
// evaluate: 0,
game_id : game.id,
path: this.currentPath
}
).then(res => {
this.setState({saving: false})
}).catch(e => {
this.setState({saving: false})
console.error('update_file error')
})
}
renderSecondDrawerChildren = () => {
const { readingCodeLoading, repositoryCode, saving } = this.state;
const { shixun } = this.props
const height = $(window).height() - 130
const isEditablePath = false;
return (
<Spin tip={saving ? "保存中..." : "加载中..."} spinning={readingCodeLoading || saving}>
<div style={{ height: `${height}px` }}>
{/* (isEditablePath ? 'none' : 'block') */}
<div className="codemirrorBackground"
style={{ backgroundImage: `url('${notEditablePathImg}')`, display: (shixun.code_edit_permission ? 'none' : 'block') }}></div>
<TPIMonaco
{...this.state}
codeLoading={readingCodeLoading}
repositoryCode={repositoryCode}
isEditablePath={shixun.code_edit_permission}
shixun={this.props.shixun}
doFileUpdateRequestOnCodeMirrorBlur={this.doFileUpdateRequestOnCodeMirrorBlur}
onEditBlur={this.onEditBlur}
></TPIMonaco>
</div>
</Spin>);
}
fetchReadRepositoryCode = (path) => {
this.currentPath = path;
const status = 1
const fetchRepoCodeUrl = `/tasks/${this.props.game.identifier}/rep_content.json?path=${path}&status=${status}`
this.setState({ readingCodeLoading: true });
axios.get(fetchRepoCodeUrl, {
}).then((fetchReadRepositoryCodeResponse) => {
if (fetchReadRepositoryCodeResponse.data.content || fetchReadRepositoryCodeResponse.data.content == "") {
this.setState({
repositoryCode: fetchReadRepositoryCodeResponse.data.content,
readingCodeLoading: false
})
} else {
this.setState({ readingCodeLoading: false });
}
// this.setState({ isEditablePath, currentPath: path });
}).catch(error =>{
console.log(error)
this.setState({ readingCodeLoading: false });
this.props.showSnackbar(`服务端异常,请联系管理员!`);
})
}
onTreeSelect = (selectedKeys, info) => {
const isLeaf = info.node.isLeaf();
if (isLeaf) { // 叶子节点
selectedKeys.length && this.setState({
fileTreeSelectedKeys: selectedKeys
})
this.refs["secondDrawer"].showSecondDrawer()
console.log('leaf clicked')
const nodePath = info.node.props.eventKey;
if (nodePath) {
const filetype = nodePath.split('.').pop().toLowerCase();
if (filetype == 'jpg' || filetype == 'png' || filetype == 'gif' || filetype == 'jpeg'
|| filetype == 'jar' || filetype == 'exe'
|| filetype == 'doc' || filetype == 'pdf' || filetype == 'xsl' || filetype == 'ppt') {
this.props.showSnackbar(`不支持加载${filetype}类型的文件。`)
return;
}
this.fetchReadRepositoryCode(nodePath);
} else {
console.error('no eventKey:', info.node)
}
}
}
onBottomDrawerClose = () => {
this.setState({ bottomDrawer: false })
}
swtichBottomDrawer = () => {
this.setState({ bottomDrawer: !this.state.bottomDrawer })
}
showCodeEvaluate = () => {
this.setState({ bottomDrawer: true })
}
onResetVNC = () => {
if (this.state.vnc_reseting) return;
// 桌面系统将恢复到初始状态,您在系统中创建的数据可能会丢失
// 请确保您的数据已保存(如:版本库代码已推送到服务器)
// 是否确认重置?
this.props.confirm({
content: <div style={{textAlign: 'center'}}>
<div>桌面系统将恢复到初始状态您在系统中创建的数据可能会丢失</div>
<div>请确保您的数据已保存版本库代码已推送到服务器</div>
<div>是否确认重置</div>
</div>,
onOk: () => {
const url = `/tasks/${this.props.game.identifier}/reset_vnc_link.json`
this.setState({ vnc_reseting: true })
axios.get(url, {
}).then((response) => {
if (response.data.data && response.data.data.vnc_url) {
// reset
this.setState({
displayKey: this.state.displayKey + 1,
vnc_url: response.data.data.vnc_url,
vnc_reseting: false
})
} else {
}
// this.setState({ isEditablePath, currentPath: path });
}).catch(error =>{
console.log(error)
this.setState({ vnc_reseting: false });
this.props.showSnackbar(`服务端异常,请联系管理员!`);
})
console.log('doooo')
},
onCancel() {
console.log('Cancel');
},
})
}
/*
selectedKeys={fileTreeSelectedKeys}
onSelect={onTreeSelect}
*/
render() {
const { challenge, vnc_url, git_url } = this.props
const secondDrawerChildren = this.renderSecondDrawerChildren();
return (
<React.Fragment>
<SecondDrawer
ref="secondDrawer"
floatText={'版本库'}
maskClosable={false}
secondDrawerChildren={secondDrawerChildren}
firstDrawerWidth={firstDrawerWidth}
getSecondDrawerWidth={this.getSecondDrawerWidth}
firstDrawerClassName="repoFilesDrawer vncDrawer"
secondDrawerClassName="codeInDrawer"
>
<style>{`
/* 评测结果 */
.codeEvaluateDrawer #game_test_set_results {
height: 198px;
}
.codeEvaluateDrawer .ant-drawer-body {
padding: 0px;
}
.codeEvaluateDrawer .ant-drawer-content-wrapper, .codeEvaluateDrawer .ant-drawer-mask {
position: absolute;
}
.codeEvaluateFloatButton {
bottom: 180px !important;
left: unset;
right: 0px;
top: unset;
}
.codeEvaluateFloatButton .text {
left: 10px;
}
.vncDrawer .ant-drawer-body {
padding: 0px;
}
.vncDrawer .rc-tree {
padding: 16px;
max-width: 220px;
color: #CBCBCB;
}
.vncDrawer .ant-drawer-wrapper-body {
background: #242324;
}
.codeInDrawer .ant-drawer-wrapper-body {
background: #1D1C1D;
}
.vncDrawer .ant-drawer-header, .codeInDrawer .ant-drawer-header {
border-bottom: 0;
}
.vncDrawer > div:nth-child(1) {
opacity: 1 !important;
}
.vncDrawer > div:nth-child(2) {
top: 0px !important;
height: 100% !important;
min-width: unset;
}
.codeInDrawer .ant-spin-nested-loading > div > .ant-spin .ant-spin-text {
text-shadow: none;
}
.resetVNC {
top: 30px;
writing-mode: initial;
left: calc(100% - 120px);
background-image: none;
width: auto;
background: #081516;
height: 30px;
padding: 0 6px;
border-radius: 4px;
}
.resetVNC .text {
top: 0px;
writing-mode: initial;
left: unset;
}
.resetVNC .text span {
vertical-align: middle;
margin-left: 2px;
}
.float_button:hover .text {
color: #4CACFF;
}
`}</style>
<div style={{ 'padding': '16px', 'border-bottom': '1px solid #3A383A' }}>
<div style={{ color: '#888888' }}>网址克隆</div>
<div>
<input value={git_url} readonly={true} style={{ color: '#BABABA', width: '203px', background: 'transparent', border: 'none' }}></input>
<i class="iconfont icon-fuzhi font-14 ml10 copybtn"
style={{color: '#4CACFF', cursor: 'pointer', verticalAlign: 'baseline'}} data-clipboard-text={git_url} ></i>
</div>
</div>
<RepoTree
{...this.props}
fileTreeSelectedKeys={this.state.fileTreeSelectedKeys}
onTreeSelect={this.onTreeSelect}
></RepoTree>
</SecondDrawer>
<FloatButton className="resetVNC" onClick={this.onResetVNC}>
{/* <i className="iconfont icon-zhongzhi2 font-16 "></i> */}
{this.state.vnc_reseting ? <Icon type="loading" style={{verticalAlign: 'sub'}} />
: <i className="iconfont icon-zhongzhi2 font-16 "></i>}
<span>重置桌面系统</span>
</FloatButton>
{/* <Spin tip="加载中..." spinning={this.state.vnc_reseting}>
</Spin> */}
<VNCDisplay
{...this.props}
key={this.state.displayKey}
vnc_url={this.state.vnc_url || this.props.vnc_url}
>
<Spin tip="加载中..." spinning={this.state.vnc_reseting}>
</Spin>
<Drawer
mask={true}
title=""
width={firstDrawerWidth}
closable={false}
onClose={this.onBottomDrawerClose}
visible={this.state.bottomDrawer===undefined?false:this.state.bottomDrawer}
className={'codeEvaluateDrawer'}
placement="bottom"
getContainer={false}
style={{ position: 'absolute', bottom: '-25px', zIndex: 1 }}
afterVisibleChange={(visible) => {
if (visible) {
const canvas = $('.vncDisply canvas')[0]
canvas && canvas.focus()
}
}}
>
{ this.props.codeEvaluate }
</Drawer>
<FloatButton onClick={this.swtichBottomDrawer}
className="codeEvaluateFloatButton"
>测试集</FloatButton>
</VNCDisplay>
</React.Fragment>
);
}
}
export default VNCContainer;