- 计算成绩
+ (this.props.isNotMember()===false?
+ 查看最新成绩
:""):
teacherdata&&teacherdata.homework_status!==undefined&&teacherdata.homework_status[0]=== "未发布"? "":
- (this.props.isNotMember()===false?
- 计算成绩
+ (this.props.isNotMember()===false?
+ 查看最新成绩
:"")
}
}
+ {/* {teacherdata&&teacherdata.task_operation&&teacherdata.task_operation[0]==="开启挑战"?"":
*/}
+ {/*{computeTimetype===true?*/}
+ {/* (this.props.isNotMember()===false?*/}
+ {/* 查看最新成绩*/}
+ {/*
:""):*/}
+ {/* teacherdata&&teacherdata.homework_status!==undefined&&teacherdata.homework_status[0]=== "未发布"? "":*/}
+ {/* (this.props.isNotMember()===false?*/}
+ {/* 查看最新成绩*/}
+ {/*
:"")*/}
+ {/*}*/}
+ {/*}*/}
{/*因为计算按钮占了和这个位置,和设计沟通学生视角取消这个按钮*/}
diff --git a/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js b/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js
index 87f4f9555..c4f5d9a10 100644
--- a/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js
+++ b/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js
@@ -32,7 +32,9 @@ class ShixunWorkReport extends Component {
DownloadMessageval:undefined,
isspinning:false,
showAppraiseModaltype:false,
- work_comment_hidden:false
+ work_comment_hidden:false,
+ showAppraiseModalsshow:true,
+ work_comment:null
}
}
@@ -104,6 +106,7 @@ class ShixunWorkReport extends Component {
this.setState({
data:result.data,
work_comment_hidden:result.data.work_comment_hidden,
+ work_comment:result.data.work_comment,
spinning:false
})
}
@@ -150,26 +153,50 @@ class ShixunWorkReport extends Component {
})
}
- showAppraiseModal=()=>{
- this.setState({
- showAppraiseModaltype:true
- })
+ showAppraiseModal=(sum)=>{
+ if(sum===undefined){
+ this.setState({
+ showAppraiseModaltype:true
+ })
+ }else{
+ this.setState({
+ showAppraiseModaltype:true,
+ work_comment:undefined,
+ work_type:0,
+ })
+
+ }
+
}
hideAppraiseModal=()=>{
- let{data}=this.state;
+ let{data,work_comment}=this.state;
this.setState({
showAppraiseModaltype:false,
- work_comment_hidden:data&&data.work_comment_hidden===true?true:data&&data.work_description!=null?true:false,
+ work_comment_hidden:data&&data.work_comment_hidden===true?true:work_comment!=null?true:false,
+ })
+ }
+ showAppraiseModals=(list,type)=>{
+ let{data,work_comment}=this.state;
+ this.setState({
+ showAppraiseModaltype:false,
+ work_comment_hidden:data&&data.work_comment_hidden===true?true:work_comment!=null?true:false,
+ work_comment:list,
+ work_type:type,
+ showAppraiseModals:true,
+ showAppraiseModalsshow:true
})
}
-
isdeleteModal=()=>{
let url =`/student_works/${this.props.match.params.homeworkid}/destroy_work_comment.json`
axios.delete(url).then((response) => {
// const { status } = response.data;
if(response.data.status===0){
this.props.showNotification(response.data.message)
+ this.setState({
+ showAppraiseModalsshow:false,
+ work_comment_hidden:false
+ })
}else{
this.props.showNotification(response.data.message)
}
@@ -179,15 +206,15 @@ class ShixunWorkReport extends Component {
});
}
render() {
- let{data,showAppraiseModaltype,work_comment_hidden} =this.state;
+ let{data,showAppraiseModaltype,work_comment_hidden,showAppraiseModalsshow,work_comment} =this.state;
let category_id=data===undefined?"":data.category===null?"":data.category.category_id;
let homework_common_id=data===undefined?"":data.homework_common_id;
let homeworkid=this.props.match.params.homeworkid;
const antIcon =
;
- let showAppraiseModals=this.props&&this.props.isAdminOrTeacher()===true?work_comment_hidden===true?true:false:data&&data.work_description===null?false:true;
-
+ let showAppraiseModals=this.props&&this.props.isAdminOrTeacher()===true?work_comment===null||work_comment===undefined?false:true:work_comment===null||work_comment===undefined?false:true;
+ console.log(showAppraiseModals)
return (
data===undefined?"":
@@ -197,6 +224,9 @@ class ShixunWorkReport extends Component {
{...this.state}
visible={showAppraiseModaltype}
Cancel={()=>this.hideAppraiseModal()}
+ showCancel={(list,type)=>this.showAppraiseModals(list,type)}
+ work_comment={this.state.work_comment}
+ work_type={this.state.work_type}
/>:""}
@@ -229,10 +259,14 @@ class ShixunWorkReport extends Component {
className=" color-blue font-14 fr ml20 mt15"
onClick={()=>this.confirmysl(`/student_works/${homeworkid}/export_shixun_work_report.pdf`)}
>
导出实训报告数据 : ""}
- {this.props.isAdmin() ?work_comment_hidden===true? "":
this.showAppraiseModal(1)}*/}
+ {/*>评阅 : ""}*/}
+ {this.props.isAdmin() ?
this.showAppraiseModal()}
- >评阅 : ""}
+ onClick={()=>this.showAppraiseModal(1)}
+ >评阅:""}
@@ -303,23 +341,28 @@ class ShixunWorkReport extends Component {
-
陈晓
+
{data&&data.username}
- 通过: {data&&data.complete_count}/{data&&data.challenges_count}
- 课堂最高完成效率: {data&&data.max_efficiency===null?'--':data&&data.max_efficiency}
- 通关时间: {data&&data.passed_time===null?'--':data&&data.passed_time}
-
-
-
- 经验值: {data&&data.myself_experience}/{data&&data.total_experience}
- 完成效率: {data&&data.efficiency===null?'--':data&&data.efficiency}
- 实战耗时: {data&&data.time_consuming===null?'--':data&&data.time_consuming}
+
+ 通过: {data&&data.complete_count}/{data&&data.challenges_count}
+ 经验值: {data&&data.myself_experience}/{data&&data.total_experience}
+
+
+
+ 课堂最高完成效率: {data&&data.max_efficiency===null?'--':data&&data.max_efficiency}
+ 完成效率: {data&&data.efficiency===null?'--':data&&data.efficiency}
+
+
+
+ 通关时间: {data&&data.passed_time===null?'--':data&&data.passed_time}
+ 实战耗时: {data&&data.time_consuming===null?'--':data&&data.time_consuming}
+
@@ -395,7 +438,7 @@ class ShixunWorkReport extends Component {
- {showAppraiseModals===true?
+ {showAppraiseModals===true&&showAppraiseModalsshow===true?
@@ -415,7 +458,7 @@ class ShixunWorkReport extends Component {
+ dangerouslySetInnerHTML={{__html: markdownToHTML(work_comment).replace(/▁/g, "▁▁▁")}}>
diff --git a/public/react/src/modules/modals/WordNumberTextarea.js b/public/react/src/modules/modals/WordNumberTextarea.js
index 52711de2c..f93dff978 100644
--- a/public/react/src/modules/modals/WordNumberTextarea.js
+++ b/public/react/src/modules/modals/WordNumberTextarea.js
@@ -14,7 +14,7 @@ render() {
onInput={(e)=>this.props.onInput(e)}
maxlength={this.props.maxlength}
/>
-
{this.props.value===undefined?0:this.props.value.length}/{this.props.maxlength}
+
{this.props.value===undefined||this.props.value===null?0:this.props.value.length}/{this.props.maxlength}
)
}
diff --git a/public/react/src/modules/page/Index.js b/public/react/src/modules/page/Index.js
index b2daa27e4..ab0f30e70 100644
--- a/public/react/src/modules/page/Index.js
+++ b/public/react/src/modules/page/Index.js
@@ -219,6 +219,7 @@ class Index extends Component {
praisePlus={context.praisePlus}
+ git_url={context.git_url}
mirror_name={context.mirror_name}
challenge={context.challenge}
myshixun={context.myshixun}
diff --git a/public/react/src/modules/page/MainContent.js b/public/react/src/modules/page/MainContent.js
index 601c002a9..d8623d84b 100644
--- a/public/react/src/modules/page/MainContent.js
+++ b/public/react/src/modules/page/MainContent.js
@@ -13,7 +13,7 @@ import ChooseEvaluateView from './main/ChooseEvaluateView'
import { CircularProgress } from 'material-ui/Progress';
import Button from 'material-ui/Button';
-import VNCDisplay from './VNCDisplay'
+import VNCContainer from './VNCContainer'
import './tpiPage.css';
import './tpiPageForMobile.css';
@@ -94,9 +94,13 @@ class MainContent extends Component {
*/}
- { showIframeContent && vnc_url ?
+ { showIframeContent && vnc_url ?
+
+
+
:
diff --git a/public/react/src/modules/page/VNC.css b/public/react/src/modules/page/VNC.css
new file mode 100644
index 000000000..cf47d7207
--- /dev/null
+++ b/public/react/src/modules/page/VNC.css
@@ -0,0 +1,17 @@
+.float_button {
+ background-image: url(./images/float_switch.jpg);
+ height: 112px;
+ width: 38px;
+ position: absolute;
+ left: -38px;
+ top: 32%;
+ cursor: pointer;
+}
+.float_button .text {
+ position: relative;
+ writing-mode: vertical-rl;
+ top: 36px;
+ color: #fff;
+ left: 13px;
+ user-select: none;
+}
\ No newline at end of file
diff --git a/public/react/src/modules/page/VNCContainer.js b/public/react/src/modules/page/VNCContainer.js
new file mode 100644
index 000000000..e0e3616e0
--- /dev/null
+++ b/public/react/src/modules/page/VNCContainer.js
@@ -0,0 +1,184 @@
+import React, { Component } from 'react';
+import axios from 'axios'
+import { Spin } 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 './VNC.css'
+const $ = window.$;
+const firstDrawerWidth = 260;
+class VNCContainer extends Component {
+ constructor(props) {
+ super(props)
+
+ this.state = {
+ fileTreeSelectedKeys: [],
+ repositoryCode: ''
+ }
+ }
+ componentDidMount() {
+ if (!this.clipboard) {
+ const clipboard = new ClipboardJS('.copybtn');
+ clipboard.on('success', (e) => {
+ this.props.showSnackbar('复制成功')
+ });
+ this.clipboard = clipboard
+ }
+
+ }
+ getSecondDrawerWidth = () => {
+ return $('#game_right_contents').width() - firstDrawerWidth
+ }
+ renderSecondDrawerChildren = () => {
+ const { readingCodeLoading, repositoryCode } = this.state;
+ const height = $(window).height() - 130
+
+ const isEditablePath = false;
+ return (
+
+
+ );
+ }
+ fetchReadRepositoryCode = (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.props.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 == 'doc' || filetype == 'pdf' || filetype == 'xsl' || filetype == 'ppt') {
+ this.props.showSnackbar(`不支持加载${filetype}类型的文件。`)
+ return;
+ }
+ this.fetchReadRepositoryCode(nodePath);
+ } else {
+ console.error('no eventKey:', info.node)
+ }
+ }
+ }
+ /*
+ selectedKeys={fileTreeSelectedKeys}
+ onSelect={onTreeSelect}
+ */
+ render() {
+ const { challenge, vnc_url, git_url } = this.props
+
+ const secondDrawerChildren = this.renderSecondDrawerChildren();
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+export default VNCContainer;
diff --git a/public/react/src/modules/page/component/FloatButton.js b/public/react/src/modules/page/component/FloatButton.js
new file mode 100644
index 000000000..1b9e191f2
--- /dev/null
+++ b/public/react/src/modules/page/component/FloatButton.js
@@ -0,0 +1,24 @@
+import React, { Component } from 'react';
+
+const $ = window.$;
+class FloatButton extends Component {
+ componentDidMount() {
+
+
+ }
+
+ render() {
+ const { challenge, vnc_url, children } = this.props
+
+ return (
+
+
+ {children || '版本库'}
+
+ );
+ }
+}
+
+export default FloatButton;
diff --git a/public/react/src/modules/page/component/SecondDrawer.js b/public/react/src/modules/page/component/SecondDrawer.js
new file mode 100644
index 000000000..db520e80e
--- /dev/null
+++ b/public/react/src/modules/page/component/SecondDrawer.js
@@ -0,0 +1,100 @@
+import React from "react";
+import ReactDOM from "react-dom";
+import { Drawer } from "antd";
+import FloatButton from './FloatButton'
+import PropTypes from 'prop-types';
+
+class SecondDrawer extends React.Component {
+ state = { visible: false, childrenDrawer: false };
+
+ showDrawer = () => {
+ this.setState({
+ visible: true
+ });
+ };
+
+ onClose = () => {
+ this.setState({
+ visible: false
+ });
+ };
+
+ showSecondDrawer = () => {
+ this.setState({
+ childrenDrawer: true
+ });
+ };
+
+ onChildrenDrawerClose = () => {
+ this.setState({
+ childrenDrawer: false
+ });
+ };
+
+ swtichFirstDrawer = () => {
+ this.setState({
+ visible: !this.state.visible,
+ childrenDrawer: false
+ });
+ };
+ componentDidMount() {
+ this.setState({ visible: true }, () => {
+ this.setState({ visible: false });
+ });
+ }
+ render() {
+ const { floatText, maskClosable, children, secondDrawerChildren, firstDrawerWidth, getSecondDrawerWidth
+ ,firstDrawerClassName, secondDrawerClassName
+ } = this.props
+ const secondDrawerWidth = getSecondDrawerWidth();
+ // 180 不知道为什么会偏移 180px
+ return (
+
+ {/* */}
+ {floatText}
+ { children }
+
+
+ { secondDrawerChildren }
+ {/* */}
+
+
+ );
+ }
+}
+
+SecondDrawer.propTypes = {
+ floatText: PropTypes.string,
+ maskClosable: PropTypes.bool,
+ secondDrawerChildren: PropTypes.element,
+};
+// firstDrawerWidth={firstDrawerWidth}
+// getSecondDrawerWidth={this.getSecondDrawerWidth}
+export default SecondDrawer
\ No newline at end of file
diff --git a/public/react/src/modules/page/component/monaco/TPIMonaco.js b/public/react/src/modules/page/component/monaco/TPIMonaco.js
index 83d55915e..54763174e 100644
--- a/public/react/src/modules/page/component/monaco/TPIMonaco.js
+++ b/public/react/src/modules/page/component/monaco/TPIMonaco.js
@@ -271,6 +271,7 @@ class TPIMonaco extends Component {
const lang = getLanguageByMirrorName(this.props.mirror_name);
const editor = window.monaco.editor.create(document.getElementById('extend-challenge-file-edit'), {
value: value,
+ readOnly: !this.props.isEditablePath,
// 属性说明
// http://testeduplus2.educoder.net/react/build/static/node_modules/_monaco-editor@0.15.6@monaco-editor/esm/vs/editor/common/config/commonEditorConfig.js
// https://github.com/Microsoft/monaco-editor/issues/29
@@ -303,7 +304,7 @@ class TPIMonaco extends Component {
notCallCodeMirrorOnChangeFlag = false
return;
}
- this.props.onRepositoryCodeUpdate(editor.getValue())
+ this.props.onRepositoryCodeUpdate && this.props.onRepositoryCodeUpdate(editor.getValue())
})
this.props.codemirrorDidMount && this.props.codemirrorDidMount()
diff --git a/public/react/src/modules/page/component/repo/RepoTree.js b/public/react/src/modules/page/component/repo/RepoTree.js
new file mode 100644
index 000000000..fbf1286c3
--- /dev/null
+++ b/public/react/src/modules/page/component/repo/RepoTree.js
@@ -0,0 +1,54 @@
+import React, { useState, useEffect, useContext, useRef, memo } from 'react';
+
+// import { Tree } from 'antd';
+// const { TreeNode } = Tree;
+import Tree, { TreeNode } from 'rc-tree';
+import 'rc-tree/assets/index.css';
+
+const $ = window.$;
+export default function RepoTree(props) {
+ const { fileTreeData, onLoadData, onTreeSelect, fileTreeSelectedKeys, loadRepoFiles } = props;
+ const [expandedKeys, setExpandedKeys] = useState([])
+ useEffect(() => {
+ loadRepoFiles()
+ }, [])
+
+ if (!fileTreeData || fileTreeData.length === 0) {
+ return ""
+ }
+
+ const onExpand = (expandedKeys) => {
+ // console.log('onExpand', arguments);
+ // if not set autoExpandParent to false, if children expanded, parent can not collapse.
+ // or, you can remove all expanded children keys.
+ setExpandedKeys(expandedKeys)
+ }
+
+ const loop = (data) => {
+ return data.map((item) => {
+ if (item.children) {
+ return {loop(item.children)};
+ }
+ return (
+
+ );
+ });
+ };
+ const treeNodes = loop(fileTreeData);
+
+
+ // selectable={false}
+ return (
+
+ {treeNodes}
+
+ )
+}
diff --git a/public/react/src/modules/page/images/float_switch.jpg b/public/react/src/modules/page/images/float_switch.jpg
new file mode 100644
index 000000000..12fc6f878
Binary files /dev/null and b/public/react/src/modules/page/images/float_switch.jpg differ
diff --git a/public/react/src/modules/page/main/CodeRepositoryViewContainer.js b/public/react/src/modules/page/main/CodeRepositoryViewContainer.js
index 8efe7b0e1..0a5be59e0 100644
--- a/public/react/src/modules/page/main/CodeRepositoryViewContainer.js
+++ b/public/react/src/modules/page/main/CodeRepositoryViewContainer.js
@@ -101,6 +101,11 @@ class CodeRepositoryViewContainer extends Component {
drawerOpen: open,
})
}
+ loadRepoFiles = () => {
+ if (!this.state.fileTreeData) {
+ this.fetchRepoFiles();
+ }
+ }
componentWillReceiveProps(newProps, oldProps) {
@@ -269,18 +274,34 @@ class CodeRepositoryViewContainer extends Component {
}
// /shixuns/mnf6b7z3/shixun_discuss?challenge_id=88
render() {
-
+
return (
-
+ {this.props.isOnlyContainer == true ?
+ React.Children.map(this.props.children, child => {
+ if(!child) {
+ return ''
+ }
+ return React.cloneElement(child, Object.assign({...this.state}, {
+ loadRepoFiles: this.loadRepoFiles,
+ onTreeSelect: this.onTreeSelect,
+ onLoadData: this.onLoadData,
+ }))
+ })
- >
+ :
+
+ }
+
);
}
}