From ae4a4a2f9927413f76017926c6588939e55e015f Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Thu, 12 Dec 2019 08:49:50 +0800
Subject: [PATCH 1/9] add author

---
 public/react/src/modules/developer/DeveloperHome.js    | 10 ++++++++--
 .../react/src/modules/developer/studentStudy/index.js  |  4 ++--
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/public/react/src/modules/developer/DeveloperHome.js b/public/react/src/modules/developer/DeveloperHome.js
index 178e13ef5..6ca297f80 100644
--- a/public/react/src/modules/developer/DeveloperHome.js
+++ b/public/react/src/modules/developer/DeveloperHome.js
@@ -421,6 +421,7 @@ class DeveloperHome extends React.PureComponent {
     // const { testReducer, handleClick } = this.props;
     const { 
       ojListReducer: {hacks_list, top_data, hacks_count},
+      user,
       pagination
     } = this.props;
     const {passed_count = 0, simple_count = 0, medium_count = 0, diff_count = 0} = top_data;
@@ -443,7 +444,11 @@ class DeveloperHome extends React.PureComponent {
           >{ctx}</Tag>
       )});
     };
-
+    // console.log('=====>>>>>>>>>.', this.props);
+    
+    const newBtnStyle = user && (user.admin || (user.is_teacher && user.professional_certification) || user.business)
+      ? { display: 'block'} 
+      : { display: 'none'};
     return (
       <div className="developer-list">
         <div className="ant-spin-container">
@@ -457,7 +462,8 @@ class DeveloperHome extends React.PureComponent {
                   <MultipTags type="warning" text="中等" numb={medium_count} style={{ marginRight: '20px' }}/>
                   <MultipTags type="error" text="困难" numb={diff_count}/>
                 </div>
-                <Button type="primary" onClick={this.handleClickNew}>新建
+                {/* 认证的老师, 超级管理员, 运营人员可见 */}
+                <Button style={ newBtnStyle } type="primary" onClick={this.handleClickNew}>新建
                   {/* <Link to="/problems/new">新建</Link> */}
                 </Button>
               </div>
diff --git a/public/react/src/modules/developer/studentStudy/index.js b/public/react/src/modules/developer/studentStudy/index.js
index e218092a0..91ad6778f 100644
--- a/public/react/src/modules/developer/studentStudy/index.js
+++ b/public/react/src/modules/developer/studentStudy/index.js
@@ -4,7 +4,7 @@
  * @Github: 
  * @Date: 2019-11-23 10:53:19
  * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-10 19:16:18
+ * @LastEditTime: 2019-12-11 17:35:49
  */
 import './index.scss';
 import React, { useEffect } from 'react';
@@ -70,7 +70,7 @@ const StudentStudy = (props) => {
         </div>
         <div className={'study_quit'}>
           {/* to={`/problems/${_hack_id}/edit`} */}
-          <span onClick={handleClickEditor} className="quit-btn">
+          <span onClick={handleClickEditor} className={`quit-btn`}>
             <Icon type="form" className="quit-icon"/> 编辑
           </span>
           {/* to="/problems" */}

From a99b4d3aac095c0932922a0ac4399d9b0fc669f8 Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Thu, 12 Dec 2019 20:10:57 +0800
Subject: [PATCH 2/9] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BB=A3=E7=A0=81?=
 =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=8F=90=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../modules/developer/studentStudy/index.js   | 54 +++++++++++++++++--
 1 file changed, 49 insertions(+), 5 deletions(-)

diff --git a/public/react/src/modules/developer/studentStudy/index.js b/public/react/src/modules/developer/studentStudy/index.js
index 91ad6778f..923017ffa 100644
--- a/public/react/src/modules/developer/studentStudy/index.js
+++ b/public/react/src/modules/developer/studentStudy/index.js
@@ -4,10 +4,10 @@
  * @Github: 
  * @Date: 2019-11-23 10:53:19
  * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-11 17:35:49
+ * @LastEditTime: 2019-12-12 19:08:24
  */
 import './index.scss';
-import React, { useEffect } from 'react';
+import React, { useEffect, useState } from 'react';
 import { connect } from 'react-redux';
 import SplitPane from 'react-split-pane';
 import LeftPane from './leftpane';
@@ -15,18 +15,22 @@ import RightPane from './rightpane';
 // import { Link } from 'react-router-dom';
 // import { getImageUrl } from 'educoder'
 // import RightPane from '../newOrEditTask/rightpane';
-import { Icon } from 'antd';
+import { Icon, Modal } from 'antd';
 import UserInfo from '../components/userInfo';
 import actions from '../../../redux/actions';
 import { fromStore} from 'educoder';
 import { withRouter } from 'react-router';
 
-const StudentStudy = (props) => {
+function StudentStudy (props) {
 
   const {
     userInfo,
     hack_identifier
   } = props;
+  
+  // 是否更新
+  const [isUpdate, setIsUpdate] = useState(true);
+
   useEffect(() => {
     const {
       match: { params }, 
@@ -35,13 +39,53 @@ const StudentStudy = (props) => {
     } = props;
 
     let { id } = params;
-    // console.log(id);
     // 保存当前的id
     saveUserProgramIdentifier(id);
     // startProgramQuestion(id);
     getUserProgramDetail(id);
   }, []);
 
+  useEffect(() => {
+    console.log('=======>>>>>>>>');
+    const { hack = {} } = props;
+    if (!hack.modify_code && isUpdate) { // 代码更改,提示是否需要更新代码
+      setIsUpdate(false);
+      Modal.confirm({
+        title: '提示',
+        content: (
+          <p>
+            代码文件有更新啦 <br />
+            还未提交的代码,请自行保存
+          </p>
+        ),
+        okText: '立即更新',
+        cancelText: '稍后再说',
+        onOk () {
+          console.log('更新代码....');
+        }
+      });
+    }
+  }, [props]);
+  // useEffect(() => {
+  //   const {hack} = props; 
+  //   if (!hack.modify_code) { // 代码更改,提示是否需要更新代码
+  //     Modal.confirm({
+  //       title: '提示',
+  //       content: (
+  //         <p>
+  //           代码文件有更新啦 <br />
+  //           还未提交的代码,请自行保存
+  //         </p>
+  //       ),
+  //       okText: '立即更新',
+  //       cancelText: '稍后再说',
+  //       onOk () {
+  //         console.log('更新代码....');
+  //       }
+  //     });
+  //   }
+  // }, [props]);
+
   const _hack_id = hack_identifier || fromStore('hack_identifier');
 
   // 处理编辑

From 806630e1e46ceee14a4099eaa901196e22fe01cb Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Fri, 13 Dec 2019 10:55:35 +0800
Subject: [PATCH 3/9] add author

---
 .../src/common/components/ModalConfirm.js     |  30 +++++
 .../src/modules/developer/DeveloperHome.js    |  24 +++-
 .../modules/developer/newOrEditTask/index.js  |  70 +++++++-----
 public/react/src/redux/actions/index.js       |   2 +
 public/react/src/redux/actions/ojForm.js      | 104 ++++++++++--------
 public/react/src/services/ojService.js        |   8 +-
 6 files changed, 160 insertions(+), 78 deletions(-)
 create mode 100644 public/react/src/common/components/ModalConfirm.js

diff --git a/public/react/src/common/components/ModalConfirm.js b/public/react/src/common/components/ModalConfirm.js
new file mode 100644
index 000000000..bb29fed03
--- /dev/null
+++ b/public/react/src/common/components/ModalConfirm.js
@@ -0,0 +1,30 @@
+/*
+ * @Description: 
+ * @Author: tangjiang
+ * @Github: 
+ * @Date: 2019-12-13 10:28:15
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-12-13 10:37:17
+ */
+import { Modal } from 'antd';
+
+export function ModalConfirm (
+  title, 
+  content,
+  handleOk,
+  handleCancel
+) {
+
+  Modal.confirm({
+    title,
+    content,
+    okText: '确定',
+    cancelText: '取消',
+    onOk () {
+      handleOk && handleOk();
+    },
+    onCancel () {
+      handleCancel && handleCancel();
+    }
+  });
+}
diff --git a/public/react/src/modules/developer/DeveloperHome.js b/public/react/src/modules/developer/DeveloperHome.js
index 6ca297f80..5f787659e 100644
--- a/public/react/src/modules/developer/DeveloperHome.js
+++ b/public/react/src/modules/developer/DeveloperHome.js
@@ -44,6 +44,13 @@ const maps = {
       'value': '2'
     }
   ],
+  'languageMenu': [
+    {
+      'key': 'c',
+      'name': 'C语言',
+      'value': 'c'
+    }
+  ],
   'difficultMenu': [
     { 
       'key': '1',
@@ -119,15 +126,14 @@ class DeveloperHome extends React.PureComponent {
         >
           {/* <Link to={`/problems/${record.identifier}/edit`}></Link> */}
         </Button>
-          <Button
+        <Button
           shape="circle" 
           type="danger"
           icon="close"
           size="small"
-          style={{ marginLeft: '10px' }}
+          style={{ marginLeft: '10px', display: record.open_or_not ? 'none' : 'inline-block' }}
           onClick={() => this.handleClickDelete(record)}
         >
-          {/* <Link to={`/problems/${record.identifier}/edit`}></Link> */}
         </Button>
       </React.Fragment>
     ),
@@ -197,7 +203,6 @@ class DeveloperHome extends React.PureComponent {
   componentDidMount() {
     // 是否是我的,如果是我的 显示编辑按钮
     const { isMySource } = this.props;
-    console.log(this.props);
     if (isMySource) {
       this.handleFilterSearch({come_from: 'mine'});
       let _columns = this.columns.concat([this.options]);
@@ -346,6 +351,14 @@ class DeveloperHome extends React.PureComponent {
     });
     this.handleFilterSearch({category: +item.key === 0 ? '' : +item.key});
   }
+  // 下拉语言
+  handleLanguageMenuClick = (item) => {
+    this.addShowFilterCtx({
+      type: 'language',
+      key: item.key
+    });
+    this.handleFilterSearch({language: item.key})
+  }
   // 难度下拉
   handleHardMenuClick = (item) => {
     this.addShowFilterCtx({
@@ -474,6 +487,9 @@ class DeveloperHome extends React.PureComponent {
                   <Dropdown className={'dropdonw-style'} placement="bottomLeft" overlay={this.getMenuItems('categoryMenu', this.handleCategoryMenuClick)}>
                     <span className={'dropdown-span'}>分类 <Icon type="down"/></span>
                   </Dropdown>
+                  <Dropdown className={'dropdonw-style'} placement="bottomLeft" overlay={this.getMenuItems('languageMenu', this.handleLanguageMenuClick)}>
+                    <span className={'dropdown-span'}>语言 <Icon type="down"/></span>
+                  </Dropdown>
                   <Dropdown className={'dropdonw-style'} placement="bottomLeft" overlay={this.getMenuItems('difficultMenu', this.handleHardMenuClick)}>
                     <span className={'dropdown-span'}>难度 <Icon type="down"/></span>
                   </Dropdown>
diff --git a/public/react/src/modules/developer/newOrEditTask/index.js b/public/react/src/modules/developer/newOrEditTask/index.js
index 6ffe46985..e750cee0a 100644
--- a/public/react/src/modules/developer/newOrEditTask/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/index.js
@@ -9,7 +9,7 @@ import './index.scss';
 import React, { useEffect } from 'react';
 import { connect } from 'react-redux';
 import SplitPane from 'react-split-pane';// import { Form } from 'antd';
-import { Button } from 'antd';
+import { Button, Modal } from 'antd';
 import LeftPane from './leftpane';
 import RightPane from './rightpane';
 import { withRouter } from 'react-router';
@@ -17,6 +17,7 @@ import { toStore } from 'educoder';
 import UserInfo from '../components/userInfo';
 // import RightPane from './rightpane/index';
 import actions from '../../../redux/actions';
+import {ModalConfirm} from '../../../common/components/ModalConfirm';
 
 const NewOrEditTask = (props) => {
   const { 
@@ -32,17 +33,18 @@ const NewOrEditTask = (props) => {
     changePublishLoadingStatus,
     startProgramQuestion,
     getUserInfoForNew,
+    handleCancelPublish,
     // updateTestAndValidate,
   } = props;
   
   // 表单提交
   const handleSubmitForm = () => {
+    // 改变loading状态
+    changeSubmitLoadingStatus(true);
     // 调用输入表单验证功能
     if (props.identifier) {
       props.handleUpdateOjForm(props);
     } else {
-      // 改变loading状态
-      changeSubmitLoadingStatus(true);
       props.handleFormSubmit(props); // 提交表单
     }
   };
@@ -66,6 +68,9 @@ const NewOrEditTask = (props) => {
   }, []);
 
   // 模拟挑战
+  const imitationChallenge = () => {
+  }
+  // 开始挑战
   const startChallenge = () => {
     // 调用 start 接口, 成功后跳转到模拟页面
     startProgramQuestion(identifier, props);
@@ -84,9 +89,20 @@ const NewOrEditTask = (props) => {
 
   // 发布
   const handleClickPublish = () => {
-    // console.log('public has click');
-    changePublishLoadingStatus(true);
-    handlePublish(props, 'publish');
+    ModalConfirm('提示', (<p>发布后即可应用到自己管理的课堂<br /> 是否确认发布?</p>), () => {
+      changePublishLoadingStatus(true);
+      handlePublish(props, 'publish');
+    });
+
+
+  }
+  // 撤销发布
+  const handleClickCancelPublish = () => {
+    ModalConfirm('提示', (<p>是否确认撤销发布?</p>), () => {
+      changePublishLoadingStatus(true);
+      handleCancelPublish(props, identifier);
+    });
+    
   }
 
   // 取消保存/取消按钮
@@ -107,11 +123,23 @@ const NewOrEditTask = (props) => {
   }
   // 发布/模拟挑战
   const renderPubOrFight = () => {
-    const pubButton = isPublish ? '' : (<Button 
-        type="primary" 
-        loading={publishLoading}
-        onClick={handleClickPublish}
-      >立即发布</Button>);
+    const pubButton = isPublish
+     ? (<Button 
+          type="primary" 
+          loading={publishLoading}
+          onClick={handleClickCancelPublish}
+       >撤销发布</Button>)
+     : (<Button 
+          type="primary" 
+          loading={publishLoading}
+          onClick={handleClickPublish}
+       >立即发布</Button>);
+    // 未发布: 模拟挑战 已发布: 开始挑战
+    const challengeBtn = isPublish ? (
+      <Button type="primary" onClick={startChallenge}>开始挑战</Button>
+    ) : (
+      <Button type="primary" onClick={imitationChallenge}>模拟挑战</Button>
+    );
     return (
       <React.Fragment>
         <Button 
@@ -120,7 +148,8 @@ const NewOrEditTask = (props) => {
           onClick={handleSubmitForm}
         >更新</Button>
         {pubButton}
-        <Button type="primary" onClick={startChallenge}>模拟挑战</Button>
+        {challengeBtn}
+        {/* <Button type="primary" onClick={startChallenge}>模拟挑战</Button> */}
       </React.Fragment>
     )
   }
@@ -142,24 +171,9 @@ const NewOrEditTask = (props) => {
   return (
     <div className={'new_add_task_wrap'}>
       <div className={'task_header'}>
-        {/* <Link to="/problems" className={'header_btn'} >
-          <Icon type="left" style={{ marginRight: '5px'}}/>后退
-        </Link> */}
         <UserInfo userInfo={userInfo}/>
         <p className={'header_title'}>{props.name || ''}</p>
         { renderQuit() }
-        {/* <Link style={{
-          position: 'absolute',
-          right: '30px',
-          top: 0,
-          color: '#5091FF'
-        }} to="/problems">退出</Link> */}
-        {/* <Button 
-          style={{ display: identifier ? 'none' : 'block'}}
-          loading={publishLoading}
-          className={`header_btn`} 
-          type="primary"
-          onClick={handleClickPublish}>立即发布</Button> */}
       </div>
       <div className="split-pane-area">
         <SplitPane split="vertical" minSize={350} maxSize={-350} defaultSize="40%">
@@ -206,6 +220,8 @@ const mapDispatchToProps = (dispatch) => ({
   handleFormSubmit: (props) => dispatch(actions.validateOjForm(props)),
   // 发布表单
   handlePublish: (props, type) => dispatch(actions.validateOjForm(props, type)),
+  // 撤销发布
+  handleCancelPublish: (props, identifier) => dispatch(actions.handleClickCancelPublish(props, identifier)),
   // 更新OJForm
   handleUpdateOjForm: (props) => dispatch(actions.validateOjForm(props)),
   // 根据id号获取表单信息
diff --git a/public/react/src/redux/actions/index.js b/public/react/src/redux/actions/index.js
index e52b88fc5..c19fa7e41 100644
--- a/public/react/src/redux/actions/index.js
+++ b/public/react/src/redux/actions/index.js
@@ -31,6 +31,7 @@ import {
   testCaseOutputChange,
   updateTestAndValidate,
   updateOpenTestCaseIndex,
+  handleClickCancelPublish,
 } from './ojForm';
 
 import {
@@ -79,6 +80,7 @@ export default {
   validateOjTimeLimit,
   validateOjCategory,
   validateOpenOrNot,
+  handleClickCancelPublish,
   addTestCase,
   deleteTestCase,
   testCaseInputChange,
diff --git a/public/react/src/redux/actions/ojForm.js b/public/react/src/redux/actions/ojForm.js
index c49e628f3..b7fbd6e80 100644
--- a/public/react/src/redux/actions/ojForm.js
+++ b/public/react/src/redux/actions/ojForm.js
@@ -4,11 +4,16 @@
  * @Github: 
  * @Date: 2019-11-20 16:35:46
  * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-10 19:54:56
+ * @LastEditTime: 2019-12-13 10:46:15
  */
 import types from './actionTypes';
 import CONST from '../../constants';
-import { fetchPostOjForm, fetchGetOjById, publishTask } from '../../services/ojService';
+import { 
+  fetchPostOjForm,
+  fetchGetOjById,
+  publishTask,
+  cancelPublicTask
+} from '../../services/ojService';
 import { Base64 } from 'js-base64';
 import { message, notification, Modal } from 'antd';
 import { toStore } from 'educoder'; 
@@ -80,6 +85,18 @@ const payloadInfo = (key, value, errMsg, validateInfo) => ({
   }
 });
 
+// 接口调用成功后,跳转至列表页
+function linkToDev (dispatch, props) {
+  toStore('oj_description', '');
+  dispatch({
+    type: types.IS_MY_SOURCE,
+    payload: true
+  });
+  setTimeout(() => {
+    props.history.push('/problems');
+  }, 1000);
+}
+
 // 表单提交验证
 export const validateOjForm = (props, type) => {
   return (dispatch, getState) => {
@@ -229,59 +246,31 @@ export const validateOjForm = (props, type) => {
         paramsObj['identifier'] = identifier;
       }
 
-      // 接口调用成功后,跳转至列表页
-      function linkToDev () {
-        toStore('oj_description', '');
-        dispatch({
-          type: types.IS_MY_SOURCE,
-          payload: true
-        });
-        setTimeout(() => {
-          props.history.push('/problems');
-        }, 1000);
-      }
-
       // 调用保存或更新
       if (type === 'publish') {
         // 提示发布信息
-        Modal.confirm({
-          title: '提示',
-          content: `
-            发布后即可应用到自己管理的课堂, 
-            是否确定发布?`,
-          okText: '确定',
-          cancelText: '取消',
-          onOk () {
-            publishTask(identifier).then(res => {
-              if (res.data.status === 0) {
-                message.success('发布成功!');
-                linkToDev();
-              }
-              dispatch({
-                type: types.PUBLISH_LOADING_STATUS,
-                payload: false
-              });
-            }).catch(() => {
-              dispatch({
-                type: types.PUBLISH_LOADING_STATUS,
-                payload: false
-              });
-            });
-          },
-          onCancel () {
-            dispatch({
-              type: types.PUBLISH_LOADING_STATUS,
-              payload: false
-            });
+        publishTask(identifier).then(res => {
+          if (res.data.status === 0) {
+            message.success('发布成功!');
+            linkToDev(dispatch, props);
           }
+          dispatch({
+            type: types.PUBLISH_LOADING_STATUS,
+            payload: false
+          });
+        }).catch(() => {
+          dispatch({
+            type: types.PUBLISH_LOADING_STATUS,
+            payload: false
+          });
         });
       } else {
         // 调用更新
         fetchPostOjForm(paramsObj).then(res => {
           if (res.status === 200) { // 保存成功后,重新跳转至列表页
-            if (res.data.identifier) {
-              message.success('保存成功!');
-              linkToDev();
+            if (res.data.status === 0) {
+              message.success(paramsObj['submitType'] === 'update' ? '更新成功' : '保存成功');
+              linkToDev(dispatch, props);
             }
               dispatch({
                 type: types.SUBMIT_LOADING_STATUS,
@@ -299,6 +288,29 @@ export const validateOjForm = (props, type) => {
     }
   }
 };
+// 撤销发布
+export const handleClickCancelPublish = (props, identifier) => {
+  return (dispatch) => {
+    cancelPublicTask(identifier).then(res => {
+      dispatch({
+        type: types.PUBLISH_LOADING_STATUS,
+        payload: false
+      });
+      if (res.status = 200) {
+        const { data} = res;
+        if (data.status === 0) {
+          message.success('撤销发布成功!');
+          linkToDev(dispatch, props);
+        }
+      }
+    }).catch(() => {
+      dispatch({
+        type: types.PUBLISH_LOADING_STATUS,
+        payload: false
+      });
+    })
+  }
+}
 // 保存提交的代码
 export const saveOjFormCode = (value) => {
   return {
diff --git a/public/react/src/services/ojService.js b/public/react/src/services/ojService.js
index 74c243379..9700f7031 100644
--- a/public/react/src/services/ojService.js
+++ b/public/react/src/services/ojService.js
@@ -4,7 +4,7 @@
  * @Github: 
  * @Date: 2019-11-20 10:55:38
  * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-10 20:46:16
+ * @LastEditTime: 2019-12-13 10:09:12
  */
 
 import axios from 'axios';
@@ -95,6 +95,12 @@ export async function publishTask (identifier) {
   return axios.post(url);
 }
 
+// 撤销发布
+export async function cancelPublicTask (identifier) {
+  const url = `/problems/${identifier}/cancel_publish.json`;
+  return axios.post(url);
+}
+
 // 更新用户编辑代码
 export async function fetchUpdateCode (identifier, params) {
   const url = `/myproblems/${identifier}/update_code.json`;

From 74586f166adccffc701d2906042e7ea6e933d149 Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Fri, 13 Dec 2019 13:30:55 +0800
Subject: [PATCH 4/9] update test cases

---
 .../modules/developer/newOrEditTask/index.js  | 22 ++++++++++++++-----
 .../leftpane/editorTab/AddTestDemo.js         |  6 ++---
 .../newOrEditTask/leftpane/editorTab/index.js |  3 ++-
 .../react/src/redux/reducers/ojFormReducer.js | 12 ++++++----
 4 files changed, 29 insertions(+), 14 deletions(-)

diff --git a/public/react/src/modules/developer/newOrEditTask/index.js b/public/react/src/modules/developer/newOrEditTask/index.js
index e750cee0a..bc905fdf7 100644
--- a/public/react/src/modules/developer/newOrEditTask/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/index.js
@@ -140,16 +140,26 @@ const NewOrEditTask = (props) => {
     ) : (
       <Button type="primary" onClick={imitationChallenge}>模拟挑战</Button>
     );
+  
+    // 更新
+    // const updateBtn = isPublish
+    //   ? ''
+    //   : (
+    //     <Button 
+    //         type="primary" 
+    //         loading={submitLoading}
+    //         onClick={handleSubmitForm}
+    //       >更新</Button>
+    //   );
     return (
       <React.Fragment>
-        <Button 
-          type="primary" 
-          loading={submitLoading}
-          onClick={handleSubmitForm}
-        >更新</Button>
+         <Button 
+            type="primary" 
+            loading={submitLoading}
+            onClick={handleSubmitForm}
+          >更新</Button>
         {pubButton}
         {challengeBtn}
-        {/* <Button type="primary" onClick={startChallenge}>模拟挑战</Button> */}
       </React.Fragment>
     )
   }
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js
index d34efc080..4c4131fa9 100644
--- a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js
@@ -4,7 +4,7 @@
  * @Github: 
  * @Date: 2019-11-21 09:19:38
  * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-10 19:37:35
+ * @LastEditTime: 2019-12-13 11:58:46
  */
 import './index.scss';
 import React, { useState } from 'react';
@@ -16,7 +16,7 @@ const { TextArea } = Input;
 const FormItem = Form.Item;
 const AddTestDemo = (props) => {
   const {
-    // key,
+    key,
     onSubmitTest,
     onDeleteTest, 
     testCase,
@@ -138,7 +138,7 @@ const AddTestDemo = (props) => {
   
   return (
     <Collapse className={'collapse_area'} activeKey={isOpen?'1':''} onChange={() => handleChangeCollapse()}>
-      <Panel header={`测试用例${testCase.position}`} extra={genExtra()} key="1">
+      <Panel header={`测试用例${props.index + 1}`} extra={genExtra()} key="1">
         <Form>
           <FormItem
             label={<span className={'label_text'}>输入</span>}
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
index 7a3b3f486..762d1d3ba 100644
--- a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
@@ -4,7 +4,7 @@
  * @Github: 
  * @Date: 2019-11-20 10:35:40
  * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-09 10:22:03
+ * @LastEditTime: 2019-12-13 11:39:52
  */
 import 'quill/dist/quill.core.css';
 import 'quill/dist/quill.bubble.css';
@@ -185,6 +185,7 @@ class EditTab extends React.Component {
     };
     const renderTestCase = () => {
       return this.props.testCases.map((item, i) => {
+        console.log(111);
         return <AddTestDemo
             key={`${i}`}
             isOpen={openTestCodeIndex.includes(i)}
diff --git a/public/react/src/redux/reducers/ojFormReducer.js b/public/react/src/redux/reducers/ojFormReducer.js
index ce89bce9a..c2ba0f4d8 100644
--- a/public/react/src/redux/reducers/ojFormReducer.js
+++ b/public/react/src/redux/reducers/ojFormReducer.js
@@ -4,7 +4,7 @@
  * @Github: 
  * @Date: 2019-11-20 16:40:32
  * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-09 16:30:46
+ * @LastEditTime: 2019-12-13 11:54:35
  */
 import { Base64 } from 'js-base64';
 import types from '../actions/actionTypes';
@@ -146,12 +146,16 @@ const ojFormReducer = (state = initialState, action) => {
       const { position } = action.payload;
       // 根据 position 去查找当前元素在数组中的位置
       const index = state.testCases.findIndex((item) => item.position === position);
+      const tempTestCase = state.testCases || [];
+      const tempTestValicate = state.testCasesValidate || [];
       if (index > -1) {
-        state.testCases.splice(index, 1); // 删除当前元素
-        state.testCasesValidate.splice(index, 1); // 删除测试用例对应的校验
+        tempTestCase.splice(index, 1); // 删除当前元素
+        tempTestValicate.splice(index, 1); // 删除测试用例对应的校验
       }
       return {
-        ...state
+        ...state,
+        testCases: [...tempTestCase],
+        testCasesValidate: [...tempTestValicate]
       };
     case types.SAVE_OJ_FORM_ID:
       state.identifier = action.payload;

From 2592cd39cf3800e12f43a8069b441a4b79fb118b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Fri, 13 Dec 2019 16:27:30 +0800
Subject: [PATCH 5/9] =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 public/react/src/AppConfig.js                          |  2 +-
 .../modules/courses/shixunHomework/ShixunWorkReport.js | 10 ++++++++--
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js
index 064c64db1..d88d5f05f 100644
--- a/public/react/src/AppConfig.js
+++ b/public/react/src/AppConfig.js
@@ -33,7 +33,7 @@ if (isDev) {
 // 超管
 // debugType="admin";
 // 老师
-// debugType="teacher";
+//ebugType="teacher";
 // 学生
 //debugType="student";
 
diff --git a/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js b/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js
index 1bf7ac181..10b12eb0a 100644
--- a/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js
+++ b/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js
@@ -315,6 +315,7 @@ class ShixunWorkReport extends Component {
 		// let showAppraiseModals=this.props&&this.props.isAdminOrTeacher()===true?work_comment===null||work_comment===undefined?false:true:work_comment===null||work_comment===undefined?false:true;
 		let showAppraiseModals=work_comment===null||work_comment===undefined?false:true;
 		document.title=data&&data.course_name;
+
 		return (
 
 				data===undefined?"":<Spin indicator={antIcon} spinning={this.state.spinning}>
@@ -366,10 +367,15 @@ class ShixunWorkReport extends Component {
 						<p className=" fl color-black mt25 summaryname">{data&&data.shixun_name}</p>
 						{/*{this.props.isAdmin()?<a className=" fr font-14 ml30 mt10 mr20 color-grey-9 ">导出实训报告数据</a>:""}*/}
 						<a onClick={this.goback} className="color-grey-6 fr font-14 ml20 mt15">返回</a>
-					 <a
+						{this.props.isAdmin() ?<a
 							className=" color-blue font-14 fr  ml20 mt15"
 							onClick={()=>this.confirmysl(`/student_works/${homeworkid}/export_shixun_work_report.pdf`)}
-						> <Spin size="small" spinning={this.state.isspinning}>导出实训报告数据</Spin></a>
+						> <Spin size="small" spinning={this.state.isspinning}>导出实训报告数据</Spin></a>:
+							parseInt(this.props&&this.props.user.user_id)===parseInt(data&&data.user_id)?<a
+								className=" color-blue font-14 fr  ml20 mt15"
+								onClick={()=>this.confirmysl(`/student_works/${homeworkid}/export_shixun_work_report.pdf`)}
+							> <Spin size="small" spinning={this.state.isspinning}>导出实训报告数据</Spin></a>:""
+						}
 						{/*{this.props.isAdmin() ?work_comment_hidden===true? "":<a*/}
 							{/*className=" color-blue font-14 fr  ml20 mt15"*/}
 							{/*onClick={()=>this.showAppraiseModal(1)}*/}

From af54d55cbf3c1276130e878179031c75558af557 Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Fri, 13 Dec 2019 16:29:33 +0800
Subject: [PATCH 6/9] update tooltip

---
 public/react/src/modules/tpm/jupyter/leftPane/index.js | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/public/react/src/modules/tpm/jupyter/leftPane/index.js b/public/react/src/modules/tpm/jupyter/leftPane/index.js
index 957f9c391..5e27dfafd 100644
--- a/public/react/src/modules/tpm/jupyter/leftPane/index.js
+++ b/public/react/src/modules/tpm/jupyter/leftPane/index.js
@@ -4,7 +4,7 @@
  * @Github: 
  * @Date: 2019-12-12 10:34:03
  * @LastEditors: tangjiang
- * @LastEditTime: 2019-12-13 16:04:31
+ * @LastEditTime: 2019-12-13 16:28:33
  */
 import './index.scss';
 import React, { useState, useEffect } from 'react';
@@ -36,7 +36,11 @@ function LeftPane (props) {
       const oList = dataSets.map((item, i) => {
         return (
           <li className="jupyter_item" key={`key_${i}`}>
-            <Tooltip placement="right" title={item.file_path}>
+            <Tooltip 
+              placement="right" 
+              title={item.file_path}
+              mouseLeaveDelay={0.3}
+            >
               <Icon type="file-text" className="jupyter_icon"/>
               <span className="jupyter_name">{item.title}</span>
             </Tooltip>

From 149e89f92269f64bffcdd1ade1de45db43271a87 Mon Sep 17 00:00:00 2001
From: daiao <358551898@qq.com>
Date: Fri, 13 Dec 2019 16:35:29 +0800
Subject: [PATCH 7/9] =?UTF-8?q?=E6=96=87=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/controllers/shixuns_controller.rb | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb
index d4f9bd3c8..ac26b740c 100644
--- a/app/controllers/shixuns_controller.rb
+++ b/app/controllers/shixuns_controller.rb
@@ -1096,4 +1096,13 @@ private
 		end
 	end
 
+	def file_ext(file_name)
+		ext = ''
+		exts = file_name.split(".")
+		if exts.size > 1
+			ext = ".#{exts.last}"
+		end
+		ext
+	end
+
 end

From bf7362639f8fd2299974b3683117d576a026d743 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Fri, 13 Dec 2019 16:44:40 +0800
Subject: [PATCH 8/9] =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 public/react/src/modules/tpm/TPMBanner.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/public/react/src/modules/tpm/TPMBanner.js b/public/react/src/modules/tpm/TPMBanner.js
index bf33f94a8..68c958dba 100644
--- a/public/react/src/modules/tpm/TPMBanner.js
+++ b/public/react/src/modules/tpm/TPMBanner.js
@@ -1080,7 +1080,7 @@ class TPMBanner extends Component {
                   content={
                   <pre className={"bannerpd201"}>
                   <div>申请公开成功后,您的实训将会展示实训列表</div>
-                  <div className={"wechatcenter mt10"}>平台审核通过,您将获得<span className={"FF6802"}> 1000 </span>金币~</div>
+                  <div className={"wechatcenter mt10"}>您将获得关卡<span className={"FF6802"}>对应的经验值和金币</span>~ </div>
                   <div className={"wechatcenter mt15"}><Button  type="primary" onClick={this.openshowpublic} >我知道了</Button></div>
                   </pre>
                 }
@@ -1199,7 +1199,7 @@ class TPMBanner extends Component {
                 }
 
 
-                {this.props.identity < 8 && shixunsDetails.shixun_status != -1 ?
+                {this.props.identity < 8 && shixunsDetails.shixun_status != -1 && shixunsDetails.shixun_status != 0?
                   <div className="fr user_default_btn user_blue_btn mr20"
                        style={{display: shixunsDetails.can_copy === false || shixunsDetails.can_copy === null ? "none" : "flex"}}>
                     <Tooltip placement="bottom" title={"基于这个实训修改形成新的实训"}>

From becba8fb097be2349435fbf52efb924a52e18587 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Fri, 13 Dec 2019 16:54:52 +0800
Subject: [PATCH 9/9] =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 public/react/src/modules/tpm/TPMBanner.js                  | 6 +++---
 .../react/src/modules/tpm/TPMsettings/LearningSettings.js  | 7 ++++---
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/public/react/src/modules/tpm/TPMBanner.js b/public/react/src/modules/tpm/TPMBanner.js
index 68c958dba..19e1acfa8 100644
--- a/public/react/src/modules/tpm/TPMBanner.js
+++ b/public/react/src/modules/tpm/TPMBanner.js
@@ -398,7 +398,7 @@ class TPMBanner extends Component {
   hidenpublic=()=>{
     this.setState({
       Modalstype: true,
-      Modalstopval: "是否确认撤销公开?",
+      Modalstopval: "是否确认撤销申请公开?",
       modalsMidval:" ",
       ModalsBottomval:" ",
       ModalCancel: this.ModalCancel,
@@ -1095,8 +1095,8 @@ class TPMBanner extends Component {
                 }
 
                 {shixunsDetails.shixun_status === 2 && shixunsDetails.public===1 && this.props.identity < 5 ?
-                  <Button type="primary" ghost id="challenge_begin" onClick={this.hidenpublic} className="fr user_default_btn user_blue_btn mr20 font-18 height39">
-                    撤销公开
+                  <Button type="primary" ghost id="challenge_begin" onClick={this.hidenpublic} className="fr user_default_btn user_blue_btn mr20 font-18 height39" style={{'width': '140px'}}>ss
+                    撤销申请公开
                   </Button>: ""
                 }
 
diff --git a/public/react/src/modules/tpm/TPMsettings/LearningSettings.js b/public/react/src/modules/tpm/TPMsettings/LearningSettings.js
index dfcdda5ba..81de06cfb 100644
--- a/public/react/src/modules/tpm/TPMsettings/LearningSettings.js
+++ b/public/react/src/modules/tpm/TPMsettings/LearningSettings.js
@@ -127,7 +127,7 @@ export default class Shixuninformation extends Component {
   }
 
   Checkvnc = () => {
-    console.log(this.state.vnc)
+
     if (this.state.vnc === false) {
       this.setState({
         hide_code: false,
@@ -193,7 +193,8 @@ export default class Shixuninformation extends Component {
     } else {
       this.setState({
         multi_webssh: false,
-        opensshRadio: null
+        opensshRadio: null,
+        hide_code:false
       })
     }
     this.setState({
@@ -274,7 +275,7 @@ export default class Shixuninformation extends Component {
                </span> : ""}
           </div> : ""}
 
-          {this.state.vnc === true ? "" : <div className="clearfix mb20">
+          {this.state.vnc === true||this.state.websshshow === false ? "" : <div className="clearfix mb20">
             <span className="color-grey-6 mt5 fl font-16 ml17" style={{minWidth: '45px'}}>隐藏代码窗口:</span>
             <span className="fl mt8">
               <Checkbox