From 68032285bb4246f45a85cc4373e5bf798c9a7883 Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Tue, 19 Nov 2019 08:42:10 +0800
Subject: [PATCH 01/17] =?UTF-8?q?=E5=BC=80=E5=8F=91=E8=80=85=E6=A8=A1?=
=?UTF-8?q?=E5=BC=8F=E9=A1=B5=E9=9D=A2=E5=B8=83=E5=B1=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
public/react/config/webpack.config.dev.js | 2 +-
public/react/config/webpack.config.prod.js | 2 +
public/react/package-lock.json | 92 +---
public/react/package.json | 7 +-
public/react/src/App.js | 401 +++++++++---------
.../src/modules/developer/DeveloperHome.js | 296 +++++++++++++
public/react/src/modules/developer/St | 0
.../developer/components/multiptags/index.js | 36 ++
.../components/multiptags/index.scss | 42 ++
public/react/src/modules/developer/index.js | 20 +
public/react/src/modules/developer/index.scss | 53 +++
.../modules/developer/newOrEditTask/index.js | 51 +++
.../developer/newOrEditTask/index.scss | 80 ++++
.../developer/newOrEditTask/leftpane/index.js | 0
.../newOrEditTask/rightpane/RightPaneCode.js | 125 ++++++
.../rightpane/RightPaneControl.js | 71 ++++
.../newOrEditTask/rightpane/index.js | 20 +
.../newOrEditTask/rightpane/index.scss | 77 ++++
.../rightpane/initTabCtx/index.js | 41 ++
.../rightpane/initTabCtx/index.scss | 28 ++
public/react/src/modules/tpm/NewHeader.js | 18 +-
public/react/src/modules/tpm/TPMIndex.css | 6 +-
public/react/src/modules/tpm/TPMIndexHOC.js | 5 +-
public/react/src/redux/README.md | 128 ++++++
public/react/src/redux/actions/actionTypes.js | 12 +
public/react/src/redux/actions/index.js | 13 +
public/react/src/redux/actions/testAction.js | 7 +
public/react/src/redux/reducers/index.js | 14 +
.../react/src/redux/reducers/testReducer.js | 30 ++
.../react/src/redux/stores/configureStore.js | 18 +
30 files changed, 1407 insertions(+), 288 deletions(-)
create mode 100644 public/react/src/modules/developer/DeveloperHome.js
create mode 100644 public/react/src/modules/developer/St
create mode 100644 public/react/src/modules/developer/components/multiptags/index.js
create mode 100644 public/react/src/modules/developer/components/multiptags/index.scss
create mode 100644 public/react/src/modules/developer/index.js
create mode 100644 public/react/src/modules/developer/index.scss
create mode 100644 public/react/src/modules/developer/newOrEditTask/index.js
create mode 100644 public/react/src/modules/developer/newOrEditTask/index.scss
create mode 100644 public/react/src/modules/developer/newOrEditTask/leftpane/index.js
create mode 100644 public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneCode.js
create mode 100644 public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneControl.js
create mode 100644 public/react/src/modules/developer/newOrEditTask/rightpane/index.js
create mode 100644 public/react/src/modules/developer/newOrEditTask/rightpane/index.scss
create mode 100644 public/react/src/modules/developer/newOrEditTask/rightpane/initTabCtx/index.js
create mode 100644 public/react/src/modules/developer/newOrEditTask/rightpane/initTabCtx/index.scss
create mode 100644 public/react/src/redux/README.md
create mode 100644 public/react/src/redux/actions/actionTypes.js
create mode 100644 public/react/src/redux/actions/index.js
create mode 100644 public/react/src/redux/actions/testAction.js
create mode 100644 public/react/src/redux/reducers/index.js
create mode 100644 public/react/src/redux/reducers/testReducer.js
create mode 100644 public/react/src/redux/stores/configureStore.js
diff --git a/public/react/config/webpack.config.dev.js b/public/react/config/webpack.config.dev.js
index 4acbb35a7..86938e51d 100644
--- a/public/react/config/webpack.config.dev.js
+++ b/public/react/config/webpack.config.dev.js
@@ -267,7 +267,7 @@ module.exports = {
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
// You can remove this if you don't use Moment.js:
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
- new MonacoWebpackPlugin(),
+ new MonacoWebpackPlugin(),
],
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
diff --git a/public/react/config/webpack.config.prod.js b/public/react/config/webpack.config.prod.js
index 1cc105517..f312da3e6 100644
--- a/public/react/config/webpack.config.prod.js
+++ b/public/react/config/webpack.config.prod.js
@@ -11,6 +11,7 @@ const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
+const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const paths = require('./paths');
const getClientEnvironment = require('./env');
@@ -371,6 +372,7 @@ module.exports = {
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
// You can remove this if you don't use Moment.js:
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
+ new MonacoWebpackPlugin(),
],
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
diff --git a/public/react/package-lock.json b/public/react/package-lock.json
index 631da270e..d66fbf62a 100644
--- a/public/react/package-lock.json
+++ b/public/react/package-lock.json
@@ -84,7 +84,6 @@
"@icedesign/base": {
"version": "0.2.8",
"resolved": "https://registry.npm.taobao.org/@icedesign/base/download/@icedesign/base-0.2.8.tgz",
- "integrity": "sha1-hmlSY+17gnKJB3sbgoy446sqzAk=",
"requires": {
"async-validator": "^1.6.7",
"classnames": "^2.2.3",
@@ -138,8 +137,7 @@
},
"@types/tapable": {
"version": "1.0.4",
- "resolved": "https://registry.npm.taobao.org/@types/tapable/download/@types/tapable-1.0.4.tgz",
- "integrity": "sha1-tP/H3Je0mMlps2CkHu4kf4JhY3A="
+ "resolved": "https://registry.npm.taobao.org/@types/tapable/download/@types/tapable-1.0.4.tgz"
},
"@types/uglify-js": {
"version": "3.0.4",
@@ -2779,8 +2777,7 @@
},
"cropperjs": {
"version": "0.7.2",
- "resolved": "https://registry.npm.taobao.org/cropperjs/download/cropperjs-0.7.2.tgz",
- "integrity": "sha1-atinHbAGKbqULZzt5lKyeXXp50o="
+ "resolved": "https://registry.npm.taobao.org/cropperjs/download/cropperjs-0.7.2.tgz"
},
"cross-spawn": {
"version": "5.1.0",
@@ -10456,6 +10453,11 @@
"resolved": "http://registry.npm.taobao.org/requires-port/download/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
},
+ "reqwest": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/reqwest/-/reqwest-2.0.5.tgz",
+ "integrity": "sha1-APsVrEkYxBnKgrQ/JMeIguZgOaE="
+ },
"resize-observer-polyfill": {
"version": "1.5.1",
"resolved": "http://registry.npm.taobao.org/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz",
@@ -10834,86 +10836,6 @@
"resolved": "http://registry.npm.taobao.org/shellwords/download/shellwords-0.1.1.tgz",
"integrity": "sha1-1rkYHBpI05cyTISHHvvPxz/AZUs="
},
- "showdown": {
- "version": "1.9.0",
- "resolved": "http://registry.npm.taobao.org/showdown/download/showdown-1.9.0.tgz",
- "integrity": "sha1-1J0qC22yG3wulu+FX3s7KijvRvQ=",
- "requires": {
- "yargs": "^10.0.3"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "3.0.0",
- "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz",
- "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
- },
- "camelcase": {
- "version": "4.1.0",
- "resolved": "http://registry.npm.taobao.org/camelcase/download/camelcase-4.1.0.tgz",
- "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
- },
- "cliui": {
- "version": "4.1.0",
- "resolved": "http://registry.npm.taobao.org/cliui/download/cliui-4.1.0.tgz",
- "integrity": "sha1-NIQi2+gtgAswIu709qwQvy5NG0k=",
- "requires": {
- "string-width": "^2.1.1",
- "strip-ansi": "^4.0.0",
- "wrap-ansi": "^2.0.0"
- }
- },
- "os-locale": {
- "version": "2.1.0",
- "resolved": "http://registry.npm.taobao.org/os-locale/download/os-locale-2.1.0.tgz",
- "integrity": "sha1-QrwpAKa1uL0XN2yOiCtlr8zyS/I=",
- "requires": {
- "execa": "^0.7.0",
- "lcid": "^1.0.0",
- "mem": "^1.1.0"
- }
- },
- "strip-ansi": {
- "version": "4.0.0",
- "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz",
- "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
- "requires": {
- "ansi-regex": "^3.0.0"
- }
- },
- "which-module": {
- "version": "2.0.0",
- "resolved": "http://registry.npm.taobao.org/which-module/download/which-module-2.0.0.tgz",
- "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
- },
- "yargs": {
- "version": "10.1.2",
- "resolved": "http://registry.npm.taobao.org/yargs/download/yargs-10.1.2.tgz",
- "integrity": "sha1-RU0HTCsWpRpD4vt4B+T53mnMtcU=",
- "requires": {
- "cliui": "^4.0.0",
- "decamelize": "^1.1.1",
- "find-up": "^2.1.0",
- "get-caller-file": "^1.0.1",
- "os-locale": "^2.0.0",
- "require-directory": "^2.1.1",
- "require-main-filename": "^1.0.1",
- "set-blocking": "^2.0.0",
- "string-width": "^2.0.0",
- "which-module": "^2.0.0",
- "y18n": "^3.2.1",
- "yargs-parser": "^8.1.0"
- }
- },
- "yargs-parser": {
- "version": "8.1.0",
- "resolved": "http://registry.npm.taobao.org/yargs-parser/download/yargs-parser-8.1.0.tgz",
- "integrity": "sha1-8TdqM7Ziml0GN4KUTacyYx6WaVA=",
- "requires": {
- "camelcase": "^4.1.0"
- }
- }
- }
- },
"signal-exit": {
"version": "3.0.2",
"resolved": "http://registry.npm.taobao.org/signal-exit/download/signal-exit-3.0.2.tgz",
diff --git a/public/react/package.json b/public/react/package.json
index e43132877..61146f126 100644
--- a/public/react/package.json
+++ b/public/react/package.json
@@ -4,6 +4,7 @@
"private": true,
"dependencies": {
"@icedesign/base": "^0.2.5",
+ "@monaco-editor/react": "^2.3.0",
"@novnc/novnc": "^1.1.0",
"antd": "^3.23.2",
"array-flatten": "^2.1.2",
@@ -49,6 +50,7 @@
"monaco-editor": "^0.15.6",
"monaco-editor-webpack-plugin": "^1.7.0",
"npm": "^6.10.1",
+ "numeral": "^2.0.6",
"object-assign": "4.1.1",
"postcss-flexbugs-fixes": "3.2.0",
"postcss-loader": "2.0.8",
@@ -77,11 +79,12 @@
"react-redux": "5.0.7",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
- "react-split-pane": "^0.1.87",
+ "react-split-pane": "^0.1.89",
"react-url-query": "^1.4.0",
"redux": "^4.0.0",
"redux-thunk": "2.3.0",
"rsuite": "^4.0.1",
+ "sass-loader": "7.3.1",
"store": "^2.0.12",
"style-loader": "0.19.0",
"styled-components": "^4.1.3",
@@ -167,7 +170,7 @@
"concat": "^1.0.3",
"happypack": "^5.0.1",
"node-sass": "^4.12.0",
- "sass-loader": "^7.3.1",
+ "reqwest": "^2.0.5",
"webpack-bundle-analyzer": "^3.0.3",
"webpack-parallel-uglify-plugin": "^1.1.0"
}
diff --git a/public/react/src/App.js b/public/react/src/App.js
index 6b4ba7399..c498b5859 100644
--- a/public/react/src/App.js
+++ b/public/react/src/App.js
@@ -39,11 +39,11 @@ import history from './history';
import {SnackbarHOC} from 'educoder'
import {initAxiosInterceptors} from './AppConfig'
-
-
+import { Provider } from 'react-redux';
+import configureStore from './redux/stores/configureStore';
// !!!tpi需要这个来加载css
import {TPMIndexHOC} from './modules/tpm/TPMIndexHOC';
-
+const store = configureStore();
const theme = createMuiTheme({
palette: {
@@ -294,7 +294,17 @@ const Ecs = Loadable({
loading: Loading,
})
+// 添加开发者社区
+const Developer = Loadable({
+ loader: () => import('./modules/developer'),
+ loading: Loading
+})
+// 开发者编辑模块
+const NewOrEditTask = Loadable({
+ loader: () => import('./modules/developer/newOrEditTask'),
+ loading: Loading
+});
// //个人竞赛报名
// const PersonalCompetit = Loadable({
// loader: () => import('./modules/competition/personal/PersonalCompetit.js'),
@@ -460,210 +470,211 @@ class App extends Component {
// console.log("appappapp");
// console.log(mygetHelmetapi);
return (
-
-
-
-
-
-
- this.Modifyloginvalue()}>
-
-
-
- this.HideAddcoursestypess(i)}/>
-
-
-
-
-
- {/*题库*/}
- {
-
- return ()
- }
- }>
- {/*题库*/}
- {
-
- return ()
- }
- }>
- {/*/!*众包创新*!/*/}
- {/**/}
- {/*竞赛*/}
- {
-
- return ()
- }
- }>
-
- {/*黑客松定制竞赛*/}
- {
- return(
-
- )
+
+
+
+ this.Modifyloginvalue()}>
+
+
+
+ this.HideAddcoursestypess(i)}/>
+
+
+
+
+
+
+
+ {/*题库*/}
+ {
+
+ return ()
+ }
+ }>
+ {/*题库*/}
+ {
+
+ return ()
+ }
+ }>
+ {/*/!*众包创新*!/*/}
+ {/**/}
+ {/*竞赛*/}
+ {
+
+ return ()
+ }
+ }>
+
+ {/*黑客松定制竞赛*/}
+ {
+ return(
+
+ )
+ }
}
- }
- />
+ />
- {/*认证*/}
-
+ {/*认证*/}
+
- {/*403*/}
-
+ {/*403*/}
+
-
+
- {/*404*/}
-
+ {/*404*/}
+
-
- {
+
+ {
- return ()
+ return ()
+ }
}
- }
- />
- {
-
- return ()
+ />
+ {
+
+ return ()
+ }
}
- }
- />
-
-
-
- {
-
- return ()
+ />
+
+
+
+ {
+
+ return ()
+ }
+ }>
+
+ {
+ return ()
+ }
+ }>
+ {/* ()*/}
+ {/*}*/}
+ {/*/>*/}
+ {
+
+ return ()
+ }
}
- }>
+ />
+ {
- return ()
- }
- }>
- {/* ()*/}
- {/*}*/}
- {/*/>*/}
- {
-
- return ()
+ />
+
+
+
+
+
+
+
+
+ {/*列表页*/}
+
+
+
+ {/*实训课程(原实训路径)*/}
+
+
+ ()
+ }
+ >
+
+ {/*课堂*/}
+
+
+ {/*
+ */}
+ {/* 教学案例 */}
+ ()
+ }/>
+
+ ()
}
- }
- />
-
-
-
-
-
-
-
-
-
- {/*列表页*/}
-
-
-
- {/*实训课程(原实训路径)*/}
-
-
- ()
- }
- >
-
- {/*课堂*/}
-
-
- {/*
- */}
- {/* 教学案例 */}
- ()
- }/>
-
- ()
- }
- >
-
-
- {/**/}
- {/**/}
- {/**/}
- {/**/}
- {/**/}
- {/* ()*/}
- {/*}*/}
- {/*/>*/}
-
- ()
- }
- >
- ()
- }/>
- ()
- }/>
-
- ()
- }
- />
-
-
-
-
-
-
-
+ >
+
+
+ {/**/}
+ {/**/}
+ {/**/}
+ {/**/}
+ {/**/}
+ {/* ()*/}
+ {/*}*/}
+ {/*/>*/}
+
+ ()
+ }
+ >
+ ()
+ }/>
+ ()
+ }/>
+
+
+
+ ()
+ }
+ />
+
+
+
+
+
+
+
);
}
}
diff --git a/public/react/src/modules/developer/DeveloperHome.js b/public/react/src/modules/developer/DeveloperHome.js
new file mode 100644
index 000000000..b551f4c21
--- /dev/null
+++ b/public/react/src/modules/developer/DeveloperHome.js
@@ -0,0 +1,296 @@
+/*
+ * @Description: undefined
+ * @Author: tangjiang
+ * @Date: 2019-11-15 11:02:49
+ * @Last Modified by: tangjiang
+ * @Last Modified time: 2019-11-18 16:52:38
+ */
+import './index.scss';
+
+import React, { PureComponent } from 'react';
+import { TPMIndexHOC } from '../tpm/TPMIndexHOC';
+import { Table, Button, Dropdown, Icon, Menu, Card, Input } from 'antd';
+import { connect } from 'react-redux';
+import actions from '../../redux/actions';
+import MultipTags from './components/multiptags';
+import { Link } from 'react-router-dom';
+
+const { Search } = Input;
+// import reqwest from 'reqwest';
+/**
+ * 下拉菜单
+ */
+const maps = {
+ 'categoryMenu': [
+ {
+ 'key': '0',
+ 'name': '全部',
+ 'vlaue': '0'
+ },
+ {
+ 'key': '1',
+ 'name': '程序设计基础',
+ 'vlaue': '1'
+ },
+ {
+ 'key': '2',
+ 'name': '数据结构与计算',
+ 'vlaue': '2'
+ }
+ ],
+ 'hardMenu': [
+ {
+ 'key': '0',
+ 'name': '简单',
+ 'vlaue': '0'
+ },
+ {
+ 'key': '1',
+ 'name': '中等',
+ 'vlaue': '1'
+ },
+ {
+ 'key': '2',
+ 'name': '困难',
+ 'vlaue': '2'
+ }
+ ],
+ 'statusMenu': [
+ {
+ 'key': '0',
+ 'name': '未做',
+ 'vlaue': '0'
+ },
+ {
+ 'key': '1',
+ 'name': '已通过',
+ 'vlaue': '1'
+ },
+ {
+ 'key': '2',
+ 'name': '未通过',
+ 'vlaue': '2'
+ }
+ ],
+ 'originMenu': [
+ {
+ 'key': '0',
+ 'name': '全部',
+ 'vlaue': '0'
+ },
+ {
+ 'key': '1',
+ 'name': '我创建的',
+ 'vlaue': '1'
+ }
+ ]
+};
+
+/**
+ * 表格列
+ */
+const columns = [
+ {
+ title: '序号',
+ dataIndex: 'id',
+ width: '10%'
+ },
+ {
+ title: '标题',
+ dataIndex: 'title',
+ },
+ {
+ title: '分类',
+ dataIndex: 'category',
+ width: '20%'
+ },
+ {
+ title: '难度',
+ dataIndex: 'level',
+ align: 'center',
+ width: '10%'
+ },
+ {
+ title: '热度',
+ dataIndex: 'hot',
+ sorter: true,
+ align: 'center',
+ width: '10%'
+ },
+ {
+ title: '通过率',
+ dataIndex: 'pass',
+ sorter: true,
+ align:'right',
+ width: '10%'
+ }
+];
+
+class DeveloperHome extends PureComponent {
+ state = {
+ data: [],
+ pagination: {
+ showQuickJumper: true
+ },
+ loading: false,
+ };
+
+ componentDidMount() {
+ this.fetch();
+ }
+
+ handleTableChange = (pagination, filters, sorter) => {
+ const pager = { ...this.state.pagination };
+ pager.current = pagination.current;
+ this.setState({
+ pagination: pager,
+ });
+ this.fetch({
+ results: pagination.pageSize,
+ page: pagination.current,
+ sortField: sorter.field,
+ sortOrder: sorter.order,
+ ...filters,
+ });
+ };
+
+ fetch = (params = {}) => {
+ console.log('params:', params);
+ this.setState({ loading: true });
+ // reqwest({
+ // url: 'https://randomuser.me/api',
+ // method: 'get',
+ // data: {
+ // results: 10,
+ // ...params,
+ // },
+ // type: 'json',
+ // }).then(data => {
+ // const pagination = { ...this.state.pagination };
+ // // Read total count from server
+ // // pagination.total = data.totalCount;
+ // pagination.total = 200;
+ // this.setState({
+ // loading: false,
+ // data: data.results,
+ // pagination,
+ // });
+ // });
+ };
+
+ /**
+ * 根据类型获取下拉菜单
+ * @param type 类型
+ * @param handleClick 处理函数
+ */
+ getMenuItems = (type, handleClick) => {
+ return (
+
+ )
+ };
+
+ /**
+ * 搜索输入框
+ * @param value 输入框值
+ */
+ handleInputSearch = (value) => {
+ console.log('搜索值==', value);
+ }
+ // 下拉类别菜单
+ handleCategoryMenuClick = (e) => {
+ console.log('dropdown ==>>>', e);
+ }
+ // 难度下拉
+ handleHardMenuClick = (e) => {}
+ // 状态下拉
+ handleSatusMenuClick = (e) => {}
+ // 来源下拉
+ handleOriginMenuClick = (e) => {}
+
+ render () {
+ // const { testReducer, handleClick } = this.props;
+ return (
+
+
+
+
+
+
+
已解决 589 / 1800 题
+
+
+
+
+
+
+
+
+
+
+
+ 分类
+
+
+ 难度
+
+
+ 状态
+
+
+ 来源
+
+
+ this.handleInputSearch(value)}
+ style={{ width: 320, float: 'right' }}
+ />
+
+
+
+ Math.random()}
+ dataSource={this.state.data}
+ pagination={this.state.pagination}
+ onChange={this.handleTableChange}
+ />
+
+
+
+
+
+ );
+ }
+}
+
+/**
+ * @param {*} state store
+ * @param {*} ownProps DeveloperHome 中的 props
+ */
+const mapStateToProps = (state, ownProps) => ({
+ testReducer: state.testReducer
+});
+
+
+const mapDispatchToProps = (dispatch) => ({
+ handleClick: () => dispatch(actions.toggleTodo())
+});
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(DeveloperHome);
+// export default DeveloperHome;
diff --git a/public/react/src/modules/developer/St b/public/react/src/modules/developer/St
new file mode 100644
index 000000000..e69de29bb
diff --git a/public/react/src/modules/developer/components/multiptags/index.js b/public/react/src/modules/developer/components/multiptags/index.js
new file mode 100644
index 000000000..1ea0627a1
--- /dev/null
+++ b/public/react/src/modules/developer/components/multiptags/index.js
@@ -0,0 +1,36 @@
+/*
+ * @Description: 显示 文字 + number 标签类型
+ * @Author: tangjiang
+ * @Date: 2019-11-15 10:41:06
+ * @Last Modified by: tangjiang
+ * @Last Modified time: 2019-11-15 17:15:27
+ */
+import './index.scss';
+
+import React, { PureComponent } from 'react';
+const numberal = require('numeral')
+
+export default class MultipTags extends PureComponent {
+
+ render () {
+ const { type = 'primary', text, numb, ...props} = this.props;
+
+ if (typeof numb !== 'number' && typeof numb !== 'string') {
+ throw new Error('输入的numb必须为数字或数字类型字符串.');
+ }
+ let result = Number(numb) >= 1000
+ ? numberal(Number(numb)).format('0.0a')
+ : Number(numb);
+
+ return (
+
+
+ { text }
+
+
+ { result }
+
+
+ )
+ }
+}
diff --git a/public/react/src/modules/developer/components/multiptags/index.scss b/public/react/src/modules/developer/components/multiptags/index.scss
new file mode 100644
index 000000000..6ed0c17d2
--- /dev/null
+++ b/public/react/src/modules/developer/components/multiptags/index.scss
@@ -0,0 +1,42 @@
+.mul-tag-wrap{
+ display: inline-block;
+ vertical-align: middle;
+
+ .tag-txt, .tag-numb{
+ display: inline-block;
+ vertical-align: middle;
+ padding: 0 10px;
+ // line-height: 20px;
+ // height: 20px;
+ font-size: 12px;
+ text-align: center;
+ }
+ .tag-txt{
+ border: 1px solid transparent;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ color: #fff;
+
+ &.primary{
+ background: #1890ff;
+ }
+ &.warning{
+ background: #faad14;
+ }
+ &.success{
+ background: #52c41a;
+ }
+ &.error{
+ background: #f5222d;
+ }
+ }
+
+ .tag-numb{
+ border: 1px solid rgba(238, 238, 238, 1);
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ border-left-color: transparent;
+ margin-left: -1px;
+ min-width: 40px;
+ }
+}
\ No newline at end of file
diff --git a/public/react/src/modules/developer/index.js b/public/react/src/modules/developer/index.js
new file mode 100644
index 000000000..524dd6104
--- /dev/null
+++ b/public/react/src/modules/developer/index.js
@@ -0,0 +1,20 @@
+/*
+ * @Description: 开发者社区入口文件,此处提供全局store,并且此处Provier只能有一个子无互
+ * @Author: tangjiang
+ * @Date: 2019-11-13 20:14:04
+ * @Last Modified by: tangjiang
+ * @Last Modified time: 2019-11-15 20:43:27
+ */
+import React from 'react';
+import { TPMIndexHOC } from '../tpm/TPMIndexHOC';
+import DeveloperHome from './DeveloperHome';
+
+const App = () => {
+ return (
+
+
+
+ );
+}
+
+export default TPMIndexHOC(App);
diff --git a/public/react/src/modules/developer/index.scss b/public/react/src/modules/developer/index.scss
new file mode 100644
index 000000000..f041da670
--- /dev/null
+++ b/public/react/src/modules/developer/index.scss
@@ -0,0 +1,53 @@
+.banner-wrap{
+ width: 100%;
+ height: 300px;
+ background-image: url(/static/media/path.e39ba7de.png);
+ background-color: #000a4f;
+ /* background-size: cover; */
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.developer-list{
+ overflow: hidden;
+ .card-top {
+ border-radius:4px;
+ background:rgba(255,255,255,1);
+ height:56px;
+ padding: 0 30px;
+ margin-top: 20px;
+ .search-params{
+ display: flex;
+ align-items: center;
+ height: 100%;
+ }
+
+ .save-question{
+ width: 200px;
+ }
+ // .flex-end{
+ // // float: right;
+ // }
+ .question-level{
+ flex: 1;
+ }
+ }
+
+ .card-table{
+ margin-top: 10px;
+ .ant-card-body{
+ padding: 10px 30px;
+ }
+ .dropdown-span{
+ position: relative;
+ top: 5px;
+ }
+ .dropdonw-style{
+ margin-right: 50px;
+ .dropdown-span{
+ cursor: pointer;
+ margin-right: 10px;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/react/src/modules/developer/newOrEditTask/index.js b/public/react/src/modules/developer/newOrEditTask/index.js
new file mode 100644
index 000000000..0b924d3c3
--- /dev/null
+++ b/public/react/src/modules/developer/newOrEditTask/index.js
@@ -0,0 +1,51 @@
+/*
+ * @Description: 新建或编辑任务
+ * @Author: tangjiang
+ * @Date: 2019-11-15 16:38:34
+ * @Last Modified by: tangjiang
+ * @Last Modified time: 2019-11-18 23:21:25
+ */
+import './index.scss';
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import SplitPane from 'react-split-pane';// import { Form } from 'antd';
+import { Button, Icon } from 'antd';
+import { Link } from 'react-router-dom';
+import RightPane from './rightpane';
+class NewOrEditTask extends Component {
+
+ render() {
+ return (
+
+
+
+ 后退
+
+ 标题内容
+
+
+
+
+ You can use a div component
+
+
+
+
+
+
+
+
+ )
+ }
+}
+
+const mapStateToProps = (state) => ({
+
+});
+
+const mapDispatchToProps = (dispatch) => ({});
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(NewOrEditTask);
diff --git a/public/react/src/modules/developer/newOrEditTask/index.scss b/public/react/src/modules/developer/newOrEditTask/index.scss
new file mode 100644
index 000000000..1d5c6e2a4
--- /dev/null
+++ b/public/react/src/modules/developer/newOrEditTask/index.scss
@@ -0,0 +1,80 @@
+.new_add_task_wrap{
+ height: 100vh;
+ .task_header{
+ display: flex;
+ align-items: center;
+ // justify-content: space-between;
+ height: 65px;
+ background:rgba(34,34,34,1);
+ padding:0 30px;
+
+ .header_btn,
+ .header_title{
+ color: #fff;
+ }
+ .header_btn{
+ width: 88px;
+ }
+ .header_title{
+ flex: 1;
+ text-align: center;
+ }
+ }
+ .split-pane-area{
+ position: relative;
+ height: calc(100% - 65px);
+ .left_pane,
+ .right_pane{
+ height: 100%;
+ }
+ }
+}
+.Resizer {
+ background: #000;
+ opacity: 0.2;
+ z-index: 1;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ -moz-background-clip: padding;
+ -webkit-background-clip: padding;
+ background-clip: padding-box;
+}
+
+.Resizer:hover {
+ -webkit-transition: all 2s ease;
+ transition: all 2s ease;
+}
+
+.Resizer.horizontal {
+ height: 11px;
+ margin: -5px 0;
+ border-top: 5px solid rgba(255, 255, 255, 0);
+ border-bottom: 5px solid rgba(255, 255, 255, 0);
+ cursor: row-resize;
+ width: 100%;
+}
+
+.Resizer.horizontal:hover {
+ border-top: 5px solid rgba(0, 0, 0, 0.5);
+ border-bottom: 5px solid rgba(0, 0, 0, 0.5);
+}
+
+.Resizer.vertical {
+ width: 11px;
+ margin: 0 -5px;
+ border-left: 5px solid rgba(255, 255, 255, 0);
+ border-right: 5px solid rgba(255, 255, 255, 0);
+ cursor: col-resize;
+}
+
+.Resizer.vertical:hover {
+ border-left: 5px solid rgba(0, 0, 0, 0.5);
+ border-right: 5px solid rgba(0, 0, 0, 0.5);
+}
+.Resizer.disabled {
+ cursor: not-allowed;
+}
+.Resizer.disabled:hover {
+ border-color: transparent;
+}
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneCode.js b/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneCode.js
new file mode 100644
index 000000000..c735b62ed
--- /dev/null
+++ b/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneCode.js
@@ -0,0 +1,125 @@
+/*
+ * @Description: 右侧代码块
+ * @Author: tangjiang
+ * @Date: 2019-11-18 08:42:04
+ * @Last Modified by: tangjiang
+ * @Last Modified time: 2019-11-19 08:39:28
+ */
+
+import './index.scss';
+
+import React, { Fragment, useState } from 'react';
+import { Icon, Drawer, Tabs, Button } from 'antd';
+// import MonacoEditor from 'react-monaco-editor';
+import MonacoEditor from '@monaco-editor/react';
+import InitTabCtx from './initTabCtx';
+
+const { TabPane } = Tabs;
+const tabsArrs = [
+ {
+ title: '自定义测试用例',
+ key: '1',
+ content: '这是自定测试用例内容'
+ },
+ {
+ title: '代码执行结果',
+ key: '2',
+ content: '这是自定代码执行结果'
+ }
+];
+
+const RightPaneCode = () => {
+
+ const [showDrawer, setShowDrawer] = useState(false);
+ const [defaultActiveKey, setDefaultActiveKey] = useState('1');
+ const [showTextResult, setShowTextResult] = useState(false);
+ const [editCode, setEditCode] = useState('console.log("test")');
+
+ // 打开设置
+ const handleShowDrawer = () => {
+ setShowDrawer(true);
+ }
+ // 关闭设置
+ const handleDrawerClose = () => {
+ setShowDrawer(false);
+ }
+ // 切换tab
+ const handleTabChange = (key) => {
+ setDefaultActiveKey(key);
+ }
+ // 显示/隐藏tab
+ const handleShowControl = () => {
+ setShowTextResult(!showTextResult);
+ }
+ // 沉浸tab内容
+ const tabs = tabsArrs.map((tab) => (
+
+
+
+ ));
+
+ const handleEditorChange = (newValue, e) => {
+ setEditCode(newValue);
+ }
+
+ const classNames = showTextResult ? 'control_tab active' : 'control_tab';
+ const editorOptions = {
+ selectOnLineNumbers: true,
+ automaticLayout: true,
+ fontSize: '16px',
+ revealHorizontalRightPadding: 0,
+ scrollBeyondLastLine: false,
+ smoothScrolling: true
+ }
+ return (
+
+
+
+ ts.js
+ 已保存
+
+
+ {/** 代码编辑器 */}
+
+ {/* 控制台信息 */}
+
+
+
+ Some contents...
+ Some contents...
+ Some contents...
+
+
+ );
+}
+
+export default RightPaneCode;
diff --git a/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneControl.js b/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneControl.js
new file mode 100644
index 000000000..fd631a622
--- /dev/null
+++ b/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneControl.js
@@ -0,0 +1,71 @@
+import './index.scss';
+
+import React, { Component } from 'react';
+import { Tabs, Button, Icon } from 'antd';
+import InitTabCtx from './initTabCtx';
+
+const { TabPane } = Tabs;
+
+const tabsArrs = [
+ {
+ title: '自定义测试用例',
+ key: '1',
+ content: '这是自定测试用例内容'
+ },
+ {
+ title: '代码执行结果',
+ key: '2',
+ content: '这是自定代码执行结果'
+ }
+];
+
+class RightPaneControl extends Component {
+
+ state = {
+ defaultActiveKey: '1'
+ }
+
+ handleTabChange = (key) => {
+ this.setState({
+ defaultActiveKey: key,
+ })
+ }
+
+ handleShowControl = () => {
+ this.setState((oldState) => ({
+ showTextResult: !oldState.showTextResult
+ }))
+ }
+
+ render () {
+ const { defaultActiveKey, showTextResult } = this.state;
+ // tab内容区块
+ const tabs = tabsArrs.map((tab) => (
+
+
+
+ ));
+
+ return (
+
+ )
+ }
+}
+
+export default RightPaneControl;
diff --git a/public/react/src/modules/developer/newOrEditTask/rightpane/index.js b/public/react/src/modules/developer/newOrEditTask/rightpane/index.js
new file mode 100644
index 000000000..b47c26425
--- /dev/null
+++ b/public/react/src/modules/developer/newOrEditTask/rightpane/index.js
@@ -0,0 +1,20 @@
+/*
+ * @Description: 右侧部分: 包含代码块与控制区
+ * @Author: tangjiang
+ * @Date: 2019-11-18 08:42:40
+ * @Last Modified by: tangjiang
+ * @Last Modified time: 2019-11-18 22:58:39
+ */
+
+import React from 'react';
+import RightPaneCode from './RightPaneCode';
+
+const RightPane = () => {
+
+ return (
+
+ );
+
+}
+
+export default RightPane;
diff --git a/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss b/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss
new file mode 100644
index 000000000..c9088d528
--- /dev/null
+++ b/public/react/src/modules/developer/newOrEditTask/rightpane/index.scss
@@ -0,0 +1,77 @@
+.right_pane_code_wrap{
+ position: relative;
+ // justify-content: center;
+ background-color: #222;
+ height: 100%;
+ // justify-content: ;
+ .code-title,
+ .controller-pane,
+ .pane_control_opts{
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ // padding: 0 30px;
+ background: #000;
+ color: #fff;
+ }
+ .code-title,
+ .pane_control_opts{
+ padding: 0 30px;
+ }
+
+ .code-title{
+ height: 56px;
+ .code-icon{
+ cursor: pointer;
+ }
+ }
+ // .controller-pane{
+ // min-height: 56px;
+ // background-color: #222;
+ // }
+ .code-pane-wrap{
+ height: 800px;
+ // position: absolute;
+ // top: 56px;
+ // bottom: 56px;
+ // width: 100%;
+ }
+
+ .pane_control_area{
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ // height: 56px;
+ .control_tab{
+ position: absolute;
+ bottom: -325px;
+ width: 100%;
+ transition: all .2s;
+ opacity: 0;
+ &.active{
+ bottom: 0;
+ opacity: 1;
+ }
+ }
+ }
+ .pane_control_opts{
+ height: 56px;
+ }
+
+ .ant-tabs-bar{
+ padding: 0 10px;
+ margin: 0px;
+ border-bottom: transparent;
+ }
+ .ant-tabs-ink-bar{
+ bottom: 1px;
+ }
+ // .tab_ctx_area.pos_center{
+ // background: #222;
+ // }
+ .pane_control_opts{
+ display: flex;
+ justify-content: space-between;
+ z-index: 20;
+ }
+}
diff --git a/public/react/src/modules/developer/newOrEditTask/rightpane/initTabCtx/index.js b/public/react/src/modules/developer/newOrEditTask/rightpane/initTabCtx/index.js
new file mode 100644
index 000000000..39821fcef
--- /dev/null
+++ b/public/react/src/modules/developer/newOrEditTask/rightpane/initTabCtx/index.js
@@ -0,0 +1,41 @@
+/*
+ * @Description: 显示tab中的内容
+ * @Author: tangjiang
+ * @Date: 2019-11-18 10:43:03
+ * @Last Modified by: tangjiang
+ * @Last Modified time: 2019-11-18 11:35:12
+ */
+import './index.scss';
+import React, { PureComponent } from 'react';
+import { Icon } from 'antd';
+
+const tabCtx = (ctx, props) => ({ctx}
);
+const loadingCtx = (加载中...);
+const loadedCtx = (加载完成);
+const maps = {
+ // default: (ctx, position) => ({ctx}
),
+ // loading: (ctx, position) => ({ctx}
),
+ // loaded: (ctx, position) => ({ctx}
),
+ // final: (ctx, position) => ({ctx}
)
+ default: (ctx, position) => tabCtx(ctx, { className: `tab_ctx_area tab_ctx_default pos_${position}` }),
+ loading: (ctx, position) => tabCtx(loadingCtx, { className: `tab_ctx_area tab_ctx_loading pos_${position}` }),
+ loaded: (ctx, position) => tabCtx(loadedCtx, { className: `tab_ctx_area tab_ctx_loaded pos_${position}` }),
+ final: (ctx, position) => tabCtx(ctx, { className: `tab_ctx_area tab_ctx_final pos_${position}` })
+}
+
+export default class InitTabCtx extends PureComponent {
+
+render () {
+ /**
+ * @param state 当前状态 default: 显示提示信息 init: 加载初始内容 loading: 加载中 loaded: 加载完成 final: 显示最终内容
+ * @param position: start | cetner | end
+ * @returns
+ */
+ const { state, ctx, position = 'start' } = this.props;
+ return(
+
+ { maps[state](ctx, position) }
+
+ )
+ }
+}
diff --git a/public/react/src/modules/developer/newOrEditTask/rightpane/initTabCtx/index.scss b/public/react/src/modules/developer/newOrEditTask/rightpane/initTabCtx/index.scss
new file mode 100644
index 000000000..daa488e88
--- /dev/null
+++ b/public/react/src/modules/developer/newOrEditTask/rightpane/initTabCtx/index.scss
@@ -0,0 +1,28 @@
+.tab_ctx_area{
+ display: flex;
+ height: 100%;
+ color: #666;
+ font-size: 14px;
+ &.pos_start{
+ justify-content: flex-start;
+ }
+ &.pos_center{
+ justify-content: center;
+ align-items: center;
+ }
+ &.pos_end{
+ justify-content: flex-end;
+ }
+ .ctx_loading,
+ .ctx_loaded{
+ display: flex;
+ position: relative;
+ flex-direction: column;
+ top: -20px;
+ color: #1890ff;
+ .ctx_icon{
+ font-size: 40px;
+ margin-bottom: 10px;
+ }
+ }
+}
diff --git a/public/react/src/modules/tpm/NewHeader.js b/public/react/src/modules/tpm/NewHeader.js
index 2c6372d66..cb31f9afa 100644
--- a/public/react/src/modules/tpm/NewHeader.js
+++ b/public/react/src/modules/tpm/NewHeader.js
@@ -806,6 +806,12 @@ submittojoinclass=(value)=>{
}
}else {
+ const developer = {
+ name: '开发者社区',
+ link: '/developer',
+ hidden: false
+ };
+ mygetHelmetapi2.navbar.push(developer);
for(var i=0;i{
headtypes = '/crowdsourcing';
}else if(match.path.startsWith('/moop_cases')){
headtypes = '/moop_cases';
- }else {
+ }else if(match.path.startsWith('/developer')){
+ headtypes = '/developer'
+ }else {
headtypes = '/';
}
}
@@ -848,7 +856,9 @@ submittojoinclass=(value)=>{
headtypes = '/crowdsourcing';
}else if(match.path.startsWith('/moop_cases')){
headtypes = '/moop_cases';
- }else {
+ }else if(match.path.startsWith('/developer')){
+ headtypes = '/developer'
+ }else {
headtypes = '/';
}
}
@@ -867,7 +877,9 @@ submittojoinclass=(value)=>{
headtypes = '/crowdsourcing';
}else if(match.path.startsWith('/moop_cases')){
headtypes = '/moop_cases';
- }else {
+ }else if(match.path.startsWith('/developer')){
+ headtypes = '/developer'
+ }else {
headtypes = '/';
}
}
diff --git a/public/react/src/modules/tpm/TPMIndex.css b/public/react/src/modules/tpm/TPMIndex.css
index 740ae8a20..f862f9b7f 100644
--- a/public/react/src/modules/tpm/TPMIndex.css
+++ b/public/react/src/modules/tpm/TPMIndex.css
@@ -1,3 +1,7 @@
+html{
+ height: 100%;
+ overflow: hidden;
+}
body {
overflow: auto !important;
font-family: "Microsoft YaHei";
@@ -6,7 +10,7 @@ body {
#root {
/* ie兼容性 */
position: relative;
- min-height: 100%;
+ min-height: 100%;
}
body>.-task-title {
opacity: 1 !important;
diff --git a/public/react/src/modules/tpm/TPMIndexHOC.js b/public/react/src/modules/tpm/TPMIndexHOC.js
index 7b665ba0a..33cc7faff 100644
--- a/public/react/src/modules/tpm/TPMIndexHOC.js
+++ b/public/react/src/modules/tpm/TPMIndexHOC.js
@@ -683,7 +683,9 @@ export function TPMIndexHOC(WrappedComponent) {
`
.newContainers{
min-width: 1200px;
- max-width: unset;
+ max-width: unset;
+ height: 100%;
+ min-height: 100%;
overflow: hidden;
}
.newHeaders{
@@ -703,6 +705,7 @@ export function TPMIndexHOC(WrappedComponent) {
}
.indexHOC > .ant-spin-nested-loading {
background: #000;
+ height: 100%;
}
.indexHOC > .ant-spin-nested-loading > div > .ant-spin .ant-spin-dot {
top: 50% !important;
diff --git a/public/react/src/redux/README.md b/public/react/src/redux/README.md
new file mode 100644
index 000000000..196e24233
--- /dev/null
+++ b/public/react/src/redux/README.md
@@ -0,0 +1,128 @@
+# actions 文件下文件的配置
+
+ ## actionTypes.js
+ 此文件指定所有请求的action类型, 类型名统一用大写形式表示
+
+ const types = {
+ ADD_TODO: 'ADD_TODO'
+ }
+
+ export default types;
+
+ ## testActions.js
+ 此文件针对每一个模块指定 action 方法, 最终通过 index.js 文件统一导出
+
+ import types from './actionTypes';
+
+ export default function toggleTodo() {
+ return {
+ type: types.ADD_TODO
+ }
+ }
+
+ ## index.js
+ 此文件为默认的导出文件, 里边包含所有指定的其它 actions 文件
+
+ import toggleTodo from './testAction.js';
+
+ export default {
+ toggleTodo
+ }
+
+# reducers 文件下文件配置
+
+ ## testReducer.js
+ 修改state值的唯一方式, 根据 action 类型打开对应的 reducer
+
+ import types from '../actions/actionTypes';
+
+ const initialState = { // 指定状态
+ count: 0
+ };
+
+ const testReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case types.ADD_TODO:
+ return {
+ ...state,
+ count: state.count + 1
+ };
+ default:
+ return state;
+ }
+ }
+
+ export default testReducer;
+
+# stores 文件配置
+
+ import { createStore } from 'redux';
+ import rootReducer from '../reducers';
+
+ const configureStore = () => createStore(rootReducer);
+
+ export default configureStore;
+
+
+# 使用
+
+```
+ import React from 'react';
+ import { Provider } from 'react-redux';
+ import DeveloperHome from './DeveloperHome';
+ // import store from '../../redux/stors/configureStore';
+ import configureStore from '../../redux/stores/configureStore'
+ const store = configureStore();
+
+ const App = () => {
+ return (
+
+
+
+ );
+ }
+
+ export default App;
+```
+
+````
+
+ import React, { PureComponent, Fragment } from 'react';
+ import { connect } from 'react-redux';
+ import actions from '../../redux/actions';
+
+ class DeveloperHome extends PureComponent {
+
+ render () {
+ const { testReducer, handleClick } = this.props;
+ return (
+
+ Developer Home, { testReducer.count }
+
+
+ );
+ }
+ }
+
+ /**
+ * @param {*} state store
+ * @param {*} ownProps DeveloperHome 中的 props
+ */
+ const mapStateToProps = (state, ownProps) => {
+ return {
+ testReducer: state.testReducer
+ };
+ }
+
+
+ const mapDispatchToProps = (dispatch) => {
+ return {
+ handleClick: () => dispatch(actions.toggleTodo())
+ }
+ }
+
+ export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+ )(DeveloperHome);
+````
\ No newline at end of file
diff --git a/public/react/src/redux/actions/actionTypes.js b/public/react/src/redux/actions/actionTypes.js
new file mode 100644
index 000000000..def2e819c
--- /dev/null
+++ b/public/react/src/redux/actions/actionTypes.js
@@ -0,0 +1,12 @@
+/*
+ * @Description: action类型
+ * @Author: tangjiang
+ * @Date: 2019-11-13 20:05:39
+ * @Last Modified by: tangjiang
+ * @Last Modified time: 2019-11-14 09:29:45
+ */
+const types = {
+ ADD_TODO: 'ADD_TODO'
+}
+
+export default types;
diff --git a/public/react/src/redux/actions/index.js b/public/react/src/redux/actions/index.js
new file mode 100644
index 000000000..1c174febd
--- /dev/null
+++ b/public/react/src/redux/actions/index.js
@@ -0,0 +1,13 @@
+/*
+ * @Description: 全局导出 action 类型
+ * @Author: tangjiang
+ * @Date: 2019-11-13 20:12:23
+ * @Last Modified by: tangjiang
+ * @Last Modified time: 2019-11-14 09:55:47
+ */
+
+import toggleTodo from './testAction.js';
+
+export default {
+ toggleTodo
+}
\ No newline at end of file
diff --git a/public/react/src/redux/actions/testAction.js b/public/react/src/redux/actions/testAction.js
new file mode 100644
index 000000000..7b5734bec
--- /dev/null
+++ b/public/react/src/redux/actions/testAction.js
@@ -0,0 +1,7 @@
+import types from './actionTypes';
+
+export default function toggleTodo() {
+ return {
+ type: types.ADD_TODO
+ }
+}
diff --git a/public/react/src/redux/reducers/index.js b/public/react/src/redux/reducers/index.js
new file mode 100644
index 000000000..3244302a4
--- /dev/null
+++ b/public/react/src/redux/reducers/index.js
@@ -0,0 +1,14 @@
+/*
+ * @Description: 全局导出 reducers
+ * @Author: tangjiang
+ * @Date: 2019-11-13 20:12:54
+ * @Last Modified by: tangjiang
+ * @Last Modified time: 2019-11-14 09:55:10
+ */
+
+import { combineReducers } from 'redux';
+import testReducer from './testReducer';
+
+export default combineReducers({
+ testReducer
+});
diff --git a/public/react/src/redux/reducers/testReducer.js b/public/react/src/redux/reducers/testReducer.js
new file mode 100644
index 000000000..b01407732
--- /dev/null
+++ b/public/react/src/redux/reducers/testReducer.js
@@ -0,0 +1,30 @@
+import types from '../actions/actionTypes';
+
+const initialState = {
+ count: 0
+};
+
+// export default function (state = initialState, action) {
+// switch (action.type) {
+// case types.ADD_TODO:
+// return {
+// ...state,
+// count: state.count + 1
+// };
+// default:
+// return state;
+// }
+// }
+const testReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case types.ADD_TODO:
+ return {
+ ...state,
+ count: state.count + 1
+ };
+ default:
+ return state;
+ }
+}
+
+export default testReducer;
\ No newline at end of file
diff --git a/public/react/src/redux/stores/configureStore.js b/public/react/src/redux/stores/configureStore.js
new file mode 100644
index 000000000..de80c0b69
--- /dev/null
+++ b/public/react/src/redux/stores/configureStore.js
@@ -0,0 +1,18 @@
+/*
+ * @Description: 指定容器并绑定 reducers
+ * @Author: tangjiang
+ * @Date: 2019-11-13 20:13:21
+ * @Last Modified by: tangjiang
+ * @Last Modified time: 2019-11-14 19:20:44
+ */
+
+import { createStore, applyMiddleware } from 'redux';
+import thunk from 'redux-thunk';
+import rootReducer from '../reducers';
+
+const configureStore = () => createStore(
+ rootReducer,
+ applyMiddleware(thunk)
+);
+
+export default configureStore;
From dca9db4482773e54b916d3b5e799ddf70e8f6194 Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Tue, 19 Nov 2019 10:51:56 +0800
Subject: [PATCH 02/17] =?UTF-8?q?=E5=B7=A6=E4=BE=A7tab?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../modules/developer/newOrEditTask/index.js | 7 +++-
.../newOrEditTask/leftpane/commitTab/index.js | 14 +++++++
.../newOrEditTask/leftpane/editorTab/index.js | 15 +++++++
.../developer/newOrEditTask/leftpane/index.js | 40 +++++++++++++++++++
.../newOrEditTask/leftpane/prevTab/index.js | 15 +++++++
.../newOrEditTask/rightpane/RightPaneCode.js | 7 +---
6 files changed, 91 insertions(+), 7 deletions(-)
create mode 100644 public/react/src/modules/developer/newOrEditTask/leftpane/commitTab/index.js
create mode 100644 public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
create mode 100644 public/react/src/modules/developer/newOrEditTask/leftpane/prevTab/index.js
diff --git a/public/react/src/modules/developer/newOrEditTask/index.js b/public/react/src/modules/developer/newOrEditTask/index.js
index 0b924d3c3..cc659363f 100644
--- a/public/react/src/modules/developer/newOrEditTask/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/index.js
@@ -3,7 +3,7 @@
* @Author: tangjiang
* @Date: 2019-11-15 16:38:34
* @Last Modified by: tangjiang
- * @Last Modified time: 2019-11-18 23:21:25
+ * @Last Modified time: 2019-11-19 09:10:45
*/
import './index.scss';
import React, { Component } from 'react';
@@ -11,6 +11,7 @@ import { connect } from 'react-redux';
import SplitPane from 'react-split-pane';// import { Form } from 'antd';
import { Button, Icon } from 'antd';
import { Link } from 'react-router-dom';
+import LeftPane from './leftpane';
import RightPane from './rightpane';
class NewOrEditTask extends Component {
@@ -26,7 +27,9 @@ class NewOrEditTask extends Component {
- You can use a div component
+
+
+
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/commitTab/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/commitTab/index.js
new file mode 100644
index 000000000..3270bd7bb
--- /dev/null
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/commitTab/index.js
@@ -0,0 +1,14 @@
+import React, { PureComponent } from 'react';
+import connect from 'react-redux';
+
+class CommitTab extends PureComponent {
+
+ render () {
+ return (
+ 提交页
+ )
+ }
+}
+
+// export default connect()(CommitTab);
+export default CommitTab;
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
new file mode 100644
index 000000000..01ebf42f8
--- /dev/null
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
@@ -0,0 +1,15 @@
+import React, { PureComponent } from 'react';
+import connect from 'react-redux';
+
+class EditTab extends PureComponent {
+
+ componentDidMount () {}
+ render () {
+ return (
+ 编辑页
+ )
+ }
+}
+
+// export default connect()(EditTab);
+export default EditTab;
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
index e69de29bb..ee7c309f2 100644
--- a/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
@@ -0,0 +1,40 @@
+import React, { useState } from 'react';
+import { Tabs } from 'antd';
+import EditorTab from './editorTab';
+import PrevTab from './prevTab';
+import CommitTab from './commitTab';
+
+const { TabPane } = Tabs;
+
+const LeftPane = () => {
+
+ const [defaultActiveKey, setDefaultActiveKey] = useState('2');
+
+ const tabArrs = [
+ { title: '编辑', key: '1', content: EditorTab },
+ { title: '预览', key: '2', content: PrevTab },
+ { title: '提交记录', key: '3', content: CommitTab },
+ ];
+
+ const tabs = tabArrs.map((tab) => {
+ const Comp = tab.content;
+ return (
+
+
+
+ )
+ });
+
+ // tab切换时
+ const handleTabChange = (key) => {
+ setDefaultActiveKey(key);
+ }
+
+ return (
+
+ { tabs }
+
+ )
+}
+
+export default LeftPane;
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/prevTab/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/prevTab/index.js
new file mode 100644
index 000000000..34ca2e815
--- /dev/null
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/prevTab/index.js
@@ -0,0 +1,15 @@
+import React, { PureComponent } from 'react';
+// import connect from 'react-redux';
+
+class PrevTab extends PureComponent {
+
+ state = {}
+ render () {
+ return (
+ 预览页
+ )
+ }
+}
+
+// export default connect()(PrevTab);
+export default PrevTab;
\ No newline at end of file
diff --git a/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneCode.js b/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneCode.js
index c735b62ed..98fb3d7a6 100644
--- a/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneCode.js
+++ b/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneCode.js
@@ -3,7 +3,7 @@
* @Author: tangjiang
* @Date: 2019-11-18 08:42:04
* @Last Modified by: tangjiang
- * @Last Modified time: 2019-11-19 08:39:28
+ * @Last Modified time: 2019-11-19 08:55:08
*/
import './index.scss';
@@ -66,10 +66,7 @@ const RightPaneCode = () => {
const editorOptions = {
selectOnLineNumbers: true,
automaticLayout: true,
- fontSize: '16px',
- revealHorizontalRightPadding: 0,
- scrollBeyondLastLine: false,
- smoothScrolling: true
+ fontSize: '16px'
}
return (
From ebc175b6559f30c7064cbae086728b81eee8a975 Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Tue, 19 Nov 2019 16:27:50 +0800
Subject: [PATCH 03/17] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=88=96=E7=BC=96?=
=?UTF-8?q?=E8=BE=91=E5=B7=A6=E4=BE=A7=E5=86=85=E5=AE=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../modules/developer/newOrEditTask/index.js | 4 ++--
.../newOrEditTask/leftpane/editorTab/index.js | 6 ++++--
.../developer/newOrEditTask/leftpane/index.js | 17 +++++++++++++----
.../developer/newOrEditTask/leftpane/index.scss | 5 +++++
4 files changed, 24 insertions(+), 8 deletions(-)
create mode 100644 public/react/src/modules/developer/newOrEditTask/leftpane/index.scss
diff --git a/public/react/src/modules/developer/newOrEditTask/index.js b/public/react/src/modules/developer/newOrEditTask/index.js
index cc659363f..05f599f63 100644
--- a/public/react/src/modules/developer/newOrEditTask/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/index.js
@@ -3,7 +3,7 @@
* @Author: tangjiang
* @Date: 2019-11-15 16:38:34
* @Last Modified by: tangjiang
- * @Last Modified time: 2019-11-19 09:10:45
+ * @Last Modified time: 2019-11-19 11:34:19
*/
import './index.scss';
import React, { Component } from 'react';
@@ -27,7 +27,7 @@ class NewOrEditTask extends Component {
-
+
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 01ebf42f8..50f67d1b3 100644
--- a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
@@ -1,12 +1,14 @@
import React, { PureComponent } from 'react';
+import { Form } from 'antd';
import connect from 'react-redux';
class EditTab extends PureComponent {
- componentDidMount () {}
render () {
return (
- 编辑页
+
+
+
)
}
}
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
index ee7c309f2..08f788796 100644
--- a/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
@@ -1,3 +1,12 @@
+/*
+ * @Description: 左侧编辑 / 评论 / 提交记录
+ * @Author: tangjiang
+ * @Date: 2019-11-19 11:35:30
+ * @Last Modified by: tangjiang
+ * @Last Modified time: 2019-11-19 11:36:10
+ */
+
+import './index.scss';
import React, { useState } from 'react';
import { Tabs } from 'antd';
import EditorTab from './editorTab';
@@ -8,12 +17,12 @@ const { TabPane } = Tabs;
const LeftPane = () => {
- const [defaultActiveKey, setDefaultActiveKey] = useState('2');
+ const [defaultActiveKey, setDefaultActiveKey] = useState('prev');
const tabArrs = [
- { title: '编辑', key: '1', content: EditorTab },
- { title: '预览', key: '2', content: PrevTab },
- { title: '提交记录', key: '3', content: CommitTab },
+ { title: '编辑', key: 'editor', content: EditorTab },
+ { title: '预览', key: 'prev', content: PrevTab },
+ { title: '提交记录', key: 'commit', content: CommitTab },
];
const tabs = tabArrs.map((tab) => {
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/index.scss b/public/react/src/modules/developer/newOrEditTask/leftpane/index.scss
new file mode 100644
index 000000000..f4d398d20
--- /dev/null
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/index.scss
@@ -0,0 +1,5 @@
+.split-pane-left{
+ .ant-tabs-nav-wrap{
+ padding: 0 30px;
+ }
+}
\ No newline at end of file
From abecab3b8ded0ee56fb9407460e7c4a9c9468e5a Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Tue, 19 Nov 2019 16:29:27 +0800
Subject: [PATCH 04/17] competions
---
.../Competitimain/CompetitionsIndex.js | 225 +++++++
.../Competitimain/Competitionsindex.css | 163 +++++
.../Competition_teams/Competitionteams.css | 53 ++
.../Competition_teams/Competitionteams.js | 267 ++++++++
.../Competitioncommon/CompetitionCommon.css | 438 +++++++++++++
.../Competitioncommon/CompetitionCommon.js | 548 ++++++++++++++++
.../CompetitionContents.js | 45 ++
.../CompetitionContentsChart.js | 423 +++++++++++++
.../CompetitionContentsMd.js | 232 +++++++
.../CompetitionContentspdf.js | 64 ++
.../Bankcardnumberverification.js | 292 +++++++++
.../CompetitionContentspdfdownload.css | 24 +
.../CompetitionContentspdfdownload.js | 215 +++++++
.../CompetitionContentspdfpeopledata.js | 596 ++++++++++++++++++
.../Mailboxvalidation.js | 270 ++++++++
.../Phonenumberverification.js | 262 ++++++++
.../mycompetotionchild.css | 314 +++++++++
.../courses/competitions/Competitions.js | 92 +++
18 files changed, 4523 insertions(+)
create mode 100644 public/react/src/modules/courses/competitions/Competitimain/CompetitionsIndex.js
create mode 100644 public/react/src/modules/courses/competitions/Competitimain/Competitionsindex.css
create mode 100644 public/react/src/modules/courses/competitions/Competition_teams/Competitionteams.css
create mode 100644 public/react/src/modules/courses/competitions/Competition_teams/Competitionteams.js
create mode 100644 public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommon.css
create mode 100755 public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommon.js
create mode 100644 public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContents.js
create mode 100644 public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentsChart.js
create mode 100644 public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentsMd.js
create mode 100644 public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdf.js
create mode 100644 public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Bankcardnumberverification.js
create mode 100644 public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.css
create mode 100644 public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.js
create mode 100644 public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfpeopledata.js
create mode 100644 public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Mailboxvalidation.js
create mode 100644 public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Phonenumberverification.js
create mode 100644 public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/mycompetotionchild.css
create mode 100644 public/react/src/modules/courses/competitions/Competitions.js
diff --git a/public/react/src/modules/courses/competitions/Competitimain/CompetitionsIndex.js b/public/react/src/modules/courses/competitions/Competitimain/CompetitionsIndex.js
new file mode 100644
index 000000000..5a341726d
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitimain/CompetitionsIndex.js
@@ -0,0 +1,225 @@
+import React, { Component } from 'react';
+import { Link } from 'react-router-dom';
+import { Menu, Icon, List, Avatar,Row, Col,Tag,Pagination,Alert} from 'antd';
+import {getImageUrl} from 'educoder';
+import axios from 'axios';
+import './Competitionsindex.css';
+import NoneData from "../../courses/coursesPublic/NoneData";
+import LoadingSpin from '../../../common/LoadingSpin';
+
+class CompetitionsIndex extends Component{
+ constructor(props) {
+ super(props)
+ this.state={
+ current: 'all',
+ datas:undefined,
+ page:1,
+ category:undefined
+
+ }
+ }
+
+ componentDidMount(){
+ window.document.title = '竞赛';
+ let{category,page}=this.state;
+ this.getdata(category,page)
+ }
+
+ getdata=(category,page)=>{
+ const Url =`/competitions.json`;
+ axios.get(Url,{params:{
+ category:category,
+ page:page,
+ per_page:15,
+ }
+ }).then((response) => {
+ if(response.status===200){
+ this.setState({
+ datas:response.data.competitions,
+ count:response.data.count,
+ })
+ }
+ })
+ .catch(function (error) {
+ console.log(error);
+ });
+ }
+
+
+ handleClick = e => {
+ this.setState({
+ current: e.key,
+ datas:undefined
+ });
+ let{category,page}=this.state;
+ this.getdata(e.key,page)
+ };
+
+ PaginationCourse=(pageNumber)=>{
+ let {category}=this.state;
+ this.setState({
+ page: pageNumber,
+ })
+ this.getdata(category,pageNumber);
+ }
+
+ render() {
+ let {datas,page,count}=this.state;
+
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+}
+export default CompetitionsIndex;
diff --git a/public/react/src/modules/courses/competitions/Competitimain/Competitionsindex.css b/public/react/src/modules/courses/competitions/Competitimain/Competitionsindex.css
new file mode 100644
index 000000000..cddb1492b
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitimain/Competitionsindex.css
@@ -0,0 +1,163 @@
+.teamsLayout{background: transparent !important;}
+
+.competitionstitle{
+ height:50px !important;
+ border-radius: 6px;
+ background: #fff;
+ display: flex;
+ justify-content: center;
+}
+
+.competitionstitle2{
+ height:50px !important;
+ margin-left: 30px !important;
+ background: #fff;
+ width: 1200px;
+}
+.CompetitionsList{
+ position: relative;
+ /*max-height: 210px;*/
+}
+.competitonimg{
+ position: absolute;
+ right: -5px;
+ width: 80px;
+ top: 20px;
+}
+
+.ant-menu-horizontal {
+ border-bottom:none !important;
+}
+
+
+.competitionsvalue{
+ font-size: 16px;
+ font-family: PingFangSC-Medium,PingFangSC;
+ font-weight: 500;
+}
+
+.competitionmr50 {
+ margin-right: 50px !important;
+}
+
+.CompetitionsIndex .ant-list-item{
+ background: #fff !important;
+ margin-top: 20px;
+ border: none !important;
+}
+
+.CompetitionsIndex .ant-list-item{
+ padding:25px;
+}
+
+.CompetitionsIndex .ant-list-item-meta-title{
+ height:28px;
+ font-size:28px;
+ font-family:PingFangSC-Regular,PingFangSC;
+ font-weight:400;
+ color:rgba(5,16,26,1);
+ line-height:28px;
+}
+
+.CompetitionsIndex .ant-list-vertical .ant-list-item-meta{
+ margin-bottom: 20px !important;
+}
+
+.CompetitionsIndex .ant-list-vertical .ant-list-item-action {
+ margin-top: 20px;
+ margin-left: auto;
+}
+
+.CompetitionsIndex .ant-list-item-action-split{
+ display: none !important;
+}
+
+.CompetitionsIndexdadels{
+ font-family: PingFangSC-Regular,PingFangSC;
+ font-weight: 400;
+ color: #777777;
+ margin-bottom: 14px;
+ text-align: center;
+}
+
+.CompetitionsIndexbottomvalue{
+ font-size: 24px;
+ font-family: ArialMT;
+ color: rgba(5,16,26,1);
+ text-align: center;
+}
+
+.CompetitionsIndex .gutter-row{
+ /*margin-right:20px;*/
+ width: 33%;
+}
+
+.pt50{
+ padding-top: 50px;
+}
+
+.competitionstitles{
+ max-width: 789px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ display: inline-block;
+ margin-right: 15px;
+ color:#000 !important;
+}
+
+.competitionsrelative{
+ position: absolute;
+ top: 28px;
+}
+
+.CompetitionsList:hover{
+ /*box-shadow: 0 2px 6px rgba(51,51,51,.09);*/
+ box-shadow:3px 4px 10px 2px rgba(229,229,229,0.5);
+ opacity: 1;
+ border-radius: 2px;
+}
+.endedfont{
+ color:#000 !important;
+}
+.CompetitionsListzhezhao{
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 1206px;
+ height: 100%;
+ z-index: 10000;
+ display: none;
+ background: rgba(0,0,0,0.33);
+ text-align: center;
+ color: #fff;
+ font-size: 22px;
+
+ align-items: center;
+ justify-content: space-around;
+ flex-direction: column;
+}
+.CompetitionsList:hover .CompetitionsListzhezhao{
+ display: block;
+ display: flex;
+}
+.competitionstitlesshou:hover a{
+ cursor: pointer;
+ color: #1c91e8 !important;
+}
+
+.competitionstitlesshou{
+ cursor: pointer;
+}
+
+
+.Competitionshead{
+ background-color: #2d28ba !important;
+ background-position: center !important;
+ background-position: 50% !important;
+ background-repeat: no-repeat !important;
+}
+
+.span666{
+ color:#666666 !important;
+}
\ No newline at end of file
diff --git a/public/react/src/modules/courses/competitions/Competition_teams/Competitionteams.css b/public/react/src/modules/courses/competitions/Competition_teams/Competitionteams.css
new file mode 100644
index 000000000..af1f40aba
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competition_teams/Competitionteams.css
@@ -0,0 +1,53 @@
+.teamsLayout{background: transparent !important;}
+.teamsLayout .teamsLayoutitle{
+ font-size:18px;
+ font-family:PingFangSC-Semibold,PingFang SC;
+ font-weight:600;
+ color:rgba(5,16,26,1);
+ line-height:25px;
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+.teamsLayoutTable .ant-table-bordered .ant-table-thead > tr > th, .ant-table-bordered .ant-table-tbody > tr > td {
+ border-right: 1px solid transparent !important;
+}
+
+.teamsLayoutTable .ant-table-body .ant-table-thead > tr> th:nth-last-child(1){
+ border-right: 1px solid #e8e8e8 !important;
+}
+
+.teamsLayoutTable .ant-table-body .ant-table-tbody > tr> td:nth-last-child(1){
+ border-right: 1px solid #e8e8e8 !important;
+}
+
+.teamsLayoutTable .ant-table-bordered .ant-table-thead > tr > th{
+ background:#EEEEEE;
+ font-size: 14px;
+ font-family: PingFangSC-Regular,PingFang SC;
+ font-weight: 400;
+ color: rgba(102,102,102,1);
+ line-height: 20px;
+}
+
+.teamsLayoutTable .ant-table-bordered .ant-table-tbody > tr > th{
+ background:#EEEEEE;
+ font-size:14px;
+ font-family:PingFangSC-Regular,PingFang SC;
+ font-weight:400;
+ color:rgba(5,16,26,1);
+ line-height:20px;
+}
+
+.teamsLayout .mt40{
+ margin-top: 40px !important;
+}
+
+.teamsLayoutheji{
+ color: #878787;
+ font-size: 16px;
+}
+
+.teamsLayoucolor-orange {
+ color: #ff6800!important;
+ font-size: 16px;
+}
\ No newline at end of file
diff --git a/public/react/src/modules/courses/competitions/Competition_teams/Competitionteams.js b/public/react/src/modules/courses/competitions/Competition_teams/Competitionteams.js
new file mode 100644
index 000000000..be6c2e68d
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competition_teams/Competitionteams.js
@@ -0,0 +1,267 @@
+import React, { Component } from 'react';
+import { Breadcrumb,Layout,Table, Divider, Tag,Badge,Tooltip} from 'antd';
+import { Link } from 'react-router-dom';
+import axios from 'axios';
+
+
+import './Competitionteams.css';
+const { Content } = Layout;
+
+class Competitionteams extends Component{
+ constructor(props) {
+ super(props)
+ this.state={
+ shixundata: undefined,
+ coursedata:undefined,
+ }
+ }
+
+ componentDidMount(){
+ window.document.title = '竞赛';
+ if(this.props.match.params.identifier!=null){
+ let url=`/competitions/${this.props.match.params.identifier}/common_header.json`;
+ axios.get(url).then((response) => {
+ if(response.status===200){
+ this.setState({
+ data:response.data,
+ })
+ }
+ }).catch((error) => {
+ console.log(error)
+ })
+ }
+
+ this.getshixundata();
+ this.getcoursedata();
+ }
+
+ getshixundata=()=>{
+
+ const Url =`/competitions/${this.props.match.params.identifier}/competition_teams/${this.props.match.params.competition_team_id}/shixun_detail.json`;
+ axios.get(Url).then((response) => {
+ if(response.status===200){
+ // let data={
+ // shixuns: [
+ // {
+ // creator: "黄井泉", // 创建者
+ // shixun_name: "单链表的学习与应用(I)", // 实训名称
+ // shixun_identifier: "mnf6b7z3",
+ // forked: false, // false:原创
+ // myshixuns_count: 179, // 学习人数
+ // forked_myshixun_count: 0, // 被fork发布的学习人数
+ // valid_count: 82, // 有效作品数
+ // score: 1320 // 应用值
+ // }
+ // ],
+ // shixun_count: 1, // 实训总计
+ // total_myshixun_count: 179, // 学习人数总计
+ // total_forked_myshixun_count: 0, // 被fork发布的学习人数总计
+ // total_valid_count: 82, // 有效作品数总计
+ // total_shixun_score: 1320 // 应用值总计
+ // }
+ let data=response.data;
+
+ let newarr=data.shixuns;
+
+ let newobj={
+ creator:"合计:",
+ shixun_name:data.shixun_count,
+ myshixuns_count:data.total_myshixun_count,
+ forked_myshixun_count:data.total_forked_myshixun_count,
+ valid_count:data.total_valid_count,
+ score:data.total_shixun_score
+ }
+ newarr.push(newobj)
+
+ this.setState({
+ shixundata:newarr
+ })
+
+
+ }
+ })
+ .catch(function (error) {
+ console.log(error);
+ });
+
+
+
+
+ }
+
+ getcoursedata=()=>{
+ const Url =`/competitions/${this.props.match.params.identifier}/competition_teams/${this.props.match.params.competition_team_id}/course_detail.json`;
+
+ axios.get(Url).then((response) => {
+ if(response.status===200){
+ // let data={
+ // courses: [
+ // {
+ // creator: "周海芳", // 创建者
+ // creator_login: "Nancy", // login
+ // course_name: "大学计算机基础2018年秋季",
+ // course_id: 1502,
+ // students_count: 122, // 学生数量
+ // shixun_homework_count: 8, // 发布的实训作业数量
+ // valid_count: 977, // 有效作品数
+ // score: 29810 // 应用值
+ // }
+ // ],
+ // total_course_count: 1, // 课堂总计
+ // total_students_count: 122, // 学生数总计
+ // total_shixun_homework_count: 8, // 实训作业数总计
+ // total_valid_count: 977, // 有效作品数总计
+ // total_course_score: 29810 // 应用值总计
+ // }
+
+ let data=response.data;
+
+ let newarr=data.courses;
+
+ let newobj={
+ creator:"合计:",
+ course_name:data.total_course_count,
+ students_count:data.total_students_count,
+ shixun_homework_count:data.total_shixun_homework_count,
+ valid_count:data.total_valid_count,
+ score:data.total_course_score
+ }
+ newarr.push(newobj)
+
+ this.setState({
+ coursedata:newarr
+ })
+
+ }
+ })
+ .catch(function (error) {
+ console.log(error);
+ });
+
+
+ }
+
+ render() {
+ let {data}=this.state;
+ const shixuncolumns = [
+ {
+ title: '创建者',
+ dataIndex: 'creator',
+ key: 'creator',
+ render: (text, record) => {text}
,
+ },
+ {
+ title: '名称',
+ dataIndex: 'shixun_name',
+ key: 'shixun_name',
+ render: (text, record) =>
+ {text}{record.forked===true?:""}
,
+ },
+ {
+ title: '学习人数',
+ dataIndex: 'myshixuns_count',
+ key: 'myshixuns_count',
+ render: (text, record) => {text}
,
+ },
+ {
+ title: '被fork发布的学习人数',
+ dataIndex: 'forked_myshixun_count',
+ key: 'forked_myshixun_count',
+ render: (text, record) =>
+
+ {text}
+ ,
+ },
+ {
+ title: '有效作品数',
+ dataIndex: 'valid_count',
+ key: 'valid_count',
+ render: (text, record) =>
+
+ {text}
+ ,
+ },
+ {
+ title: '应用值',
+ dataIndex: 'score',
+ key: 'score',
+ render: (text, record) => {text}
,
+ },
+ ];
+
+ const coursecolumns = [
+ {
+ title: '创建者',
+ dataIndex: 'creator',
+ key: 'creator',
+ render: (text, record) => {text}
,
+ },
+ {
+ title: '名称',
+ dataIndex: 'course_name',
+ key: 'course_name',
+ render: (text, record) => {text}
,
+ },
+ {
+ title: '学生数量',
+ dataIndex: 'students_count',
+ key: 'students_count',
+ render: (text, record) => {text}
,
+ },
+ {
+ title: '发布的实训作业数量',
+ dataIndex: 'shixun_homework_count',
+ key: 'shixun_homework_count',
+ render: (text, record) =>
+ {text}
+ ,
+ },
+ {
+ title: '有效作品数',
+ dataIndex: 'valid_count',
+ key: 'valid_count',
+ render: (text, record) =>
+
+ {text}
+ ,
+ },
+ {
+ title: '应用值',
+ dataIndex: 'score',
+ key: 'score',
+ render: (text, record) => {text}
,
+ },
+ ];
+
+
+ // console.log(this.state.shixundata)
+ return (
+
+
+
+ {data&&data.name}
+ 报名
+ 战队详情
+
+
+
+
+ 实训项目
+
+
+
+ 翻转课堂
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+}
+export default Competitionteams;
diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommon.css b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommon.css
new file mode 100644
index 000000000..984498203
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommon.css
@@ -0,0 +1,438 @@
+.teamsLayout{background: transparent !important;}
+
+.teamsLayout .ant-layout-sider{
+ background: transparent !important;
+ flex: 0 0 180px !important;
+ max-width: 180px !important;
+ min-width: 180px !important;
+ width: 180px !important;
+}
+.teamsLayout .teamsLayoutitle{
+ font-size:18px;
+ font-family:PingFangSC-Semibold,PingFang SC;
+ font-weight:600;
+ color:rgba(5,16,26,1);
+ line-height:25px;
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+.teamsLayoutTable .ant-table-bordered .ant-table-thead > tr > th, .ant-table-bordered .ant-table-tbody > tr > td {
+ border-right: 1px solid transparent !important;
+}
+
+.teamsLayoutTable .ant-table-body .ant-table-thead > tr> th:nth-last-child(1){
+ border-right: 1px solid #e8e8e8 !important;
+}
+
+.teamsLayoutTable .ant-table-body .ant-table-tbody > tr> td:nth-last-child(1){
+ border-right: 1px solid #e8e8e8 !important;
+}
+
+.teamsLayoutTable .ant-table-bordered .ant-table-thead > tr > th{
+ background:#EEEEEE;
+ font-size: 14px;
+ font-family: PingFangSC-Regular,PingFang SC;
+ font-weight: 400;
+ color: rgba(102,102,102,1);
+ line-height: 20px;
+}
+
+.teamsLayoutTable .ant-table-bordered .ant-table-tbody > tr > th{
+ background:#EEEEEE;
+ font-size:14px;
+ font-family:PingFangSC-Regular,PingFang SC;
+ font-weight:400;
+ color:rgba(5,16,26,1);
+ line-height:20px;
+}
+
+.teamsLayout .mt40{
+ margin-top: 40px !important;
+}
+
+.teamsLayoutheji{
+ color: #878787;
+ font-size: 16px;
+}
+
+.teamsLayoucolor-orange {
+ color: #ff6800 !important;
+ font-size: 16px;
+}
+
+.CompetitionCommonbanner{
+ padding: 20px;
+ background:rgba(255,255,255,1);
+ box-shadow:3px 2px 12px 2px rgba(0,0,0,0.05);
+ position: relative;
+}
+
+.CompetitionCommonbannerfont{
+ height:100%;
+ width: 365px !important;
+ line-height: 34px;
+}
+
+.CompetitionCommonbannerfont .competitionbannerdiv:nth-child(1){
+ max-height:100px;
+ font-size:25px;
+ font-weight:400;
+ color:rgba(5,16,26,1);
+ line-height: 30px;
+}
+
+.CompetitionCommonbannerfont .competitionbannerdiv:nth-child(2){
+ max-height: 70px;
+ font-size:16px;
+ font-weight:400;
+ /*color:rgba(155,155,155,1);*/
+ color:#05101A;
+}
+
+.CompetitionCommonbannerfont .competitionbannerdiv:nth-child(3){
+ max-height: 70px;
+ font-size: 16px;
+ font-weight: 400;
+ /*color: rgba(155,155,155,1);*/
+ color:#05101A;
+}
+
+
+
+.Competitioncolor9b{
+ color: #9B9B9B;
+}
+
+.Competitioncolor77{
+ color: #777777;
+ font-size: 14px;
+}
+
+.Competitioncolor516{
+ font-size:24px;
+ color:rgba(5,16,26,1);
+}
+
+.Competitionfontsize22{
+ font-size:22px;
+ font-weight:500;
+ color:rgba(255,255,255,1);
+}
+
+.Competitionfontsize16{
+ font-size: 16px;
+ font-weight: 400;
+ color: rgba(102,102,102,1);
+}
+
+.ant-layout-sider {
+ position: relative;
+ min-width: 0;
+ background: #001529;
+ -webkit-transition: all 0.2s;
+ -o-transition: all 0.2s;
+ transition: all 0.2s;
+}
+
+.CompetitionMenu .ant-menu-item::after {
+ left: 0px !important;
+ right: auto;
+ border-right: 5px solid #4CACFF;
+}
+
+.CompetitionMenu .ant-menu-item{
+ height: 30px;
+ line-height: 30px;
+ background:none;
+ color:#666;
+}
+
+.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected {
+ background-color: transparent;
+}
+
+.CompetitionMenu .ant-menu-item:not(:last-child){
+ margin-bottom: 40px;
+ background: transparent;
+ color:#666;
+}
+
+.CompetitionMenu .ant-menu-item{
+ font-size: 18px;
+}
+
+.CompetitionMenu .ant-menu-item-selected {
+ color: rgba(76,172,255,1) !important;
+}
+
+.CompetitionMenu{
+ width: 145px;
+ background: #fff;
+ border: 1px solid rgba(239,239,239,1);
+ padding-top: 20px;
+ padding-bottom: 40px !important;
+}
+
+.teamsLayoutleft{
+ background: transparent !important;
+}
+
+.Competitioncharts{
+ font-size: 24px;
+ color: rgba(5,16,26,1);
+}
+.Competitionfirst{
+ width:233px;
+ height:298px;
+ background:rgba(250,250,250,1);
+ box-shadow:0px 2px 8px 2px rgba(255,134,34,0.5);
+ border-radius:5px;
+}
+.Competitionsecondary{
+ width:234px;
+ height:298px;
+ background:rgba(250,250,250,1);
+ box-shadow:0px 3px 5px 0px rgba(254,190,154,1);
+ border-radius:5px;
+}
+
+.Competitionthird{
+ width: 234px;
+ height: 298px;
+ background: rgba(250,250,250,1);
+ box-shadow: 0px 4px 5px 0px rgba(200,200,202,1);
+ border-radius: 5px;
+}
+
+.Competition399{
+ height:399px;
+}
+
+.Competitiontransparent table{
+ background: transparent;
+}
+
+.Commonimg{
+ position: absolute;
+ right: -5px;
+ width:93px;
+ top: 10px;
+}
+
+.Competitionthirdbox{
+ width:234px;
+ height:167px;
+ background:rgba(223,223,225,1);
+ position: relative;
+}
+
+.Competitionfirstbox{
+ width:233px;
+ height:167px;
+ background:rgba(255,231,160,1);
+ position: relative;
+}
+
+.Competitionsecondarybox{
+ width:234px;
+ height:167px;
+ background:rgba(253,230,217,1);
+ position: relative;
+}
+
+.rankingimg{
+ width: 60px;
+ height: 60px;
+ border-radius: 50% !important;
+ box-shadow: 0px 0px 12px rgba(0,0,0,0.2);
+ border: 2px solid #459BE5;
+}
+
+.Competitioncenter{
+ text-align: center;
+ padding-top: 20px;
+}
+
+
+.jinshaifont{
+ font-size: 16px;
+ color: rgba(5,16,26,1);
+ margin-top: 13px !important;
+}
+
+.Competitionthird .ant-card-body {
+ padding: 12px;
+ zoom: 1;
+}
+
+/*.Competitionthird .ant-card-meta-title{*/
+ /*margin-bottom: 0px !important;*/
+/*}*/
+
+.Competitionfirst .ant-card-body {
+ padding: 12px;
+ zoom: 1;
+}
+
+.Competitionsecondary .ant-card-body {
+ padding: 12px;
+ zoom: 1;
+}
+
+.center{
+ text-align: center;
+}
+
+.rankfonttop{
+ font-size:14px;
+ color:rgba(102,102,102,1);
+}
+
+.rankfontmid{
+ font-size:18px;
+ color:rgba(102,102,102,1);
+}
+
+.rankfontbottom{
+ font-size:26px;
+ color:rgba(165,91,41,1);
+ text-align: center;
+}
+
+.rankfontbottoms{
+ font-size:28px;
+ color:rgba(165,91,41,1);
+ text-align: center;
+}
+
+.Competitionuserimg{
+ width: 64px;
+ height: 63px;
+ border-radius: 50%;
+ border: 2px solid #459BE5;
+}
+
+.CompetitionsListzhezhao{
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 1206px;
+ height: 100%;
+ z-index: 10000;
+ display: none;
+ background: rgba(0,0,0,0.33);
+ text-align: center;
+ color: #fff;
+ font-size: 22px;
+
+}
+
+.relative{position: relative;}
+
+.relative:hover .CompetitionsListzhezhao{
+ display: block;
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+ flex-direction: column;
+}
+
+.image_urlbox{
+ width: 790px;
+ height: 340px;
+}
+
+.CompetitionContents{
+ background: #fff !important;
+ padding: 40px;
+ box-shadow: 3px 2px 12px 2px rgba(0,0,0,0.05);
+ border: 1px solid rgba(239,239,239,1);
+}
+
+.rankbeicenter{
+ text-align: center;
+}
+.rankbei{
+ font-size: 16px;
+ color: rgba(119,119,119,1);
+
+}
+
+.youranklist{
+ background: rgba(226,241,255,1);
+ line-height: 50px;
+ text-align: center;
+ padding-left: 20px;
+}
+
+.ranknames{
+ font-size: 16px;
+ color: rgba(62,62,62,1);
+}
+
+.ranknameslast{
+ font-size:16px;
+ color:rgba(12,158,254,1);
+}
+
+.textleft{
+ text-align: left;
+}
+
+.textright{
+ text-align: right;
+}
+
+.userranksclass{
+ text-align: left;
+ width: 18%;
+ padding-left: 12px;
+ margin-right: 28px;
+}
+
+.Commonimgbox{
+ width: 800px !important;
+}
+
+.CompetitionCommonbannerfont{
+ width: 350px !important;
+ margin-left:10px;
+}
+
+.color000{
+ color: #000;
+}
+
+.cursorpointer{
+ cursor: pointer;
+}
+
+.rankfonttop{
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap
+}
+
+.usernamebox{
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ cursor: default;
+ max-width: 100px;
+ display: inherit;
+}
+
+.competimgabsolute{
+ position: absolute;
+ left: 72px;
+ bottom: -10px;
+}
+.competimgabsolute .ant-badge-count{
+ box-shadow: none !important;
+}
+
+.competimgabsoluteijmg{
+ position: absolute;
+ left: -11px;
+ bottom: 0px;
+}
\ No newline at end of file
diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommon.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommon.js
new file mode 100755
index 000000000..b2ac34fe1
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommon.js
@@ -0,0 +1,548 @@
+import React, { Component } from 'react';
+import { Breadcrumb,Layout,Table, Divider, Tag,Badge,Row, Col,Button, Menu, Icon} from 'antd';
+import { Link } from 'react-router-dom';
+import axios from 'axios';
+import {markdownToHTML,getImageUrl} from 'educoder';
+import CompetitionContents from './CompetitionCommonChild/CompetitionContents';
+import CompetitionContentsChart from './CompetitionCommonChild/CompetitionContentsChart';
+import CompetitionContentsMd from './CompetitionCommonChild/CompetitionContentsMd';
+import CompetitionContentspdf from './CompetitionCommonChild/CompetitionContentspdf';
+
+import './CompetitionCommon.css';
+
+const {Sider } = Layout;
+
+class CompetitionCommon extends Component{
+ constructor(props) {
+ super(props)
+ this.state={
+ data: undefined,
+ bannerdata: undefined,
+ module_type: undefined,
+ mdContentdata: undefined,
+ chart_rules: undefined,
+ Competitionedittype: false,
+ chartdata: undefined,
+ has_url: false,
+ signupdata: undefined
+ }
+ }
+
+ componentDidMount(){
+ window.document.title = '竞赛';
+ if(this.props.match.params.identifier!=null){
+ this.getbannerdata();
+ // this.setState({
+ // thiskeys:this.props.location.search.replace('?menu=', '')
+ // })
+ // let url=`/competitions/${this.props.match.params.identifier}.json`;
+ // axios.get(url).then((response) => {
+ // if(response.status===200){
+ // this.setState({
+ // bannerdata:response.data
+ // })
+ // }
+ // }).catch((error) => {
+ // //console.log(error)
+ // })
+ }
+ }
+
+ componentDidUpdate = (prevProps) => {
+ if (prevProps.user != this.props.user) {
+
+ //console.log("componentDidUpdatess");
+ //console.log(this.props.user);
+ if (this.props.user && this.props.user.login != "") {
+ const zul = `/competitions/${this.props.match.params.identifier}/competition_staff.json`;
+ axios.get((zul)).then((result) => {
+ if (result) {
+ if (result.data) {
+ this.setState({
+ signupdata: result.data
+ })
+ }
+ }
+ }).catch((error) => {
+ ////console.log(error);
+ })
+ }
+ }
+
+ }
+ //获取头部信息
+ getbannerdata=()=>{
+ // let menuid=this.props.location.search.replace('?menu=', '');
+ let query=this.props.location&&this.props.location.search;
+ const types = query.split('&')
+ const menuid = types[0].split('?menu=')
+ let url=`/competitions/${this.props.match.params.identifier}/common_header.json`;
+ axios.get(url).then((response) => {
+ if(response.status===200){
+ this.setState({
+ data: response.data,
+ thiskeys: menuid[1] === undefined || menuid[1] === "" ? response.data.competition_modules[0].id : menuid[1],
+ mode: response.data.mode
+ })
+ if(menuid[1]===undefined||menuid[1]===""){
+ this.getrightdata(
+ response.data.competition_modules[0].id,
+ response.data.competition_modules[0].module_type,
+ response.data.competition_modules[0].module_url,
+ response.data.competition_modules[0].has_url
+ )
+ }else{
+ let newlist=response.data.competition_modules;
+ newlist.map((item,key)=>{
+ if(`${item.id}`===`${menuid[1]}`){
+ this.getrightdata(
+ item.id,
+ item.module_type,
+ item.module_url,
+ item.has_url
+ )
+ }
+ })
+ }
+ }
+ }).catch((error) => {
+ //console.log(error)
+ })
+
+ //this.props.user 有可能为空
+
+ if (this.props.user && this.props.user.login != "") {
+ const zul = `/competitions/${this.props.match.params.identifier}/competition_staff.json`;
+ axios.get((zul)).then((result) => {
+ if (result) {
+ if (result.data) {
+ this.setState({
+ signupdata: result.data
+ })
+ }
+ }
+ }).catch((error) => {
+ ////console.log(error);
+ })
+ }
+
+ }
+
+ getrightdatas=(e)=>{
+ let keys = parseInt(e.key);
+ this.getlistdata(keys)
+ this.props.history.replace(`?menu=${keys}`);
+ }
+
+ getlistdata=(keys,listkey)=>{
+
+ let{data}=this.state;
+ this.setState({
+ thiskeys:keys
+ })
+ data&&data.competition_modules.map((item,key)=>{
+ if(item.module_type!="enroll") {
+ if (keys === item.id) {
+ this.getrightdata(item.id, item.module_type, item.module_url, item.has_url, listkey)
+ return
+ }
+ }
+ })
+ }
+
+ getnewchartdata=(typeid,tabkey)=>{
+ if(typeid==="chart"){
+ let url=`/competitions/${this.props.match.params.identifier}/chart_rules.json`;
+ axios.get(url)
+ .then((response) => {
+ if(response.status===200){
+ this.setState({
+ chart_rules:response.data,
+ tabkey: tabkey === undefined ? response.data.stages[0].id === null ? "0" : `${response.data.stages[0].id}` : tabkey
+ })
+
+
+ }
+ }).catch((error) => {
+ //console.log(error)
+ })
+ }
+ }
+
+ getrightdata=(id,typeid,module_url,has_url,listkey)=>{
+
+ // if(typeid==="enroll"){
+ // this.props.history.replace(`/competitions/${this.props.match.params.identifier}/enroll`);
+ // return
+ // }
+
+ this.getnewchartdata(typeid, listkey)
+
+ if(has_url===false){
+ let url=`${module_url}`;
+ axios.get(url).then((response) => {
+ if(response.status===200){
+
+ if(typeid==="chart"){
+ this.setState({
+ chartdata:response.data
+ })
+ }else{
+ this.setState({
+ mdContentdata:response.data
+ })
+ }
+
+ }
+ }).catch((error) => {
+ //console.log(error)
+ })
+ }else{
+ if (module_url.substring(0, 7) == 'http://' || module_url.substring(0, 8) == 'https://') {
+ // window.location.href= module_url
+ window.open(module_url)
+ }else{
+ window.open(`https://${module_url}`)
+ // window.location.href=;
+ }
+ return
+ }
+
+ this.setState({
+ module_id:id,
+ module_type:typeid,
+ has_url:has_url
+ })
+
+ }
+
+ Competitionedit=()=>{
+ this.setState({
+ Competitionedittype: true
+ })
+ }
+
+ hideCompetitionedit=()=>{
+ this.setState({
+ Competitionedittype:false
+ })
+
+ }
+ newgotocourse=(url)=>{
+ if(this.props.checkIfLogin()===false){
+ this.props.showLoginDialog()
+ return
+ }
+ if(this.props.checkIfProfileCompleted()===false){
+ this.props.showProfileCompleteDialog()
+ return
+ }
+ window.open(url);
+
+ }
+
+ gotocourse=(url)=>{
+ if(this.props.checkIfLogin()===false){
+ this.props.showLoginDialog()
+ return
+ }
+ if(this.props.checkIfProfileCompleted()===false){
+ this.props.showProfileCompleteDialog()
+ return
+ }
+
+ if(url===undefined){
+ let {data,signupdata}=this.state;
+ // if(signupdata.enrolled===true){
+ // this.props.history.replace(`/courses/${data.course_id}`);
+ // }else{ }
+
+ if (data.member_of_course === true) {
+ // this.props.history.replace(`/courses/${data.course_id}`);
+ window.open(`/courses/${data.course_id}`)
+ } else {
+ // 以学生身份调用加入课堂 进入课堂首页
+ let url = "/courses/apply_to_join_course.json"
+ axios.post(url, {
+ invite_code: data.invite_code,
+ student: 1
+ }
+ ).then((response) => {
+ if (response.data.status === 0) {
+ // this.props.history.replace();
+ this.getbannerdata()
+ window.open(`/courses/${data.course_id}`);
+
+ }
+ })
+
+ }
+
+ }else{
+
+ if (url === "personal") {
+ let urls = `/competitions/${this.props.match.params.identifier}/enroll`;
+ this.Personalregistration(urls)
+ } else {
+ window.open(url);
+ }
+
+ }
+ }
+
+
+ Personalregistration = (urls) => {
+
+ let {signupdata} = this.state;
+
+ if (signupdata.enroll_ended === true) {
+ //已截止
+ this.props.showNotification(`报名已截止`);
+ return;
+ }
+ if (signupdata.enrolled === true) {
+ this.props.showNotification(`你已经报名,不能重复报名!`);
+ return;
+ }
+ const url = `/competitions/${this.props.match.params.identifier}/competition_teams.json`;
+ axios.post(url).then((response) => {
+ if (response) {
+ if (response.data) {
+ this.props.showNotification(`报名成功,预祝您夺得桂冠!`);
+ // this.props.history.replace(urls);
+ this.getbannerdata()
+ window.open(urls)
+ }
+ }
+ }).catch((error) => {
+
+ });
+ }
+
+
+ Competitioncallback=(key)=>{
+ this.setState({
+ tabkey:key
+ })
+ let url=`/competitions/${this.props.match.params.identifier}/charts.json`;
+ axios.get(url,{params:{
+ stage_id:key===0||key===null?undefined:key
+ }}).then((response) => {
+ if(response.status===200){
+ this.setState({
+ chartdata:response.data
+ })
+ }
+ }).catch((error) => {
+ //console.log(error)
+ })
+
+ }
+
+
+ render() {
+ let {data, module_type, Competitionedittype, signupdata} = this.state;
+
+ return (
+ data===undefined?"":
+
+
+ 在线竞赛
+ {data && data.name}
+
+
+
+
+
+ {data.competition_status === "nearly_published" ?
+ data && data.permission.editable === true ? "" :
+ 即将发布 敬请期待
: ""}
+
+
+
+
+
+
+ 15 ? "competitionbannerdiv mt30" : "competitionbannerdiv mt30"}>{data && data.name}
+
+
+ 竞赛时间:{data && data.start_time}~{data && data.end_time}
+ {/**/}
+
+
+
+
+
+ 奖金
+
+
+ 浏览数
+
+
+ 报名数
+
+
+
+
+
+ ¥{data && data.bonus}
+
+
+ {data.competition_status === "nearly_published" ? "--" : data && data.visits_count}
+
+
+
+ {data.competition_status === "ended" ?
+ this.gotocourse(`/competitions/${this.props.match.params.identifier}/enroll`)}
+ onClick={ data.mode === 2 ?data.member_of_course==true?() => this.newgotocourse(`/courses/${data.course_id}`):"":() => this.newgotocourse(`/competitions/${this.props.match.params.identifier}/enroll`)}
+ >{data && data.member_count}
+ :data.competition_status === "nearly_published" ?
+ this.gotocourse(`/competitions/${this.props.match.params.identifier}/enroll`)}
+ >{"--"}
:
+ data.competition_status === "progressing" ?
+ data.mode === 2 ?
+ this.gotocourse()}>{data && data.member_count}
: signupdata && signupdata.personal === true ?
+ this.gotocourse("personal")}>{data && data.member_count}
: this.gotocourse(`/competitions/${this.props.match.params.identifier}/enroll`)}>{data && data.member_count}
+ :""}
+
+
+
+
+
+ {data.competition_status === "ended" ? : }
+
+ {data.competition_status === "ended" ?
+ : data.enroll_end === true ?
+ :
+ data.competition_status === "progressing" ?
+ :""}
+
+ {data && data.enroll_end_time === null ? "" : `报名截止时间:${data && data.enroll_end_time}`}
+
+
+
+
+
+
+
+
+ {/**/}
+
+
+ {module_type === "certificate" ? "" :
+ {this.state.module_type === "chart" ? Competitionedittype === false ? this.Competitionedit()}
+ Competitioncallback={(e) => this.Competitioncallback(e)}
+ /> : "" : Competitionedittype === false ? this.Competitionedit()}
+ {...this.props}
+ {...this.state}
+ /> : ""}
+ {/**/}
+ {Competitionedittype === true ? this.hideCompetitionedit()}
+ getlistdata={(keys, listkey) => this.getlistdata(keys, listkey)}
+ Competitioncallback={(e) => this.Competitioncallback(e)}
+ {...this.props}
+ {...this.state}
+ /> : ""}
+ }
+
+ {module_type === "certificate" ?
+
+ : ""}
+
+
+
+
+ )
+ }
+}
+export default CompetitionCommon;
diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContents.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContents.js
new file mode 100644
index 000000000..62c7140cd
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContents.js
@@ -0,0 +1,45 @@
+import React, { Component } from 'react';
+import {Button,Layout} from 'antd';
+import axios from 'axios';
+import {markdownToHTML,getImageUrl,AttachmentList} from 'educoder';
+
+
+const { Header, Footer, Sider, Content } = Layout;
+class CompetitionContents extends Component{
+ constructor(props) {
+ super(props)
+ this.state={
+ hash:undefined
+ }
+ }
+
+ componentDidMount(){
+ window.document.title = '竞赛';
+ this.props.MdifHasAnchorJustScorll();
+ }
+
+ render() {
+ let {mdContentdata, data} = this.props;
+ //mdhash滚动
+ this.props.MdifHasAnchorJustScorll();
+ return (
+
+
+ {data && data.permission.editable === true ? this.props.Competitionedittype === false ? this.props.has_url === false ?
+
:"":"":""}
+
+
+
+ )
+ }
+}
+export default CompetitionContents;
diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentsChart.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentsChart.js
new file mode 100644
index 000000000..420f83ff1
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentsChart.js
@@ -0,0 +1,423 @@
+import React, { Component } from 'react';
+import {Button,Layout,Tabs,Icon, Card, Avatar, Row, Col ,Table,Badge} from 'antd';
+import {markdownToHTML,getImageUrl} from 'educoder';
+import axios from 'axios';
+
+const { Content } = Layout;
+const { TabPane } = Tabs;
+const { Meta } = Card;
+
+class CompetitionContents extends Component{
+ constructor(props) {
+ super(props)
+ this.state={
+ personal:undefined
+ }
+ }
+
+ componentDidMount(){
+ window.document.title = '竞赛';
+ let url=`/competitions/${this.props.match.params.identifier}/competition_staff.json`;
+ axios.get(url)
+ .then((response) => {
+ if(response.status===200){
+ console.log(response)
+ this.setState({
+ personal:response.data.personal
+ })
+ }
+ }).catch((error) => {
+ console.log(error)
+ })
+ this.props.MdifHasAnchorJustScorll();
+ }
+
+ derivefun=(url)=>{
+ axios.get(url).then((response)=>{
+ if(response === undefined){
+ return
+ }
+ if(response.data.status&&response.data.status===-1){
+ this.props.showNotification(response.data.message);
+ }else if(response.data.status&&response.data.status===-2){
+ // if(response.data.message === "100"){
+ // // 已超出文件导出的上限数量(100 ),建议:
+ //
+ // this.setState({
+ // DownloadType:true,
+ // DownloadMessageval:100
+ // })
+ // }else {
+ // //因附件资料超过500M
+ // this.setState({
+ // DownloadType:true,
+ // DownloadMessageval:500
+ // })
+ // }
+ this.props.showNotification(response.data.message);
+ }else {
+ // this.props.showNotification(`正在下载中`);
+ // window.open("/api"+url, '_blank');
+ this.props.slowDownload(url);
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+ render() {
+ this.props.MdifHasAnchorJustScorll();
+ const operations =
+ const columns = [
+ {
+ title: 'usersum',
+ dataIndex: 'usersum',
+ key: 'name',
+ render: text => {text},
+ },
+ {
+ title: 'userimg',
+ dataIndex: 'userimg',
+ key: 'userimg',
+ render: (text, record) =>(
+
+
+
}/)
+
+
+ ),
+ },
+ {
+ title: 'username',
+ dataIndex: 'username',
+ key: 'username',
+ render: text => {text},
+ },
+ {
+ title: 'school',
+ dataIndex: 'school',
+ key: 'school',
+ render: text => {text},
+ },
+ {
+ title: 'spendtime',
+ dataIndex: 'spendtime',
+ key: 'spendtime',
+ render: text => {text},
+ },
+ {
+ title: 'score',
+ dataIndex: 'score',
+ key: 'score',
+ render: text => {text},
+ },
+ ];
+
+ const datas = [];
+ let {chart_rules, chartdata, data} = this.props;
+ let {personal}=this.state;
+
+ if(this.props&&this.props.mode!=1){
+
+ columns.some((item,key)=> {
+ if (item.title === "spendtime") {
+ columns.splice(key, 1)
+ return true
+ }
+ }
+ )
+
+ }
+
+ {chartdata===undefined?"":chartdata.teams.length===0?"":chartdata.teams.map((item,key)=>{
+ let list={
+ usersum:key+1,
+ userimg:item.user_image,
+ username:personal===undefined||personal===null?item.record_user_name:personal===true?item.record_user_name:item.team_name,
+ school:item.school_name,
+ spendtime:item.spend_time,
+ score:item.score<50?"< 50 分":item.score,
+ user_login:item.user_login,
+ competition_prize:item.competition_prize
+ }
+ datas.push(list)
+ })}
+
+ // console.log(this.props&&this.props.mode)
+ // console.log(columns)
+
+ return (
+
+
+ {chart_rules === undefined ? "" :
+
this.props.Competitioncallback(e)} activeKey={this.props.tabkey}
+ tabBarExtraContent={data && data.permission.editable === true ? this.props.Competitionedittype === false ? this.props.has_url === false ? operations : "" : "" : ""}>
+ {chart_rules.stages.map((item,key)=>{
+ return(
+
+ {chart_rules.rule_contents.map((items,keys)=>{
+ if(item.id===items.competition_stage_id){
+ return(
+
+ )
+ }else if(item.id===null&&items.competition_stage_id===0){
+ return(
+
+ )
+ }
+ })}
+
+ )
+ })}
+ }
+
+
+
总排名
+ {chartdata===undefined?"":chartdata.teams.length===0?
+
}/)
+
要抓住一切机会,向所有人证明你自己,证明你能够迎接荣耀
+ :""}
+
+ {chartdata===undefined?"":chartdata.teams.length===0?"":chartdata.teams.map((item,key)=>{
+
+
+ if(key===1){
+ return(
+
+
+
+
+
+
+
+ }
+ >
+
+ {item.school_name}
+ {this.props&&this.props.mode===1?{item.spend_time}
:""}
+ }
+ description={
+ {item.score<50?"< 50 分":item.score}分
+ }
+ />
+
+
+
+ )
+ }
+
+ })}
+ {chartdata===undefined?"":chartdata.teams.length===0?"":chartdata.teams.map((item,key)=>{
+ if(key===0){
+ return(
+
+
+
+
+
+
+
+ }
+ >
+
+ {item.school_name}
+ {this.props&&this.props.mode===1?{item.spend_time}
:""}
+ }
+ description={
+ {item.score<50?"< 50 分":item.score}分
+ }
+
+ />
+
+
+
+ )
+ }
+ })}
+ {chartdata===undefined?"":chartdata.teams.length===0?"":chartdata.teams.map((item,key)=>{
+ if(key===2){
+ return(
+
+
+
+
+
+
+
+ }
+ >
+
+ {item.school_name}
+ {this.props&&this.props.mode===1?{item.spend_time}
:""}
+ }
+ description={
+ {item.score<50?"< 50 分":item.score}分
+ }
+
+ />
+
+
+ )
+ }
+
+
+
+ })}
+
+
+ {chartdata===undefined?"":chartdata.user_ranks.length===0?"":
+
+ {chartdata.user_ranks.map((item,key)=>{
+
+ return(
+
+
+ 您当前排名:{item.rank}
+
+
+ {personal===undefined||personal===null?item.record_user_name:personal===true?item.user_name:item.team_name}
+
+
+ {/*{item.team_name}*/}
+
+ {item.cost_time=== "--"?
+ {this.props&&this.props.mode===1?item.cost_time:""}
+ :
+ {this.props&&this.props.mode===1?item.cost_time:""}
+ }
+ {item.cost_time=== "--"?
+ {item.score<50?"< 50 分":item.score}
+ :
+ {item.score<50?"< 50 分":item.score}
+ }
+
+ )
+ })}
+
}
+
+
+ {chartdata === undefined ? "" : chartdata.teams.length === 0 ? "" :
+ }
+
+
+
+
+
+ )
+ }
+}
+export default CompetitionContents;
diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentsMd.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentsMd.js
new file mode 100644
index 000000000..049f2bab1
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentsMd.js
@@ -0,0 +1,232 @@
+import React, { Component } from 'react';
+import {Button, Card, Row, Col ,Upload,Icon,message,Tabs} from 'antd';
+import axios from 'axios';
+import {getImageUrl,getUrl,appendFileSizeToUploadFileAll,appendFileSizeToUploadFile} from 'educoder';
+import TPMMDEditor from '../../../tpm/challengesnew/TPMMDEditor';
+const { TabPane } = Tabs;
+class CompetitionContentsMd extends Component{
+ constructor(props) {
+ super(props)
+ this.contentMdRef = React.createRef();
+ this.state={
+ contentFileList:[],
+ chartmodule_id:undefined
+ }
+ }
+ componentDidUpdate =(prevState)=>{
+ if(prevState!=this.props){
+ this.getchartdata();
+ }
+ }
+ componentDidMount(){
+ window.document.title = '竞赛';
+
+ this.getchartdata()
+ }
+
+ getchartdata=()=>{
+ let {mdContentdata,chart_rules}=this.props;
+
+ // is_pdf: false
+ if(this.props.module_type==="chart"){
+ let type=true;
+ if(chart_rules===undefined){
+
+ }else{
+ chart_rules.rule_contents.map((items,keys)=>{
+ debugger
+ if(parseInt(this.props.tabkey)===items.competition_stage_id){
+ console.log(items)
+ this.contentMdRef.current.setValue(items.content);
+ this.setState({
+ contentFileList:undefined,
+ chartmodule_id:items.id
+ })
+ type=false;
+ }
+ })
+
+ if(type===true){
+ this.contentMdRef.current.setValue("");
+ this.setState({
+ contentFileList:undefined,
+ chartmodule_id:undefined
+ })
+
+ }
+ }
+
+
+ }else{
+ let contentFileList = mdContentdata===undefined?[]:mdContentdata.attachments===undefined?[]:mdContentdata.attachments.map((item) => {
+ return {
+ id: item.id,
+ uid: item.id,
+ name: appendFileSizeToUploadFile(item),
+ url: item.url,
+ filesize: item.filesize,
+ status: 'done',
+ response:{id: item.id}
+ }
+ })
+ this.setState({
+ contentFileList:contentFileList
+ })
+ this.contentMdRef.current.setValue(mdContentdata===undefined?"":mdContentdata.md_content===undefined?"":mdContentdata.md_content || '')
+
+ }
+ }
+
+ handleContentUploadChange = (info) => {
+ if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
+ let contentFileList = info.fileList;
+ this.setState({ contentFileList: appendFileSizeToUploadFileAll(contentFileList) });
+ }
+
+ }
+
+ onAttachmentRemove = (file, stateName) => {
+ if(file.response!=undefined){
+ this.props.confirm({
+ content: '是否确认删除?',
+
+ onOk: () => {
+ this.deleteAttachment(file, stateName)
+ },
+ onCancel() {
+ console.log('Cancel');
+ },
+ });
+ return false;
+ }
+
+ }
+ deleteAttachment = (file, stateName) => {
+ // 初次上传不能直接取uid
+ const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
+ axios.delete(url, {
+ })
+ .then((response) => {
+ if (response.data) {
+ const { status } = response.data;
+ if (status == 0) {
+ console.log('--- success')
+ this.props.showNotification(response.data.message);
+ this.setState((state) => {
+ const index = state[stateName].indexOf(file);
+ const newFileList = state[stateName].slice();
+ newFileList.splice(index, 1);
+ return {
+ [stateName]: newFileList,
+ };
+ });
+ }
+ }
+ })
+ .catch(function (error) {
+ console.log(error);
+ });
+ }
+ handleSubmit = () => {
+ let {contentFileList}=this.state;
+ const mdContnet = this.contentMdRef.current.getValue().trim();
+ // if(mdContnet.length>10000){
+ // this.props.showNotification("内容超过10000个字");
+ // return
+ // }
+ let attachment_ids=undefined
+ if(contentFileList!=undefined){
+ attachment_ids= contentFileList.map(item => {
+ return item.response ? item.response.id : item.id
+ })
+ }
+
+ let newstage_id=parseInt(this.props.tabkey)===0||null?undefined:parseInt(this.props.tabkey)
+ let data={}
+ if(this.props.module_type==="chart"){
+ data={
+ md_content_id:this.state.chartmodule_id,
+ competition_module_id:this.props.module_id,
+ stage_id:newstage_id,
+ content:mdContnet,
+ }
+ }else{
+ data={
+ md_content_id:this.props.mdContentdata.md_id,
+ competition_module_id:this.props.mdContentdata.id,
+ content:mdContnet,
+ attachment_ids:attachment_ids
+ }
+ }
+
+ let url=`/competitions/${this.props.match.params.identifier}/update_md_content.json`;
+ axios.post(url,data
+ ).then((response) => {
+ if(response.data.status===0){
+ this.props.showNotification(response.data.message);
+ this.props.getlistdata(this.props.thiskeys,this.props.tabkey);
+ this.props.hideCompetitionedit();
+ }else{
+ this.props.showNotification(response.data.message);
+ }
+ }).catch((error) => {
+ console.log(error)
+ })
+
+ }
+ render() {
+ let {contentFileList}=this.state;
+ let {chart_rules}=this.props;
+ const uploadProps = {
+ width: 600,
+ fileList: contentFileList,
+ multiple: true,
+ // https://github.com/ant-design/ant-design/issues/15505
+ // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
+ // showUploadList: false,
+ action: `${getUrl()}/api/attachments.json`,
+ onChange: this.handleContentUploadChange,
+ onRemove: (file) => this.onAttachmentRemove(file, 'contentFileList'),
+ beforeUpload: (file) => {
+ console.log('beforeUpload', file.name);
+ const isLt150M = file.size / 1024 / 1024 < 150;
+ if (!isLt150M) {
+ this.props.showNotification("文件大小必须小于150MB");
+ }
+ return isLt150M;
+ },
+ };
+ // console.log(this.props.tabkey)
+ // console.log(chart_rules)
+ console.log(this.props.mdContentdata)
+ return (
+
+ {chart_rules===undefined?"":this.props.module_type==="chart"?
this.props.Competitioncallback(e)}>
+
+ {chart_rules.stages.map((item,key)=>{
+ return(
+
+ )
+ })}
+
+ :""}
+
+ {this.props.module_type==="chart"?"":
+
+ (单个文件150M以内)
+ }
+
+
+
+
+ )
+ }
+}
+export default CompetitionContentsMd;
\ No newline at end of file
diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdf.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdf.js
new file mode 100644
index 000000000..218e8497f
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdf.js
@@ -0,0 +1,64 @@
+import React, { Component } from 'react';
+import {Tabs} from 'antd';
+import axios from 'axios';
+import {markdownToHTML,getImageUrl,AttachmentList} from 'educoder';
+import CompetitionContentspdfdownload from './CompetitionContentspdfChild/CompetitionContentspdfdownload';
+import CompetitionContentspdfpeopledata from './CompetitionContentspdfChild/CompetitionContentspdfpeopledata';
+// import NoneData from "../../../courses/shixunHomework/shixunHomework";
+
+const { TabPane } = Tabs;
+class CompetitionContentspdf extends Component{
+ constructor(props) {
+ super(props)
+ this.state={
+ Tabskey:"1"
+ }
+ }
+
+ componentDidMount(){
+ window.document.title = '竞赛';
+ let query=this.props.location&&this.props.location.search;
+ const types = query.split('user_id=')
+ if(types[1]===undefined){
+ }else{
+ this.setState({
+ Tabskey:"2"
+ })
+ }
+ }
+
+ Competitioncallback=(key)=>{
+ this.setState({
+ Tabskey:key
+ })
+ }
+
+ render() {
+
+
+ return (
+
+
+
+ this.Competitioncallback(e)} activeKey={this.state.Tabskey}>
+
+ {this.state.Tabskey==="1"?this.Competitioncallback(e)}
+ />:""}
+
+
+ {this.state.Tabskey==="2"?:""}
+
+
+
+
+
+ )
+ }
+}
+export default CompetitionContentspdf;
diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Bankcardnumberverification.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Bankcardnumberverification.js
new file mode 100644
index 000000000..d48ea8fe2
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Bankcardnumberverification.js
@@ -0,0 +1,292 @@
+import React, {Component} from 'react';
+import {Button, Layout, Input, Form} from 'antd';
+import axios from 'axios';
+import {getImageUrl} from 'educoder';
+import mycompetotionchild from './mycompetotionchild.css';
+import {getHiddenName} from "../../../../user/account/AccountBasicEdit";
+import '../../../../courses/css/Courses.css'
+
+export const identityMap = {"teacher": "教师", "student": "学生", "professional": "专业人士"}
+
+class Bankcardnumberverification extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ basicInfo: {},
+ updating: '',
+ secondsFlag: false,
+ seconds: 60,
+ phonebool: false,
+ emailbool: false,
+ formationdata: [],
+ bank_account_editable: false,
+ leader: false,
+ bank_account: undefined,
+ certification: 1
+ }
+ }
+
+ componentDidMount() {
+ window.document.title = '竞赛';
+ // console.log("3获取用户信息");
+ // console.log(this.props)
+ try {
+ this.props.triggerRef(this);
+ }catch (e) {
+
+ }
+ console.log(this.props.bank_account);
+
+ //初始化值
+ if (this.props.bank_account) {
+ this.props.form.setFieldsValue({
+ openingbank: this.props.bank_account.bank,
+ subbranch: this.props.bank_account.second_bank,
+ subbranchs: this.props.bank_account.card_no,
+ })
+ this.setState({
+ openingbank: this.props.bank_account.bank,
+ subbranch: this.props.bank_account.second_bank,
+ subbranchs: this.props.bank_account.card_no,
+ })
+ }
+
+ }
+
+ setdata(bank,second_bank,card_no){
+ this.props.form.setFieldsValue({
+ openingbank: bank,
+ subbranch: second_bank,
+ subbranchs:card_no,
+ })
+ }
+ componentDidUpdate = (prevProps) => {
+ if (prevProps.bank_account != this.props.bank_account) {
+ console.log("componentDidUpdate");
+ console.log(this.props);//是新数据
+ console.log(prevProps);//是老数据
+ ////console.log("Registration");
+ ////console.log("componentDidUpdate");
+ ////console.log(this.props.user.admin);
+ try {
+ if(this.props.bank_account){
+ this.props.form.setFieldsValue({
+ openingbank: this.props.bank_account.bank,
+ subbranch: this.props.bank_account.second_bank,
+ subbranchs: this.props.bank_account.card_no,
+ })
+ }
+ this.setState({
+ openingbank: this.props.bank_account.bank,
+ subbranch: this.props.bank_account.second_bank,
+ subbranchs: this.props.bank_account.card_no,
+ })
+ }catch (e) {
+
+ }
+ }
+
+ }
+ yhBankstrue = () => {
+ this.props.form.validateFieldsAndScroll((err, values) => {
+ if (!err) {
+ let url = `/competitions/${this.props.match.params.identifier}/prize_leader_account.json`;
+ axios.patch(url, {
+ user_id:this.props.userdata.id,
+ bank: values.openingbank,
+ second_bank: values.subbranch ,
+ card_no: values.subbranchs
+ })
+ .then((result) => {
+ try {
+ if (result.data.status === 0) {
+ try {
+ // console.log(values.openingbank);
+ // console.log(values.subbranch);
+ // console.log(values.subbranchs);
+ this.props.form.setFieldsValue({
+ openingbank: values.openingbank,
+ subbranch: values.subbranch,
+ subbranchs: values.subbranchs,
+ });
+ this.setState({
+ openingbank: values.openingbank,
+ subbranch: values.subbranch,
+ subbranchs: values.subbranchs,
+ })
+ }catch (e) {
+
+ }
+
+ try {
+ this.props.showNotification(`提交成功,等待审核!`);
+
+ }catch (e) {
+
+ }
+ try {
+ this.props.getdata(this.props.userdata.id);
+ }catch (e) {
+
+ }
+ try {
+ this.props.GetawardinformationAPI();
+ }catch (e) {
+
+ }
+ }
+ } catch (e) {
+
+ }
+
+ }).catch((error) => {
+ console.log(error);
+ })
+ }
+ })
+
+ }
+
+ render() {
+ const {getFieldDecorator} = this.props.form;
+ const {updating, seconds, secondsFlag, basicInfo, phonebool, emailbool, certification, formationdata, bank_account_editable, leader, bank_account} = this.state
+ return (
+
+
+
签/领/开户行及银行卡号
+
为保障奖金的及时发放,请队长如实填写你名下的银行卡信息
+
+
+
+
+
+
+ {getFieldDecorator('openingbank', {
+ rules: [{
+ initialValue:this.state.openingbank,
+ required: true,
+ message: '请输入开户行',
+ }],
+ })(
+
+ )}
+
+
+
+ {getFieldDecorator('subbranch', {
+ rules: [{
+ initialValue: this.state.subbranch,
+ required: true,
+ message: '请输入支行',
+ }],
+ })(
+
+ )}
+
+
+
+ {getFieldDecorator('subbranchs', {
+ rules: [{
+ initialValue: this.state.subbranchs,
+ required: true,
+ message: '请输入账号',
+ }],
+ })(
+
+ )}
+
+
+
+
+
+ {/*
*/}
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+}
+
+const Bankcardnumberverifications = Form.create({name: 'Bankcardnumberverification'})(Bankcardnumberverification);
+
+export default Bankcardnumberverifications;
+
diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.css b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.css
new file mode 100644
index 000000000..726a02277
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.css
@@ -0,0 +1,24 @@
+.pdfdownload {
+ max-width: 791px;
+ height: 40px;
+ background: rgba(249, 249, 249, 1);
+ line-height: 40px;
+ padding-left: 15px;
+}
+
+.pdfpicture {
+ font-size: 16px;
+ color: rgba(0, 0, 0, 1);
+}
+
+.pdfdownloadfont4CACFF {
+ color: #4CACFF !important;
+}
+
+.pdfdownloadfont00CC5F {
+ color: #00CC5F;
+}
+
+.pdfdownloadfontFF6602 {
+ color: #FF6602;
+}
diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.js
new file mode 100644
index 000000000..eb304e007
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfdownload.js
@@ -0,0 +1,215 @@
+import React, { Component } from 'react';
+import {Button,Layout,Row, Col,Divider,Table} from 'antd';
+import axios from 'axios';
+import {getImageUrl} from 'educoder';
+import './CompetitionContentspdfdownload.css';
+// import NoneData from "../../../courses/shixunHomework/shixunHomework";
+
+
+class CompetitionContentspdfdownload extends Component{
+ constructor(props) {
+ super(props)
+ this.state={
+ data:undefined,
+ teams:undefined
+ }
+ }
+
+ componentDidMount(){
+ window.document.title = '竞赛';
+ let url=`/competitions/${this.props.match.params.identifier}/prize.json`;
+ let query=this.props.location&&this.props.location.search;
+ const types = query.split('user_id=')
+ let userid;
+ if(types[1]===undefined){
+ userid=this.props.user&&this.props.user.user_id;
+ }else{
+ userid=types[1];
+ }
+ axios.get(url,{params:{
+ user_id:userid,
+ }
+ }).then((response) => {
+ if(response.status===200){
+
+ let datas=response.data.teams;
+ if(datas.length>0){
+ datas.map((item,key)=>{
+ let lista=item.team_members;
+ if(lista.length>0){
+ console.log(lista)
+ lista.map((i,k)=>{
+ i["bank_account"]=item.bank_account;
+ })
+ }
+ })
+ }
+ this.setState({
+ data:response.data,
+ teams:datas,
+ })
+ }
+ }).catch((error) => {
+ console.log(error)
+ })
+ }
+
+ render() {
+
+
+
+ let {data,teams}=this.state;
+
+ const columns = [
+ {
+ title: '角色',
+ dataIndex: 'type',
+ key: 'type',
+ render: (text, record) => (
+
+ {record.role}
+
+ ),
+ },
+ {
+ title: '姓名',
+ dataIndex: 'name',
+ key: 'name',
+ render: (text, record) => (
+
+ {record.name}
+
+ ),
+ },
+ {
+ title: '实名认证',
+ dataIndex: 'namecertify',
+ key: 'namecertify',
+ render: (text, record) => (
+
+ {record.real_name_auth==="authed"?已认证:record.real_name_auth==="authing"?待审核:record.real_name_auth==="not_authed"?未认证:""}
+
+ ),
+ },
+ {
+ title: '职业认证',
+ key: 'certify',
+ dataIndex: 'certify',
+ render: (text, record) => (
+
+ {record.professional_auth==="authed"?已认证:record.professional_auth==="authing"?待审核:record.professional_auth==="not_authed"?未认证:""}
+
+ ),
+ },
+ {
+ title: '手机绑定',
+ key: 'mobile',
+ dataIndex: 'mobile',
+ render: (text, record) => (
+
+ {record.phone_binded===true?已绑定:未绑定}
+
+ ),
+ },
+ {
+ title: '邮箱绑定',
+ key: 'mail',
+ dataIndex: 'mail',
+ render: (text, record) => (
+
+ {record.email_binded===true?已绑定:未绑定}
+
+ ),
+ },
+ {
+ title: '开户行及银行卡号信息(队长填写)',
+ key: 'idcard',
+ dataIndex: 'idcard',
+ render: (value, record, index) => {
+ if (index === 0&&record.bank_account!=null) {
+ return {
+ children: {record.bank_account.bank + record.bank_account.second_bank + record.bank_account.card_no},
+ };
+ }
+
+ },
+ },
+ ];
+
+
+ let people=[ { url: '/api/competitions/xxxxx/certificates/1/personal' },
+ { url: '/api/competitions/xxxxx/certificates/2/personal' },]
+ return (
+
+
+ 温馨提示:填写的个人信息经审批后,将提供个人获奖证书下载;团队队员信息全部审批后,将提供团队获奖证书下载。
+
+
+
+ 证书情况
+
+
+
+ 个人证书:{data&&data.personal_certifications.length===0&&data&&data.all_certified===false?
+ 暂未生成 原因:还未认证个人信息,this.props.Competitioncallback("2")}>立即认证:
+ data&&data.personal_certifications.length===0&&data&&data.all_certified===true?
+ 暂未生成 原因:组委会未完成证书审批,请稍后:
+ data&&data.personal_certifications.map((item,key)=>{
+ return(
+
+
+ 立即下载
+
+ )
+ })}
+
+
+
+ 团队证书:
+ {data&&data.team_certifications.length===0?暂未生成
+ :data&&data.team_certifications.map((item,key)=>{
+ return(
+
+
+ 立即下载
+
+ )
+ })}
+
+
+
+
+ {teams&&teams.map((item,key)=>{
+ return(
+
+ {item.name}战队信息填报概况
+
+
+
+ )
+ })
+ }
+
+
+
+ )
+ }
+}
+export default CompetitionContentspdfdownload;
\ No newline at end of file
diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfpeopledata.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfpeopledata.js
new file mode 100644
index 000000000..1afbf16a7
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/CompetitionContentspdfpeopledata.js
@@ -0,0 +1,596 @@
+import React, {Component} from 'react';
+import {Button, Layout, Input, Form} from 'antd';
+import axios from 'axios';
+import {getImageUrl} from 'educoder';
+import mycompetotionchild from './mycompetotionchild.css';
+import {getHiddenName} from "../../../../user/account/AccountBasicEdit";
+import '../../../../courses/css/Courses.css'
+import RealNameCertificationModal from "../../../../user/modal/RealNameCertificationModal";
+import Phonenumberverifications from './Phonenumberverification';
+import Mailboxvalidations from './Mailboxvalidation'
+import Bankcardnumberverifications from './Bankcardnumberverification'
+export const identityMap = {"teacher": "教师", "student": "学生", "professional": "专业人士"}
+
+class CompetitionContentspdfpeopledata extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ basicInfo: {},
+ updating: '',
+ secondsFlag: false,
+ seconds: 60,
+ phonebool: false,
+ emailbool: false,
+ formationdata: [],
+ bank_account_editable: false,
+ leader: false,
+ bank_account: undefined,
+ certification: 1,
+ userdata:undefined
+ }
+ }
+
+ componentDidMount() {
+ window.document.title = '竞赛';
+ console.log("获取用户信息");
+ console.log(this.props);
+
+ this.GetawardinformationAPI();
+ let query=this.props.location&&this.props.location.search;
+ const types = query.split('user_id=')
+ let userid;
+ if(types[1]===undefined){
+ userid=this.props.user&&this.props.user.user_id;
+ }else{
+ userid=types[1];
+ }
+ this.getdata(userid);
+ this.GetuseridApi(userid);
+
+ }
+
+ GetuseridApi=(id)=>{
+ //个人信息API 获取个人信息
+ let url = `/users/accounts/${id}.json`;
+ axios.get(url).then((result) => {
+ if (result.data) {
+ console.log("GetuseridApi");
+ console.log(result.data);
+ this.setState({
+ userdata:result.data
+ })
+ }
+ }).catch((error) => {
+ console.log(error);
+ })
+
+ }
+
+ GetawardinformationAPI = () => {
+ let url = `/competitions/${this.props.match.params.identifier}/prize.json`;
+ let query=this.props.location&&this.props.location.search;
+ const types = query.split('user_id=')
+ let userid;
+ if(types[1]===undefined){
+ userid=this.props.user&&this.props.user.user_id;
+ }else{
+ userid=types[1];
+ }
+ axios.get(url,{params:{
+ user_id:userid,
+ }
+ }).then((result) => {
+ if (result.data) {
+ this.setState({
+ formationdata: result.data.formationdata,
+ bank_account_editable: result.data.bank_account_editable, //队长是否可以编辑
+ leader: result.data.leader, //是否是队长
+ bank_account: result.data.bank_account, //队长银行卡号信息
+ })
+ }
+ }).catch((error) => {
+ console.log(error);
+ })
+ }
+
+
+ getdata = (id) => {
+ this.setState({
+ certification: 3
+ })
+ this.GetuseridApi(id);
+ };
+ // 绑定手机
+ onPhoneSubmit = () => {
+ this.props.form.validateFieldsAndScroll((err, values) => {
+ if (!err) {
+ let {id} =this.state.userdata;
+ let reg = /^1\d{10}$/;
+ if (reg.test(values.phone)) {
+ let url = `/users/accounts/${id}/phone_bind.json`
+ axios.post((url), {
+ phone: values.phone,
+ code: values.phoneValidateCode
+ }).then((result) => {
+ if (result) {
+ this.props.showNotification("手机号码绑定成功!");
+ this.setState({
+ phonebool: false
+ })
+ this.getdata(this.state.userdata.id);
+ }
+ }).catch((error) => {
+ console.log(error);
+ })
+ } else {
+ this.props.showNotification("请输入有效的11位手机号码");
+ }
+ }
+ })
+ }
+ // 绑定邮箱
+ onEmailSubmit = () => {
+ this.props.form.validateFieldsAndScroll((err, values) => {
+ if (!err) {
+ let {id} =this.state.userdata;
+ let reg = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/;
+ if (reg.test(values.email)) {
+ let url = `/users/accounts/${id}/email_bind.json`
+ axios.post((url), {
+ email: values.email,
+ code: values.emailValidateCode
+ }).then((result) => {
+ if (result) {
+ this.props.showNotification("邮箱地址绑定成功!");
+ this.setState({
+ emailbool: false
+ })
+ this.getdata(this.state.userdata.id);
+ }
+ }).catch((error) => {
+ console.log(error);
+ })
+ } else {
+ this.props.showNotification("请输入正确的邮箱地址");
+ }
+ }
+ })
+ }
+ //取消编辑
+ hideUpdating = (i) => {
+ if (i === 1) {
+ this.setState({
+ phonebool: false
+ })
+ } else if (i === 2) {
+ this.setState({
+ emailbool: false
+ })
+
+ } else if (i === 3) {
+
+ }
+
+ }
+
+ // 获取验证码
+ getCode = (index) => {
+ let url = `/accounts/get_verification_code.json`
+ let login = '';
+ let values = this.props.form.getFieldsValue();
+ if (index == 3) {
+ //绑定手机号码
+ login = values.phone;
+ let reg = /^1\d{10}$/;
+ if (reg.test(login) == false) {
+ this.props.showNotification(`请先输入正确的手机号码`);
+ return;
+ }
+ } else if (index == 4) {
+ // 绑定邮箱
+ login = values.email;
+ let reg = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/;
+ if (reg.test(login) == false) {
+ this.props.showNotification(`请先输入正确的邮箱地址`);
+ return;
+ }
+ }
+ let type = index;
+ if (!login) {
+ this.props.showNotification(`请先输入${index == 3 ? "手机号码" : "邮箱地址"}`);
+ return;
+ }
+ axios.get((url), {
+ params: {
+ login, type
+ }
+ }).then((result) => {
+ if (result) {
+ // 倒计时
+ this.setState({
+ secondsFlag: true
+ })
+ this.remainTime();
+ }
+ }).catch((error) => {
+ console.log(error);
+ })
+ }
+
+ // 获取验证码倒计时
+ remainTime = () => {
+ this.setState({
+ seconds: 60
+ })
+ this.timer = setInterval(() => {
+ let {seconds} = this.state;
+ let s = parseInt(seconds) - 1;
+ if (s > -1) {
+ this.setState({
+ seconds: s
+ })
+ } else {
+ this.setState({
+ secondsFlag: false
+ })
+ clearInterval(this.timer);
+ }
+ }, 1000)
+ }
+
+ phonebools = () => {
+ this.setState({
+ phonebool: true
+ })
+ }
+
+ emailbools = () => {
+ console.log("点击了邮箱");
+ this.setState({
+ emailbool: true
+ })
+ }
+
+ //立即认证
+ checkBasicInfo = (index) => {
+ if (this.state.userdata.base_info_completed == true) {
+ this.showRealNameCertificationModal(index)
+ } else {
+ try {
+ this.props.confirm({
+ okText: `立即完善`,
+ content: `请先完善基本信息`,
+ onOk: () => {
+ this.props.history.push('/account/profile/edit')
+ }
+ })
+ } catch (e) {
+ this.props.history.push(`/account/profile/edit`);
+
+ }
+ }
+
+ }
+ showRealNameCertificationModal = (index) => {
+ this.setState({
+ certification: index,
+ }, () => {
+ if (index == 1) {
+ this.realNameCertificationModal1.setVisible(true)
+ } else if (index == 2) {
+ this.realNameCertificationModal2.setVisible(true)
+ }
+ })
+ }
+ //绑定银行确认
+ yhBankstrue = () => {
+ this.props.form.validateFieldsAndScroll((err, values) => {
+ if (!err) {
+ let url = `/competitions/${this.props.match.params.identifier}/prize_leader_account.json`;
+ axios.patch(url, {
+ user_id:this.state.userdata.id,
+ bank: values.openingbank,
+ second_bank: values.subbranchs,
+ card_no: values.subbranch
+ })
+ .then((result) => {
+ try {
+ if (result.data.status == 0) {
+ // console.log(JSON.stringify(result));
+ this.props.showNotification(`提交成功`);
+ this.getdata(this.state.userdata.id);
+ this.GetawardinformationAPI();
+ }
+ } catch (e) {
+
+ }
+
+ }).catch((error) => {
+ console.log(error);
+ })
+ }
+ })
+
+ }
+
+ //取消认证弹框
+ onCancel = () => {
+ this.getdata(this.state.userdata.id);
+
+ }
+
+ bindRef = ref => { this.child = ref }
+ //撤销认证
+ Cancellationofapplication = (index) => {
+ let userid;
+ let query=this.props.location&&this.props.location.search;
+ const types = query.split('user_id=')
+ if(types[1]===undefined){
+ userid=this.props.user&&this.props.user.user_id;
+ }else{
+ userid=types[1];
+ }
+ let url = ""
+ if (index === 1) {
+ url = `/users/accounts/${userid}/authentication_apply.json`;
+ } else if (index === 2) {
+ url = `/users/accounts/${userid}/professional_auth_apply.json`;
+ }
+ axios.delete(url)
+ .then((response) => {
+ try {
+ if (response.data.status == 0) {
+ if (index === 1) {
+ this.props.showNotification('撤销实名认证成功')
+ } else if (index === 2) {
+ this.props.showNotification('撤销职业认证成功')
+ }
+ try {
+ this.getdata(this.state.userdata.id);
+ }catch (e) {
+
+ }
+
+ }
+ } catch (e) {
+
+ }
+
+ })
+ .catch(function (error) {
+ console.log(error);
+ });
+
+ }
+
+
+ render() {
+ const admins=this.props.user.admin;
+ if(admins===undefined||admins===null) {
+ admins === false;
+ }
+ const {updating, seconds, secondsFlag,userdata, basicInfo, phonebool, emailbool, certification, formationdata, bank_account_editable, leader, bank_account} = this.state
+ return (
+
+ {this.state.certification === 1 &&userdata?
+
+
this.realNameCertificationModal1 = form}
+ certification={certification}
+ Getdata={(id) => this.getdata(id)}
+ onCancel={() => this.onCancel()}
+ >
+
+
+ : ""}
+
+ {this.state.certification === 2 &&userdata ?
+
this.realNameCertificationModal2 = form}
+ certification={certification}
+ Getdata={(id) => this.getdata(id)}
+ onCancel={() => this.onCancel()}
+
+ > : ""}
+
+
*实名信息
+
+ {userdata && userdata.authentication == "uncertified" ?
+
通过实名认证后才能获得证书
: ""
+ }
+ {userdata && userdata.authentication == "uncertified" ?
+
this.checkBasicInfo(1)}>立即认证
: ""
+ }
+
+
+
+
姓名:
+
{userdata && userdata.name}
+
+ {
+ userdata && userdata.authentication == "uncertified" ? "" :
+ userdata && userdata.authentication == "applying" ?
+
待审核!
this.Cancellationofapplication(1)}>撤销认证
+ :
+
+
已认证
+
+ }
+
+
+
+
+
性别:
+
{userdata && userdata.gender == 0 ? "男" : "女"}
+
+
+
+
*职业信息
+
+ {
+ userdata && userdata.professional_certification == "uncertified" ?
+
通过职业认证后才能获得证书
+
+ : ""}
+ {
+ userdata && userdata.professional_certification == "uncertified" ?
+
this.checkBasicInfo(2)}>立即认证
+
+ : ""}
+
+
+
+
职业:
+
{userdata && userdata.identity && identityMap[userdata.identity]}
+ {
+ userdata && userdata.professional_certification == "uncertified" ?
+ "" :
+ userdata && userdata.professional_certification == "applying" ?
+
+
待审核!
this.Cancellationofapplication(2)}>撤销认证
+
+ :
+
+
已认证
+
this.checkBasicInfo(2)}>重新认证
+
+
+ }
+
+
+
+
{userdata && userdata.technical_title ? "职称:" : ""}{userdata && userdata.student_id ? "学号:" : ""}
+
{userdata && (userdata.technical_title || userdata.student_id)}
+
+
+
学校:
+
{userdata && userdata.school_name}
+
+
+
院系:
+
{userdata && userdata.department_name}
+
+
+
+
手机号:
+ {
+ userdata && userdata.phone ?
+
{userdata && userdata.phone}
+ :
+
未绑定
+ }
+
this.phonebools()}>{userdata && userdata.phone ? (phonebool === false ? "更换" : "") : (phonebool === false ? "立即绑定" : "")}
+
+ {/*手机号绑定*/}
+ {
+ phonebool === true &&userdata ?
+
this.hideUpdating(i)}
+ getdata={(id) => this.getdata(id)}>
+ : ""
+ }
+
+
+
+
Email:
+
{userdata && userdata.mail}
+
this.emailbools()}>{userdata && userdata.mail ? (emailbool === false ? "更换" : "") : (emailbool === false ? "立即绑定" : "")}
+
+ {
+ emailbool === false ? "" :
+ (
+ userdata?
+
this.hideUpdating(i)}
+ getdata={(id) => this.getdata(id)}>
+ :""
+ )
+ }
+ {
+ leader === true ?
+
+ {
+ bank_account_editable === true ?
+
this.hideUpdating(i)}
+ getdata={(id) => this.getdata(id)}
+ GetawardinformationAPI={() => this.GetawardinformationAPI()}
+ bank_account={this.state.bank_account}
+ >
+ :
+ admins===true?
+
this.hideUpdating(i)}
+ getdata={(id) => this.getdata(id)}
+ GetawardinformationAPI={() => this.GetawardinformationAPI()}
+ bank_account={this.state.bank_account}
+ >
+ :
+
+
+
签/领/开户行及银行卡号
+
为保障奖金的及时发放,请队长如实填写你名下的银行卡信息
+
+ {
+ bank_account && bank_account ?
+
+
+
开户行:
+
{bank_account && bank_account.bank}
+
+
+
支行:
+
{bank_account && bank_account.second_bank}
+
+
+
账号:
+
{bank_account && bank_account.card_no}
+
+
+ :
+ ""
+ }
+
+
+ }
+
+ :
+
+ {
+ admins===true?
+ this.hideUpdating(i)}
+ getdata={(id) => this.getdata(id)}
+ GetawardinformationAPI={() => this.GetawardinformationAPI()}
+ bank_account={this.state.bank_account}
+ >
+ :""
+ }
+
+ }
+
+
+
+ )
+ }
+}
+
+export default CompetitionContentspdfpeopledata;
+
diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Mailboxvalidation.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Mailboxvalidation.js
new file mode 100644
index 000000000..934369aac
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Mailboxvalidation.js
@@ -0,0 +1,270 @@
+import React, {Component} from 'react';
+import {Button, Layout, Input, Form} from 'antd';
+import axios from 'axios';
+import {getImageUrl} from 'educoder';
+import mycompetotionchild from './mycompetotionchild.css';
+import {getHiddenName} from "../../../../user/account/AccountBasicEdit";
+import '../../../../courses/css/Courses.css'
+
+export const identityMap = {"teacher": "教师", "student": "学生", "professional": "专业人士"}
+
+class Mailboxvalidation extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ basicInfo: {},
+ updating: '',
+ secondsFlag: false,
+ seconds: 60,
+ phonebool: false,
+ emailbool: false,
+ formationdata: [],
+ bank_account_editable: false,
+ leader: false,
+ bank_account: undefined,
+ certification: 1
+ }
+ }
+
+ componentDidMount() {
+ window.document.title = '竞赛';
+ // console.log("3获取用户信息");
+ // console.log(this.props);
+ }
+
+
+ // 绑定邮箱
+ onEmailSubmit = () => {
+ this.props.form.validateFieldsAndScroll((err, values) => {
+ if (!err) {
+ let {id} = this.props.userdata;
+ let reg = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/;
+ if (reg.test(values.email)) {
+ let url = `/users/accounts/${id}/email_bind.json`
+ axios.post((url), {
+ email: values.email,
+ code: values.emailValidateCode
+ }).then((result) => {
+ if (result) {
+ this.props.showNotification("邮箱地址绑定成功!");
+ this.hideUpdating(2);
+ this.props.getdata(id);
+ }
+ }).catch((error) => {
+ console.log(error);
+ })
+ } else {
+ this.props.showNotification("请输入正确的邮箱地址");
+ }
+ }
+ })
+ }
+ //取消编辑
+ hideUpdating = (i) => {
+ if (i === 1) {
+ this.props.hideUpdating(1);
+ } else if (i === 2) {
+ this.props.hideUpdating(2);
+
+
+ } else if (i === 3) {
+
+ }
+
+ }
+
+ // 获取验证码
+ getCode = (index) => {
+ let url = `/accounts/get_verification_code.json`
+ let login = '';
+ let values = this.props.form.getFieldsValue();
+ if (index == 3) {
+ //绑定手机号码
+ login = values.phone;
+ let reg = /^1\d{10}$/;
+ if (reg.test(login) == false) {
+ this.props.showNotification(`请先输入正确的手机号码`);
+ return;
+ }
+ } else if (index == 4) {
+ // 绑定邮箱
+ login = values.email;
+ let reg = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/;
+ if (reg.test(login) == false) {
+ this.props.showNotification(`请先输入正确的邮箱地址`);
+ return;
+ }
+ }
+ let type = index;
+ if (!login) {
+ this.props.showNotification(`请先输入${index == 3 ? "手机号码" : "邮箱地址"}`);
+ return;
+ }
+ axios.get((url), {
+ params: {
+ login, type
+ }
+ }).then((result) => {
+ if (result) {
+ // 倒计时
+ this.setState({
+ secondsFlag: true
+ })
+ this.remainTime();
+ }
+ }).catch((error) => {
+ console.log(error);
+ })
+ }
+
+ // 获取验证码倒计时
+ remainTime = () => {
+ this.setState({
+ seconds: 60
+ })
+ this.timer = setInterval(() => {
+ let {seconds} = this.state;
+ let s = parseInt(seconds) - 1;
+ if (s > -1) {
+ this.setState({
+ seconds: s
+ })
+ } else {
+ this.setState({
+ secondsFlag: false
+ })
+ clearInterval(this.timer);
+ }
+ }, 1000)
+ }
+
+ phonebools = () => {
+ this.setState({
+ phonebool: true
+ })
+ }
+
+ emailbools = () => {
+ console.log("点击了邮箱");
+ this.setState({
+ emailbool: true
+ })
+ }
+
+
+ render() {
+ const {getFieldDecorator} = this.props.form;
+ const {updating, seconds, secondsFlag, basicInfo, phonebool, emailbool, certification, formationdata, bank_account_editable, leader, bank_account} = this.state
+ console.log(emailbool);
+ return (
+
+
+
+
+
+ {getFieldDecorator('email', {
+ rules: [{
+ // initialValue: this.state.cityDefaultValue,
+ required: true,
+ message: basicInfo && basicInfo.mail ? '请输入要更换的新邮箱地址' : '请输入邮箱地址',
+ }],
+ })(
+
+ )}
+
+
+
+ {getFieldDecorator('emailValidateCode', {
+ rules: [{
+ // initialValue: this.state.cityDefaultValue,
+ required: true,
+ message: '请输入邮箱收到的验证码',
+ }],
+ })(
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+}
+
+const Mailboxvalidations = Form.create({name: 'Mailboxvalidation'})(Mailboxvalidation);
+
+export default Mailboxvalidations;
+
diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Phonenumberverification.js b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Phonenumberverification.js
new file mode 100644
index 000000000..fa0b20b7a
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/Phonenumberverification.js
@@ -0,0 +1,262 @@
+import React, {Component} from 'react';
+import {Button, Layout, Input, Form} from 'antd';
+import axios from 'axios';
+import {getImageUrl} from 'educoder';
+import mycompetotionchild from './mycompetotionchild.css';
+import {getHiddenName} from "../../../../user/account/AccountBasicEdit";
+import '../../../../courses/css/Courses.css'
+import RealNameCertificationModal from "../../../../user/modal/RealNameCertificationModal";
+
+export const identityMap = {"teacher": "教师", "student": "学生", "professional": "专业人士"}
+
+class Phonenumberverification extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ updating: '',
+ secondsFlag: false,
+ seconds: 60,
+ phonebool: false,
+ emailbool: false,
+ formationdata: [],
+ bank_account_editable: false,
+ leader: false,
+ bank_account: undefined,
+ certification: 1
+ }
+ }
+
+ componentDidMount() {
+ window.document.title = '竞赛';
+ // console.log("获取用户信息");
+ // console.log(this.props);
+ }
+
+
+ // 绑定手机
+ onPhoneSubmit = () => {
+ this.props.form.validateFieldsAndScroll((err, values) => {
+ if (!err) {
+ let {id} = this.props.userdata;
+ let reg = /^1\d{10}$/;
+ if (reg.test(values.phone)) {
+ let url = `/users/accounts/${id}/phone_bind.json`
+ axios.post((url), {
+ phone: values.phone,
+ code: values.phoneValidateCode
+ }).then((result) => {
+ if (result) {
+ this.props.showNotification("手机号码绑定成功!");
+ this.props.hideUpdating(1)
+ this.props.getdata(id);
+ }
+ }).catch((error) => {
+ console.log(error);
+ })
+ } else {
+ this.props.showNotification("请输入有效的11位手机号码");
+ }
+ }
+ })
+ }
+ //取消编辑
+ hideUpdating = (i) => {
+ if (i === 1) {
+ this.props.hideUpdating(1);
+ } else if (i === 2) {
+ this.props.hideUpdating(2);
+
+ } else if (i === 3) {
+
+ }
+
+ }
+
+ // 获取验证码
+ getCode = (index) => {
+ let url = `/accounts/get_verification_code.json`
+ let login = '';
+ let values = this.props.form.getFieldsValue();
+ if (index == 3) {
+ //绑定手机号码
+ login = values.phone;
+ let reg = /^1\d{10}$/;
+ if (reg.test(login) == false) {
+ this.props.showNotification(`请先输入正确的手机号码`);
+ return;
+ }
+ } else if (index == 4) {
+ // 绑定邮箱
+ login = values.email;
+ let reg = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/;
+ if (reg.test(login) == false) {
+ this.props.showNotification(`请先输入正确的邮箱地址`);
+ return;
+ }
+ }
+ let type = index;
+ if (!login) {
+ this.props.showNotification(`请先输入${index == 3 ? "手机号码" : "邮箱地址"}`);
+ return;
+ }
+ axios.get((url), {
+ params: {
+ login, type
+ }
+ }).then((result) => {
+ if (result) {
+ // 倒计时
+ this.setState({
+ secondsFlag: true
+ })
+ this.remainTime();
+ }
+ }).catch((error) => {
+ console.log(error);
+ })
+ }
+
+ // 获取验证码倒计时
+ remainTime = () => {
+ this.setState({
+ seconds: 60
+ })
+ this.timer = setInterval(() => {
+ let {seconds} = this.state;
+ let s = parseInt(seconds) - 1;
+ if (s > -1) {
+ this.setState({
+ seconds: s
+ })
+ } else {
+ this.setState({
+ secondsFlag: false
+ })
+ clearInterval(this.timer);
+ }
+ }, 1000)
+ }
+
+ phonebools = () => {
+ this.setState({
+ phonebool: true
+ })
+ }
+
+
+ render() {
+ const {getFieldDecorator} = this.props.form;
+ const {updating, seconds, secondsFlag, phonebool, emailbool, certification, formationdata, bank_account_editable, leader, bank_account} = this.state
+ const {basicInfo} = this.props
+ console.log(emailbool);
+ return (
+
+
+
+
+
+ {getFieldDecorator('phone', {
+ rules: [{
+ // initialValue: this.state.cityDefaultValue,
+ required: true,
+ message: `请输入要${basicInfo.phone ? '更换' : '绑定'}的手机号码`,
+ }],
+ })(
+
+ )}
+
+
+
+ {getFieldDecorator('phoneValidateCode', {
+ rules: [{
+ // initialValue: this.state.cityDefaultValue,
+ required: true,
+ message: '请输入手机获取的验证码',
+ }],
+ })(
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+}
+
+const Phonenumberverifications = Form.create({name: 'Phonenumberverification'})(Phonenumberverification);
+
+export default Phonenumberverifications;
+
diff --git a/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/mycompetotionchild.css b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/mycompetotionchild.css
new file mode 100644
index 000000000..fd85606e0
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitioncommon/CompetitionCommonChild/CompetitionContentspdfChild/mycompetotionchild.css
@@ -0,0 +1,314 @@
+/*垂直布局
+
+ 一
+ 二
+ 三
+*/
+.flexdirectionjust {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
+
+
+.directstwebkitflex {
+ display: flex;
+ display: -webkit-flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.diredisplayitflex {
+ display: flex;
+ display: -webkit-flex;
+ align-items: center;
+}
+
+/*垂直布局*/
+/*靠左侧
+一 二 三 四 五 六 七 八
+*/
+.flexdirection {
+ display: flex;
+ flex-direction: row;
+}
+
+.flexdirections {
+ display: flex;
+ flex-direction: initial;
+}
+
+/*靠左侧
+*/
+
+
+/*靠右侧八 七 六 五 四 三 二 一*/
+.flexdirectionss {
+ display: flex;
+ flex-direction: row-reverse;
+}
+
+
+/*垂直布局
+一
+二
+三
+四
+*/
+.flexdidirectionss {
+ display: flex;
+ flex-direction: column;
+}
+
+/*垂直布局
+四
+三
+二
+一
+*/
+.flexdidireverses {
+ display: flex;
+ flex-direction: column-reverse;
+}
+
+.fontcolorsysl {
+ color: #FF0000
+}
+
+.fontcolorsyslhei {
+ color: #000000
+}
+
+.fontcolorsyslhui {
+ color: #888888
+}
+
+.fontcolorsyslhui1 {
+ color: #666666;
+}
+
+.fontcolorsysllan {
+ color: #4CACFF
+}
+
+.fontcolorsysljin {
+ color: #DD7600
+}
+
+.w200 {
+ width: 200px;
+}
+
+.w64 {
+ width: 64px;
+}
+
+.w60 {
+ width: 60px;
+}
+
+.w98 {
+ width: 98px;
+}
+
+.myysllineheight {
+ line-height: 40px;
+}
+
+.myyslminwidth {
+ min-width: 60px;
+}
+
+.myyslminwidth276 {
+ width: 276px;
+}
+
+.buttongo {
+ background: #E7E7E7;
+ border: 1px solid #E7E7E7;
+ width: 60px;
+ height: 30px;
+ border-radius: 4px;
+ color: #999999;
+ font-size: 16px;
+}
+
+.buttongo2 {
+ background: #4CACFF;
+ border: 1px solid #4CACFF;
+ width: 64px;
+ height: 32px;
+ border-radius: 4px;
+ color: #FFFFFF;
+ font-size: 16px;
+}
+
+.fontwenzi {
+ text-align: center;
+ line-height: 30px;
+}
+
+.mt17 {
+ margin-top: 17px;
+}
+
+.mt36 {
+ margin-top: 36px;
+}
+
+.mt23 {
+ margin-top: 23px;
+}
+
+.mt19 {
+ margin-top: 19px;
+}
+
+.mt23 {
+ margin-top: 23px;
+}
+
+.mt34 {
+ margin-top: 34px;
+}
+
+.ml11 {
+ margin-left: 11px;
+}
+
+.ml38 {
+ margin-left: 38px;
+}
+
+.ml7 {
+ margin-left: 7px;
+}
+
+.colorgreenlight {
+ color: #6EC76E
+}
+
+.colorgreenorg {
+ color: #FF7300;
+}
+
+.borcolors {
+ border: 1px solid #4CACFF;
+
+ text-align: center;
+}
+
+.mycompitcursor {
+ cursor: pointer;
+}
+
+.basicForm {
+ background: #fff;
+ padding: 30px;
+ margin-bottom: 10px;
+ box-sizing: border-box;
+ width: 100%;
+ min-height: 390px;
+}
+
+.basicForm .title {
+ font-size: 16px;
+ padding-left: 30px;
+ margin-bottom: 10px;
+}
+
+.flexTable {
+ display: flex;
+ flex-direction: column;
+}
+
+.flexRow {
+ display: flex;
+}
+
+.mb15 {
+ margin-bottom: 15px !important;
+}
+
+/* BUTTOn */
+.ant-btn {
+ border-radius: 2px;
+}
+
+button.ant-btn.ant-btn-primary.grayBtn {
+ background: #CBCBCB;
+ border-color: #CBCBCB;
+}
+
+.borderBottom {
+ border-bottom: 1px solid #4CACFF;
+}
+
+/* form ---------------- START */
+.formItemInline {
+ display: flex;
+}
+
+.formItemInline .ant-form-item-control-wrapper {
+ display: inline-block;
+}
+
+.hideRequireTag .ant-form-item-required:before {
+ display: none;
+}
+
+
+/* .basicForm .ant-form-item-label {
+ width: 100px;
+ padding-right: 10px;
+}
+ .basicForm .ant-form-item-label label {
+ color: #979797
+ } */
+
+
+.courseNormalForm .ant-select-show-search {
+ height: 40px;
+}
+
+.courseNormalForm .ant-select-auto-complete.ant-select .ant-input {
+ height: 40px;
+}
+
+.courseNormalForm .ant-select-search__field__mirror {
+ height: 40px;
+}
+
+.courseNormalForm .ant-input-lg {
+ height: 40px;
+}
+
+.courseNormalForm .ant-select-selection--single {
+ height: 40px;
+}
+
+.courseNormalForm .ant-select-auto-complete.ant-select .ant-select-selection--single {
+ height: 40px
+}
+
+.courseNormalForm .ant-input-affix-wrapper {
+ height: 40px;
+}
+
+/* 职业 */
+.courseNormalForm .ant-select-selection-selected-value {
+ line-height: 38px
+}
+
+.courseNormalForm input {
+ height: 40px;
+}
+
+.w300 {
+ width: 300px;
+}
+
+.w56 {
+ width: 56px;
+}
diff --git a/public/react/src/modules/courses/competitions/Competitions.js b/public/react/src/modules/courses/competitions/Competitions.js
new file mode 100644
index 000000000..704b85ef9
--- /dev/null
+++ b/public/react/src/modules/courses/competitions/Competitions.js
@@ -0,0 +1,92 @@
+import React, { Component } from 'react';
+
+import { Redirect } from 'react-router';
+
+import { Route, Link, Switch } from "react-router-dom";
+
+import Loading from '../../Loading';
+
+import Loadable from 'react-loadable';
+import { TPMIndexHOC } from '../tpm/TPMIndexHOC';
+import { CNotificationHOC } from '../courses/common/CNotificationHOC';
+
+//新版竞赛首页
+const CompetitionsIndex = Loadable({
+ loader: () => import('./Competitimain/CompetitionsIndex'),
+ loading: Loading,
+})
+
+//竞赛详情页
+const CompetitionCommon=Loadable({
+ loader: () => import('./Competitioncommon/CompetitionCommon'),
+ loading: Loading,
+})
+
+
+//战队详情
+const CompetitionTeams = Loadable({
+ loader: () => import('./Competition_teams/Competitionteams'),
+ loading: Loading,
+})
+
+//团队竞赛报名
+const Registration = Loadable({
+ loader: () => import('../competition/Registration'),
+ loading: Loading,
+});
+
+class Competitions extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ componentDidMount(){
+
+ window.document.title = '竞赛';
+ }
+
+ render() {
+
+ return (
+
+
+
+
+ {/*新版竞赛战队详情*/}
+ ()
+ }
+ >
+
+
+ {/*新版竞赛报名*/}
+ ()
+ }
+ />
+
+ {/*新版竞赛详情页面*/}
+ ()
+ }
+ >
+
+ {/*新版竞赛首页*/}
+ ()
+ }
+ >
+
+
+
+
+ );
+ }
+}
+
+export default CNotificationHOC() (TPMIndexHOC (Competitions)) ;
\ No newline at end of file
From f27b3eb43a597f91b763a7cd232870fd59f73c9f Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Tue, 19 Nov 2019 19:30:38 +0800
Subject: [PATCH 05/17] =?UTF-8?q?=E7=BC=96=E8=BE=91=E9=A1=B5=E9=9D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../newOrEditTask/leftpane/editorTab/index.js | 34 ++++++++++++++++---
.../developer/newOrEditTask/leftpane/index.js | 13 +++----
2 files changed, 36 insertions(+), 11 deletions(-)
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 50f67d1b3..9c4499dee 100644
--- a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
@@ -1,17 +1,41 @@
import React, { PureComponent } from 'react';
-import { Form } from 'antd';
-import connect from 'react-redux';
+import { Form, Input, Button } from 'antd';
+const FormItem = Form.Item;
class EditTab extends PureComponent {
+ handleSubmit = (e) => {
+ e.preventDefault();
+ this.props.form.validateFieldsAndScroll((err, value) => {
+ if (!err) {
+ console.log(value);
+ }
+ })
+ }
+
render () {
+ const { form } = this.props;
+ const { getFieldDecorator } = form;
return (
-
+
)
}
}
-// export default connect()(EditTab);
-export default EditTab;
+const EditTabForm = Form.create()(EditTab);
+export default EditTabForm;
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/index.js b/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
index 08f788796..6a5e93923 100644
--- a/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/index.js
@@ -3,7 +3,7 @@
* @Author: tangjiang
* @Date: 2019-11-19 11:35:30
* @Last Modified by: tangjiang
- * @Last Modified time: 2019-11-19 11:36:10
+ * @Last Modified time: 2019-11-19 19:07:02
*/
import './index.scss';
@@ -12,24 +12,25 @@ import { Tabs } from 'antd';
import EditorTab from './editorTab';
import PrevTab from './prevTab';
import CommitTab from './commitTab';
+// import * from 'rc-form';
const { TabPane } = Tabs;
const LeftPane = () => {
- const [defaultActiveKey, setDefaultActiveKey] = useState('prev');
+ const [defaultActiveKey, setDefaultActiveKey] = useState('editor');
const tabArrs = [
- { title: '编辑', key: 'editor', content: EditorTab },
- { title: '预览', key: 'prev', content: PrevTab },
- { title: '提交记录', key: 'commit', content: CommitTab },
+ { title: '编辑', key: 'editor', content: ( this.form} />) },
+ { title: '预览', key: 'prev', content: () },
+ { title: '提交记录', key: 'commit', content: () },
];
const tabs = tabArrs.map((tab) => {
const Comp = tab.content;
return (
-
+ { Comp }
)
});
From 2140bb7a3ca69b39eb903d11aebdbe4bd8bea8d2 Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Tue, 19 Nov 2019 22:20:41 +0800
Subject: [PATCH 06/17] merge code
---
public/react/index.js | 46 +
public/react/src/tpm/1.js | 83 +
.../react/src/tpm/Audit_situationComponent.js | 260 ++
public/react/src/tpm/NewFooter.js | 67 +
public/react/src/tpm/NewHeader.js | 1427 ++++++++++
public/react/src/tpm/SiderBar.js | 143 +
public/react/src/tpm/TPMBanner.js | 1056 +++++++
public/react/src/tpm/TPMChallenge.js | 54 +
public/react/src/tpm/TPMChallengeContainer.js | 34 +
public/react/src/tpm/TPMCollaborators.js | 53 +
.../src/tpm/TPMCollaboratorsContainer.js | 47 +
public/react/src/tpm/TPMFork/TPMForklist.js | 213 ++
.../react/src/tpm/TPMFork/shixunCss/fork.css | 3 +
.../react/src/tpm/TPMFork/shixunCss/tag2.png | Bin 0 -> 1170 bytes
public/react/src/tpm/TPMFork_listContainer.js | 50 +
public/react/src/tpm/TPMForklist.js | 63 +
public/react/src/tpm/TPMIndex.css | 229 ++
public/react/src/tpm/TPMIndex.js | 416 +++
public/react/src/tpm/TPMIndexHOC.js | 754 +++++
public/react/src/tpm/TPMPropaedeutics.js | 74 +
.../src/tpm/TPMPropaedeuticsComponent.js | 39 +
public/react/src/tpm/TPMRanking_list.js | 59 +
.../react/src/tpm/TPMRanking_listContainer.js | 37 +
public/react/src/tpm/TPMRepository.js | 58 +
.../react/src/tpm/TPMRepositoryComponent.js | 229 ++
public/react/src/tpm/TPMShixunDiscuss.css | 47 +
public/react/src/tpm/TPMShixunDiscuss.js | 72 +
.../src/tpm/TPMShixunDiscussContainer.js | 45 +
.../TPMUpdatepropaede/TPMUpdatepropaede.js | 100 +
.../react/src/tpm/TPMsettings/TPMsettings.js | 2437 +++++++++++++++++
.../src/tpm/TPMsettings/css/TPMsettings.css | 113 +
public/react/src/tpm/beian.png | Bin 0 -> 19256 bytes
.../src/tpm/challengesnew/TPMMDEditor.js | 355 +++
.../react/src/tpm/challengesnew/TPManswer.js | 366 +++
.../react/src/tpm/challengesnew/TPManswer2.js | 368 +++
.../src/tpm/challengesnew/TPMchallengesnew.js | 615 +++++
.../src/tpm/challengesnew/TPMevaluation.js | 1213 ++++++++
.../src/tpm/challengesnew/TPMquestion.js | 1052 +++++++
.../src/tpm/challengesnew/TpmQuestionEdit.js | 229 ++
.../src/tpm/challengesnew/TpmQuestionMain.js | 84 +
.../src/tpm/challengesnew/TpmQuestionNew.js | 219 ++
.../challengesnew/css/TPMchallengesnew.css | 269 ++
.../react/src/tpm/challengesnew/editorMD.js | 122 +
public/react/src/tpm/component/TPMNav.js | 57 +
.../src/tpm/component/TPMRightSection.js | 205 ++
public/react/src/tpm/component/TPMright.css | 79 +
.../component/modal/RepositoryChooseModal.js | 153 ++
public/react/src/tpm/newshixuns/Newshixuns.js | 1356 +++++++++
.../newshixuns/TPMNewshixuns/TPMNewshixuns.js | 19 +
.../src/tpm/newshixuns/css/Newshixuns.css | 397 +++
public/react/src/tpm/roundedRectangle.png | Bin 0 -> 720 bytes
.../tpm/shixunchild/Challenges/Challenges.js | 676 +++++
.../Collaborators/Collaborators.css | 9 +
.../Collaborators/Collaborators.js | 658 +++++
.../Propaedeutics/Propaedeu_tics.js | 114 +
.../shixunchild/Ranking_list/Ranking_list.js | 145 +
.../tpm/shixunchild/Repository/Repository.js | 266 ++
.../Repository/RepositoryAddFile.js | 198 ++
.../Repository/RepositoryCodeEditor.js | 185 ++
.../Repository/RepositoryCombinePath.js | 82 +
.../Repository/RepositoryDirectories.js | 66 +
.../Repository/TPMRepositoryCommits.js | 145 +
.../ShixunDiscuss/ShixunDiscuss.js | 170 ++
.../src/tpm/shixunchild/Shixunfork_list.js | 69 +
.../shixunchild/shixunchildCss/Challenges.css | 28 +
.../shixunchildCss/Shixunfork_list.css | 6 +
public/react/src/tpm/shixuns/ShixunCard.js | 200 ++
.../react/src/tpm/shixuns/ShixunCardList.js | 253 ++
.../react/src/tpm/shixuns/ShixunSearchBar.js | 292 ++
public/react/src/tpm/shixuns/ShixunsIndex.js | 422 +++
.../react/src/tpm/shixuns/css/TPMBanner.css | 114 +
.../tpm/shixuns/shixunCss/ShixunCardList.css | 13 +
.../tpm/shixuns/shixunCss/ShixunSearchBar.css | 20 +
.../src/tpm/shixuns/shixunCss/shixunCard.css | 42 +
.../react/src/tpm/shixuns/shixunCss/tag2.png | Bin 0 -> 1170 bytes
.../shixuns/shixusFunction/ShixunSearchBar.js | 142 +
76 files changed, 19781 insertions(+)
create mode 100644 public/react/index.js
create mode 100644 public/react/src/tpm/1.js
create mode 100644 public/react/src/tpm/Audit_situationComponent.js
create mode 100644 public/react/src/tpm/NewFooter.js
create mode 100644 public/react/src/tpm/NewHeader.js
create mode 100644 public/react/src/tpm/SiderBar.js
create mode 100644 public/react/src/tpm/TPMBanner.js
create mode 100644 public/react/src/tpm/TPMChallenge.js
create mode 100644 public/react/src/tpm/TPMChallengeContainer.js
create mode 100644 public/react/src/tpm/TPMCollaborators.js
create mode 100644 public/react/src/tpm/TPMCollaboratorsContainer.js
create mode 100644 public/react/src/tpm/TPMFork/TPMForklist.js
create mode 100644 public/react/src/tpm/TPMFork/shixunCss/fork.css
create mode 100644 public/react/src/tpm/TPMFork/shixunCss/tag2.png
create mode 100644 public/react/src/tpm/TPMFork_listContainer.js
create mode 100644 public/react/src/tpm/TPMForklist.js
create mode 100644 public/react/src/tpm/TPMIndex.css
create mode 100644 public/react/src/tpm/TPMIndex.js
create mode 100644 public/react/src/tpm/TPMIndexHOC.js
create mode 100644 public/react/src/tpm/TPMPropaedeutics.js
create mode 100644 public/react/src/tpm/TPMPropaedeuticsComponent.js
create mode 100644 public/react/src/tpm/TPMRanking_list.js
create mode 100644 public/react/src/tpm/TPMRanking_listContainer.js
create mode 100644 public/react/src/tpm/TPMRepository.js
create mode 100644 public/react/src/tpm/TPMRepositoryComponent.js
create mode 100644 public/react/src/tpm/TPMShixunDiscuss.css
create mode 100644 public/react/src/tpm/TPMShixunDiscuss.js
create mode 100644 public/react/src/tpm/TPMShixunDiscussContainer.js
create mode 100644 public/react/src/tpm/TPMUpdatepropaede/TPMUpdatepropaede.js
create mode 100644 public/react/src/tpm/TPMsettings/TPMsettings.js
create mode 100644 public/react/src/tpm/TPMsettings/css/TPMsettings.css
create mode 100755 public/react/src/tpm/beian.png
create mode 100644 public/react/src/tpm/challengesnew/TPMMDEditor.js
create mode 100644 public/react/src/tpm/challengesnew/TPManswer.js
create mode 100644 public/react/src/tpm/challengesnew/TPManswer2.js
create mode 100644 public/react/src/tpm/challengesnew/TPMchallengesnew.js
create mode 100644 public/react/src/tpm/challengesnew/TPMevaluation.js
create mode 100644 public/react/src/tpm/challengesnew/TPMquestion.js
create mode 100644 public/react/src/tpm/challengesnew/TpmQuestionEdit.js
create mode 100644 public/react/src/tpm/challengesnew/TpmQuestionMain.js
create mode 100644 public/react/src/tpm/challengesnew/TpmQuestionNew.js
create mode 100644 public/react/src/tpm/challengesnew/css/TPMchallengesnew.css
create mode 100644 public/react/src/tpm/challengesnew/editorMD.js
create mode 100644 public/react/src/tpm/component/TPMNav.js
create mode 100644 public/react/src/tpm/component/TPMRightSection.js
create mode 100644 public/react/src/tpm/component/TPMright.css
create mode 100644 public/react/src/tpm/component/modal/RepositoryChooseModal.js
create mode 100644 public/react/src/tpm/newshixuns/Newshixuns.js
create mode 100644 public/react/src/tpm/newshixuns/TPMNewshixuns/TPMNewshixuns.js
create mode 100644 public/react/src/tpm/newshixuns/css/Newshixuns.css
create mode 100755 public/react/src/tpm/roundedRectangle.png
create mode 100644 public/react/src/tpm/shixunchild/Challenges/Challenges.js
create mode 100644 public/react/src/tpm/shixunchild/Collaborators/Collaborators.css
create mode 100644 public/react/src/tpm/shixunchild/Collaborators/Collaborators.js
create mode 100644 public/react/src/tpm/shixunchild/Propaedeutics/Propaedeu_tics.js
create mode 100644 public/react/src/tpm/shixunchild/Ranking_list/Ranking_list.js
create mode 100644 public/react/src/tpm/shixunchild/Repository/Repository.js
create mode 100644 public/react/src/tpm/shixunchild/Repository/RepositoryAddFile.js
create mode 100644 public/react/src/tpm/shixunchild/Repository/RepositoryCodeEditor.js
create mode 100644 public/react/src/tpm/shixunchild/Repository/RepositoryCombinePath.js
create mode 100644 public/react/src/tpm/shixunchild/Repository/RepositoryDirectories.js
create mode 100644 public/react/src/tpm/shixunchild/Repository/TPMRepositoryCommits.js
create mode 100644 public/react/src/tpm/shixunchild/ShixunDiscuss/ShixunDiscuss.js
create mode 100644 public/react/src/tpm/shixunchild/Shixunfork_list.js
create mode 100644 public/react/src/tpm/shixunchild/shixunchildCss/Challenges.css
create mode 100644 public/react/src/tpm/shixunchild/shixunchildCss/Shixunfork_list.css
create mode 100644 public/react/src/tpm/shixuns/ShixunCard.js
create mode 100644 public/react/src/tpm/shixuns/ShixunCardList.js
create mode 100644 public/react/src/tpm/shixuns/ShixunSearchBar.js
create mode 100644 public/react/src/tpm/shixuns/ShixunsIndex.js
create mode 100644 public/react/src/tpm/shixuns/css/TPMBanner.css
create mode 100644 public/react/src/tpm/shixuns/shixunCss/ShixunCardList.css
create mode 100644 public/react/src/tpm/shixuns/shixunCss/ShixunSearchBar.css
create mode 100644 public/react/src/tpm/shixuns/shixunCss/shixunCard.css
create mode 100644 public/react/src/tpm/shixuns/shixunCss/tag2.png
create mode 100644 public/react/src/tpm/shixuns/shixusFunction/ShixunSearchBar.js
diff --git a/public/react/index.js b/public/react/index.js
new file mode 100644
index 000000000..cb8cb4f94
--- /dev/null
+++ b/public/react/index.js
@@ -0,0 +1,46 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+
+import './index.css';
+import './indexPlus.css';
+import App from './App';
+
+// 加之前main.js 18.1MB
+// import { message } from 'antd';
+import message from 'antd/lib/message';
+import 'antd/lib/message/style/css';
+
+import { AppContainer } from 'react-hot-loader';
+
+import registerServiceWorker from './registerServiceWorker';
+
+import { configureUrlQuery } from 'react-url-query';
+
+import history from './history';
+
+// link the history used in our app to url-query so it can update the URL with it.
+configureUrlQuery({ history });
+// ----------------------------------------------------------------------------------- 请求配置
+
+window.__useKindEditor = false;
+
+
+const render = (Component) => {
+ ReactDOM.render(
+
+
+ ,
+ document.getElementById('root')
+ );
+}
+
+
+// ReactDOM.render(
+// ,
+// document.getElementById('root'));
+// registerServiceWorker();
+
+render(App);
+if (module.hot) {
+ module.hot.accept('./App', () => { render(App) });
+}
diff --git a/public/react/src/tpm/1.js b/public/react/src/tpm/1.js
new file mode 100644
index 000000000..1a1494e08
--- /dev/null
+++ b/public/react/src/tpm/1.js
@@ -0,0 +1,83 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import PropTypes from 'prop-types';
+
+import Comments from '../comment/Comments'
+
+import { commentHOC } from '../comment/CommentsHOC'
+import { CircularProgress } from 'material-ui/Progress';
+
+import './TPMShixunDiscuss.css'
+
+import TPMRightSection from './component/TPMRightSection'
+import TPMNav from './component/TPMNav'
+
+class TPMShixunDiscuss extends Component {
+ constructor(props) {
+ super(props)
+
+ }
+
+ componentWillReceiveProps(newProps, newContext) {
+ if (newProps.shixun && newProps.shixun.id && (!this.props || !this.props.shixun || this.props.shixun.id != newProps.shixun.id) ) {
+ window.document.title = newProps.shixun.name
+ // this.props.fetchCommentIfNotFetched &&
+ // this.props.fetchCommentIfNotFetched();
+ }
+ }
+
+ componentDidMount() {
+ // TODO 加了HOC后 mount了两次
+ this.props.fetchCommentIfNotFetched &&
+ this.props.fetchCommentIfNotFetched();
+ }
+ //
+
+ onPaginationChange = (page) => {
+ window.$("html,body").animate({"scrollTop":160})
+ this.props.onPaginationChange(page)
+ }
+
+ render() {
+ const { loadingComments, creator, shixun, myshixun, recommend_shixuns, current_user, watched,
+ aboutFocus, user, match
+ } = this.props;
+
+ let _user = user;
+ if (user) {
+ _user = Object.assign({}, user);
+ _user.user_url = `/users/${user.login}`
+ }
+ return (
+
+
+
+
+
+ { loadingComments ?
+ :
+
+ }
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+export default commentHOC( TPMShixunDiscuss );
diff --git a/public/react/src/tpm/Audit_situationComponent.js b/public/react/src/tpm/Audit_situationComponent.js
new file mode 100644
index 000000000..4d6c413da
--- /dev/null
+++ b/public/react/src/tpm/Audit_situationComponent.js
@@ -0,0 +1,260 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+import { List,Typography,Tag,Modal,Radio} from 'antd';
+
+import TPMRightSection from './component/TPMRightSection';
+import TPMNav from './component/TPMNav';
+import axios from 'axios';
+
+class Audit_situationComponent extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ datas:undefined,
+ value:undefined,
+ }
+ }
+
+ componentDidMount() {
+ this.getdatas()
+
+ }
+
+
+ getdatas=()=>{
+
+ let url=`/shixuns/${this.props.match.params.shixunId}/review_newest_record.json`;
+ axios.get(url).then((response) => {
+
+ if(response.data===undefined||JSON.stringify(response.data) == "{}"||response.data===null){
+ this.setState({
+ datas:[
+ {
+ name: '内容审核情况',
+ id:"Content",
+ },
+ {
+ name: '性能审核情况',
+ id:"Performance",
+ },
+ ]
+ })
+ }else{
+ let newlist=[]
+ if(response.data.content_info!=undefined&&response.data.perference_info===undefined){
+ let arr=[
+ {
+ name: '内容审核情况',
+ id:"Content",
+ status:response.data.content_info.status,
+ username:response.data.content_info.username,
+ time:response.data.content_info.time,
+ },
+ {
+ name: '性能审核情况',
+ id:"Performance",
+ },
+ ]
+ newlist=arr
+ }
+
+ if(response.data.content_info===undefined&&response.data.perference_info!=undefined){
+ let arr=[
+ {
+ name: '内容审核情况',
+ id:"Content",
+ },
+ {
+ name: '性能审核情况',
+ id:"Performance",
+ status:response.data.perference_info.status,
+ username:response.data.perference_info.username,
+ time:response.data.perference_info.time,
+ },
+ ]
+ newlist=arr
+ }
+
+ if(response.data.content_info!=undefined&&response.data.perference_info!=undefined){
+ let arr=[
+ {
+ name: '内容审核情况',
+ id:"Content",
+ status:response.data.content_info.status,
+ username:response.data.content_info.username,
+ time:response.data.content_info.time,
+ },
+ {
+ name: '性能审核情况',
+ id:"Performance",
+ status:response.data.perference_info.status,
+ username:response.data.perference_info.username,
+ time:response.data.perference_info.time,
+ },
+ ]
+ newlist=arr
+ }
+
+ this.setState({
+ datas:newlist
+ })
+
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ showModal = (id,status) => {
+ debugger
+ this.setState({
+ visible: true,
+ editid:id,
+ value:status
+ });
+ };
+
+ handleOk=(id,editid)=>{
+ let url = `/shixuns/${this.props.match.params.shixunId}/review_shixun.json`;
+ axios.post(url, {
+ status: id===undefined?1:id,
+ review_type: editid,
+ }).then((response) => {
+ if(response.data.status===0){
+ this.props.showNotification(response.data.message);
+ this.setState({
+ visible: false,
+ });
+ this.getdatas()
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+ };
+
+ handleCancel = e => {
+ this.setState({
+ visible: false,
+ });
+ };
+
+ onChange = e => {
+ this.setState({
+ value: e.target.value,
+ });
+ };
+ render() {
+ const { tpmLoading, shixun, user, match } = this.props;
+ let {value,editid,datas}=this.state;
+
+ console.log(this.props)
+ return (
+
+
+ {this.state.visible===true?
+
+
+
+
+ 已完成
+ 未完成
+
+
+
+
+
+
+ :""}
+
+
+
+ { tpmLoading ? :
+
+
+
+
+
+
+
+
+ {this.props.identity >2||this.props.identity===undefined?"":
(
+ this.showModal(item.id,item.status)} key={key}>
+
+ ,
+ ]}
+ >
+
+ {item.name}
+ {item.status===undefined?"":item.status===1?已完成:未完成}
+
}
+ description={
+
+ {item.time===undefined?"":审核时间: {item.time}}
+ {item.username===undefined?"":审核人: {item.username}}
+
+ }
+ />
+
+ )}
+ />}
+
+
+
+
+
+
+
+
+
+ }
+
+ );
+ }
+}
+
+export default Audit_situationComponent;
diff --git a/public/react/src/tpm/NewFooter.js b/public/react/src/tpm/NewFooter.js
new file mode 100644
index 000000000..4ff1cc46a
--- /dev/null
+++ b/public/react/src/tpm/NewFooter.js
@@ -0,0 +1,67 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+import { Link } from 'react-router-dom';
+import { getImageUrl, toPath } from 'educoder'
+import PropTypes from 'prop-types';
+
+class NewFooter extends Component {
+ constructor(props) {
+ super(props)
+
+ }
+
+ componentWillReceiveProps(newProps, newContext) {
+
+ }
+
+
+ render() {
+ return (
+
+ {/*newContainers*/}
+
+ {this.props.user&&this.props.user.main_site===true?
+ {/*
*/}
+
+ - 网站首页
+ - 关于我们
+ - 联系我们
+ - 合作伙伴
+ - 服务协议
+ - 帮助中心
+ - 意见反馈
+
+
:""}
+
+ {this.props.mygetHelmetapi === null ? "" :
+ this.props.mygetHelmetapi===undefined|| this.props.mygetHelmetapi.footer===null||this.props.mygetHelmetapi.footer===undefined?
+
+ © 2019 EduCoder
+ 湘ICP备17009477号
+
+
湘公网安备43019002000962号
+
+ Trustie & IntelliDE inside. 版权所有 湖南智擎科技有限公司
+
+ :
+
+
+ }
+
+
+
+
+
+ );
+ }
+}
+
+export default NewFooter;
diff --git a/public/react/src/tpm/NewHeader.js b/public/react/src/tpm/NewHeader.js
new file mode 100644
index 000000000..41855c15a
--- /dev/null
+++ b/public/react/src/tpm/NewHeader.js
@@ -0,0 +1,1427 @@
+import React, { Component } from 'react';
+import { BrowserRouter as Router, Route, Link } from "react-router-dom";
+import { Redirect } from 'react-router';
+import AccountProfile from"../user/AccountProfile";
+import PropTypes from 'prop-types';
+import Certifiedprofessional from "../../modules/modals/Certifiedprofessional"
+
+// import searchImg from '../../../../images/educoder/icon/search.svg'
+
+// /images/educoder/icon/search.svg
+
+import { getImageUrl, toPath ,trigger,broadcastChannelPostMessage} from 'educoder'
+
+import axios from 'axios';
+
+import { Modal,Checkbox ,Radio,Input,message,notification } from 'antd';
+
+import Addcourses from '../courses/coursesPublic/Addcourses';
+
+import LoginDialog from '../login/LoginDialog';
+
+import Trialapplication from '../login/Trialapplication'
+
+import 'antd/lib/modal/style/index.css';
+
+import 'antd/lib/checkbox/style/index.css';
+
+import 'antd/lib/radio/style/index.css';
+
+import 'antd/lib/input/style/index.css';
+
+import './TPMIndex.css';
+
+const $ = window.$
+// TODO 这部分脚本从公共脚本中直接调用
+
+const RadioGroup = Radio.Group;
+const { Search } = Input;
+let old_url;
+
+/*
+ _logined_header.html.erb
+ _unlogin_header.html.erb
+*/
+window._header_componentHandler = null;
+class NewHeader extends Component {
+ constructor(props) {
+ super(props)
+ this.state={
+ Addcoursestypes:false,
+ tojoinitemtype:false,
+ tojoinclasstitle:undefined,
+ rolearr:["",""],
+ Checkboxteacherchecked:false,
+ Checkboxstudentchecked:false,
+ Checkboxteachingchecked:false,
+ Checkboxteachertype:false,
+ Checkboxteachingtype:false,
+ code_notice:false,
+ checked_notice:false,
+ RadioGroupvalue:undefined,
+ submitapplications:false,
+ isRender:false,
+ showSearchOpentype:false,
+ showTrial:false,
+ setevaluatinghides:false,
+ occupation:0,
+ mydisplay:false,
+ headtypesonClickbool:false,
+ headtypess:"/",
+ mygetHelmetapi2: null,
+ }
+ console.log("176")
+ // console.log(props);
+ // console.log("NewHeader1234567890");
+ // console.log(this.props);
+ }
+ componentDidUpdate = (prevProps) => {
+ // console.log("componentDidMount2");
+ // console.log(this.state.mygetHelmetapi2);
+ if(this.state.mygetHelmetapi2===undefined){
+ this.getAppdata();
+ }
+ }
+ componentDidMount() {
+ console.log("componentDidMount1");
+ this.getAppdata();
+ window._header_componentHandler = this;
+
+ //下拉框的显示隐藏
+ var hoverTimeout;
+ var hoveredPanel;
+ $(".edu-menu-panel").hover(function(){
+ if (hoverTimeout) { // 一次只显示一个panel
+ if (hoveredPanel && hoveredPanel != this) {
+ $(hoveredPanel).find(".edu-menu-list").hide()
+ }
+ clearTimeout(hoverTimeout);
+ hoverTimeout = null;
+ }
+ hoveredPanel = this;
+ $(this).find(".edu-menu-list").show();
+ },function(){
+ var that =this;
+ // 延迟hide
+ hoverTimeout = setTimeout(function() {
+ $(that).find(".edu-menu-list").hide();
+ }, 800)
+
+ });
+
+ //获取游览器地址
+ try {
+ window.sessionStorage.setItem("yslgeturls", JSON.stringify(window.location.href))
+ } catch (e) {
+
+ }
+ // axios.interceptors.response.use((response) => {
+ // if (response != undefined)
+ // if (response && response.data.status === -1) {
+ // if (response.data.message === "该课堂要求成员完成实名认证") {
+ //
+ // } else if (response.data.message === "该课堂要求成员完成职业认证") {
+ // console.log("该课堂要求成员完成职业认证");
+ // this.HideAddcoursestypess(2);
+ //
+ //
+ //
+ // return
+ // } else if (response.data.message === "该课堂要求成员完成实名和职业认证") {
+ // console.log("该课堂要求成员完成实名和职业认证");
+ // this.HideAddcoursestypess(3);
+ // return
+ //
+ // }
+ // }
+ // return response;
+ // }, (error) => {
+ //
+ // });
+ }
+
+ componentDidUpdate = (prevProps) => {
+ // if(prevProps.user!=this.props.user){
+ // // console.log("216")
+ // // console.log(prevProps.user);
+ // // console.log(this.props.user);
+ // if(this.props.user !== undefined){
+ // this.setState({
+ // user_phone_binded :this.props.user.user_phone_binded,
+ // })
+ // }
+ //
+ //
+ // }
+ }
+
+ openNotification = (messge) => {
+ notification.open({
+ message: "提示",
+ description:
+ messge,
+ });
+ };
+
+ componentWillReceiveProps(newProps, oldProps) {
+ this.setState({
+ user:newProps.user
+ })
+ if(newProps.Headertop!=undefined){
+ old_url=newProps.Headertop.old_url
+ }
+
+ }
+ getCookie=(key)=>{
+ var arr,reg = RegExp('(^| )'+key+'=([^;]+)(;|$)');
+ if (arr = document.cookie.match(reg)) //["username=liuwei;", "", "liuwei", ";"]
+ return decodeURIComponent(arr[2]);
+ else
+ return null;
+ }
+
+ delCookie=(name)=>{
+ var exp = new Date();
+ exp.setTime(exp.getTime() - 1);
+ var cval=this.getCookie(name);
+ if(cval!=null){
+ document.cookie= name + "="+cval+";expires="+exp.toGMTString();
+ }
+ }
+ onLogout = () => {
+ const url = `/accounts/logout.json`
+ this.delCookie("autologin_trustie")
+ axios.get(url, {
+ })
+ .then((response) => {
+ if(response.data.status===1){
+ this.setState({
+ user:undefined
+ })
+ // let path="/";
+ // this.props.history.push(path);
+ // broadcastChannelPostMessage('refreshPage')
+ window.location.href ="/login"
+ message.success('退出成功');
+ }
+ });
+ }
+
+ tojoinclass=()=>{
+ let{user} =this.state;
+ if(user===undefined){
+ this.setState({
+ isRender:true
+ })
+ return
+ }
+ if(user&&user.login===""){
+ this.setState({
+ isRender:true
+ })
+ return;
+ }
+
+ if(user&&user.profile_completed===false){
+ this.setState({
+ AccountProfiletype:true
+ })
+ return;
+ }
+
+ this.setState({
+ Addcoursestypes:true,
+ })
+ }
+
+ tojoinitem=()=>{
+ if(this.props.user&&this.props.user.email===undefined||this.props.user&&this.props.user.email===null||this.props.user&&this.props.user.email===""){
+ this.openNotification("请先绑定邮箱,谢谢");
+ return
+ }
+ let{user} =this.state;
+ if(user===undefined){
+ this.setState({
+ isRender:true
+ })
+ return
+ }
+ if(user&&user.login===""){
+ this.setState({
+ isRender:true
+ })
+ return;
+ }
+
+ if(user&&user.profile_completed===false){
+ this.setState({
+ AccountProfiletype:true
+ })
+ return;
+ }
+
+ this.setState({
+ tojoinitemtype:true
+ })
+ }
+
+
+ submitstatevalue=(sum,value,data)=>{
+ this.setState({
+ Addcoursestypes:false,
+ tojoinitemtype:false,
+ tojoinclasstitle:undefined,
+ rolearr:["",""],
+ Checkboxteacherchecked:false,
+ Checkboxstudentchecked:false,
+ Checkboxteachingchecked:false,
+ Checkboxteachertype:false,
+ Checkboxteachingtype:false,
+ code_notice:false,
+ checked_notice:false,
+ submitapplicationssum:sum,
+ submitapplications:true,
+ submitapplicationsvalue:value,
+ submitapplicationsvaluedata:data,
+ RadioGroupvalue:undefined
+ })
+ }
+
+ onChangeRadioGroup = (e) => {
+ this.setState({
+ RadioGroupvalue: e.target.value,
+ });
+ }
+
+ submitsubmitapplications=()=>{
+ let {
+ submitapplicationssum,
+ submitapplicationsvaluedata
+ }=this.state;
+ this.setState({
+ submitapplications:false,
+ RadioGroupvalue:undefined
+ })
+ if(submitapplicationssum===0){
+ if(submitapplicationsvaluedata!=undefined){
+ window.location.href = "/courses/"+submitapplicationsvaluedata;
+ }
+ }else if(submitapplicationssum===1){
+ if(submitapplicationsvaluedata!=undefined){
+ window.location.href = "/projects/"+submitapplicationsvaluedata;
+ }
+ }
+ }
+
+ hidesubmitapplications=()=>{
+ this.setState({
+ Addcoursestypes:false,
+ tojoinitemtype:false,
+ tojoinclasstitle:undefined,
+ rolearr:["",""],
+ Checkboxteacherchecked:false,
+ Checkboxstudentchecked:false,
+ Checkboxteachingchecked:false,
+ Checkboxteachertype:false,
+ Checkboxteachingtype:false,
+ code_notice:false,
+ checked_notice:false,
+ submitapplications:false,
+ RadioGroupvalue:undefined
+ })
+ }
+ educoderlogin=()=>{
+ //登录账号
+ this.setState({
+ isRender:true
+ })
+ // var url = `/accounts/logout.json`;
+ //
+ // axios.get((url)).then((result) => {
+ // if(result!==undefined){
+ // // this.setState({
+ // // isRender:true
+ // // })
+ // window.location.href = "/";
+ // }
+ // }).catch((error) => {
+ // console.log(error);
+ // })
+ }
+ educoderloginysl=()=>{
+ //退出账号
+ // this.setState({
+ // isRender:true
+ // })
+ var url = `/accounts/logout.json`;
+
+ axios.get((url)).then((result) => {
+ if(result!==undefined){
+ // this.setState({
+ // isRender:true
+ // })
+ // broadcastChannelPostMessage('refreshPage')
+ window.location.href = "/";
+ }
+ }).catch((error) => {
+ console.log(error);
+ })
+ }
+
+ hideAddcoursestypes=()=>{
+ this.setState({
+ Addcoursestypes:false
+ })
+ };
+ HideAddcoursestypess=(i)=>{
+ console.log("调用了");
+ this.setState({
+ Addcoursestypes:false,
+ mydisplay:true,
+ occupation:i,
+ })
+ };
+ ModalCancelsy=()=>{
+ this.setState({
+ mydisplay:false,
+ })
+ };
+
+
+ hidetojoinclass=()=>{
+ this.setState({
+ tojoinclasstype:false,
+ tojoinitemtype:false,
+ tojoinclasstitle:undefined,
+ rolearr:["",""],
+ Checkboxteacherchecked:false,
+ Checkboxstudentchecked:false,
+ Checkboxteachingchecked:false,
+ Checkboxteachertype:false,
+ Checkboxteachingtype:false,
+ code_notice:false,
+ checked_notice:false,
+ RadioGroupvalue:undefined
+ })
+ }
+
+submittojoinclass=(value)=>{
+ let {tojoinclasstitle,rolearr,RadioGroupvalue}=this.state;
+
+ if(tojoinclasstitle===undefined){
+ this.setState({
+ code_notice:true
+ })
+ return
+ }
+ let newrolearr=rolearr;
+ // if(value===1){
+ if(tojoinclasstitle.length<6){
+ this.setState({
+ code_notice:true
+ })
+ return
+ }
+ // }else if(value===0){
+ // if(tojoinclasstitle.length<5){
+ // this.setState({
+ // code_notice:true
+ // })
+ // return
+ // }
+ // }
+ if(tojoinclasstitle===""||tojoinclasstitle===undefined){
+ this.setState({
+ code_notice:true
+ })
+ return
+ }else{
+ this.setState({
+ code_notice:false
+ })
+ }
+
+ let pamst=[];
+ let num=0;
+ for(var i = 0 ; i {
+ // if( response.data.state===0){
+ // this.submitstatevalue(0,"加入成功",response.data.course_id)
+ // }else if( response.data.state===1){
+ // }else if( response.data.state===2){
+ // this.submitstatevalue( 0,"课堂已过期! 请联系课堂管理员重启课堂。(在配置课堂处)")
+ // }else if( response.data.state===3){
+ // this.submitstatevalue( 0,"您已是课堂成员)",response.data.course_id)
+ // }else if( response.data.state===4){
+ // this.submitstatevalue( 0,"您输入的邀请码错误)")
+ // }else if( response.data.state===5){
+ // this.submitstatevalue( 0,"您还未登录")
+ // }else if( response.data.state===6){
+ // this.submitstatevalue( 0,"申请已提交,请等待审核")
+ // }else if( response.data.state===7){
+ // this.submitstatevalue( 0," 您已经发送过申请了,请耐心等待")
+ // }else if( response.data.state===8){
+ // this.submitstatevalue( 0,"您已经是该课堂的教师了",response.data.course_id)
+ // }else if( response.data.state==9){
+ // this.submitstatevalue( 0,"您已经是该课堂的教辅了",response.data.course_id)
+ // }else if( response.data.state==10){
+ // this.submitstatevalue(0,"您已经是该课堂的管理员了",response.data.course_id)
+ // }else if( response.data.state==11){
+ // this.submitstatevalue(0," 该课堂已归档,请联系老师")
+ // }else if( response.data.state==12){
+ // this.submitstatevalue(0,"您已经发送过申请了,请耐心等待师")
+ // }else if( response.data.state==13){
+ // this.submitstatevalue(0,"您申请已提交,请等待审核")
+ // }else if( response.data.state==14){
+ // this.submitstatevalue("此邀请码已停用,请与老师联系")
+ // }else if( response.data.state==15){
+ // this.submitstatevalue(0,"您已是课堂成员! 加入分班请在课堂具体分班页面进行")
+ // }else {
+ // this.submitstatevalue(0," 未知错误,请稍后再试")
+ // }
+ // })
+ //
+ // }
+
+ if(value===1){
+ let url="/project_applies.json"
+ // const form = new FormData();
+ // form.append('code', tojoinclasstitle);
+ // form.append('role', RadioGroupvalue);
+ // form.append('type', 1);
+ axios.post(url,{
+ code:tojoinclasstitle,
+ role:RadioGroupvalue
+ }
+ ).then((response) => {
+ if( response.data.status===1){
+ this.submitstatevalue(1,"您输入的邀请码错误")
+ }else if( response.data.status===2){
+ this.submitstatevalue( 1,"您已经是该项目成员",response.data.project)
+ }else if( response.data.status===3){
+ this.submitstatevalue( 1,"请选择一个角色")
+ }else if( response.data.status===4){
+ this.submitstatevalue( 1,"您的申请已提交,请等待项目管理员审批")
+ }else if( response.data.status===5){
+ this.submitstatevalue( 1,"您已经申请加入该项目了,请耐心等待")
+ }else if( response.data.status===6){
+ this.submitstatevalue( 1,"您已成功加入项目",response.data.project)
+ }else if( response.data.status===0){
+ if(RadioGroupvalue==="reporter"){
+ this.openNotification("您加入项目成功!");
+ window.location.href=`/projects/${response.data.project_id}`;
+ }else{
+ this.openNotification("您的申请已提交,请等待项目管理员审批!");
+ }
+ }
+ })
+ }
+ this.hidetojoinclass()
+}
+
+ // trialapplications =()=>{
+ // console.log("点击了")
+ // this.setState({
+ // isRenders: true,
+ // showTrial:true,
+ // })
+ // }
+
+ // 关闭
+ cancelModulationModels = () => {
+ this.setState({isRenders: false})
+ }
+
+ inputjoinclassvalue=(e)=>{
+ console.log(e.target.value.length);
+ if(e.target.value.length>=7){
+ this.openNotification("请输入6位项目邀请码!");
+ return
+ }
+ this.setState({
+ tojoinclasstitle:e.target.value
+ })
+ }
+
+ showSearchOpen=(e)=>{
+ this.setState({
+ showSearchOpentype:true
+ })
+
+ }
+
+ hideshowSearchOpen=(e)=>{
+ let {setevaluatinghides}=this.state;
+ if(setevaluatinghides===true){
+ this.setState({
+ showSearchOpentype:false,
+ setevaluatinghides:false
+ })
+
+ }
+ }
+
+ onKeywordSearchKeyDown = (value) => {
+ let url=`/search?value=${value}`;
+ this.props.history.push(url)
+ }
+
+ onKeywordSearchKeyDowns=()=>{
+ this.setState(
+ {
+ setevaluatinghides:false
+ }
+ )
+ }
+
+ setevaluatinghides=()=>{
+ this.setState(
+ {
+ setevaluatinghides:true
+ }
+ )
+ }
+ //头部获取是否已经登录了
+ getUser=(url,type)=>{
+
+ if(type==="projects"){
+ if(this.props.user&&this.props.user.email===undefined||this.props.user&&this.props.user.email===null||this.props.user&&this.props.user.email===""){
+ this.openNotification("请先绑定邮箱,谢谢");
+ return
+ }
+ }
+ // console.log("点击了503")
+ // console.log(url);
+ let{user} =this.state;
+
+ if(user===undefined){
+ this.setState({
+ isRender:true
+ })
+ return
+ }
+
+ if(user&&user.login===""){
+ this.setState({
+ isRender:true
+ })
+ return;
+ }
+
+ if(user&&user.profile_completed===false){
+ this.setState({
+ AccountProfiletype:true
+ })
+ return;
+ }
+
+ if(url !== undefined || url!==""){
+ window.location.href = url;
+ }
+
+
+ }
+
+ //修改登录方法
+ Modifyloginvalue=()=>{
+ this.setState({
+ isRender:false,
+ })
+ }
+
+ hideAccountProfile=()=>{
+ this.setState({
+ AccountProfiletype:false
+ })
+ };
+ headtypesonClick=(url,bool)=>{
+ this.setState({
+ headtypess:url,
+ headtypesonClickbool:bool,
+ })
+ }
+ //获取数据为空的时候
+ gettablogourlnull = () => {
+ this.setState({
+ mygetHelmetapi2: undefined
+ });
+ document.title = "EduCoder";
+ var link = document.createElement('link'),
+ oldLink = document.getElementById('dynamic-favicon');
+ link.id = 'dynamic-favicon';
+ link.rel = 'shortcut icon';
+ link.href = "/react/build/./favicon.ico";
+ if (oldLink) {
+ document.head.removeChild(oldLink);
+ }
+ document.head.appendChild(link);
+ };
+
+ //获取数据的时候
+ gettablogourldata = (response) => {
+ document.title = response.data.setting.name;
+ var link = document.createElement('link'),
+ oldLink = document.getElementById('dynamic-favicon');
+ link.id = 'dynamic-favicon';
+ link.rel = 'shortcut icon';
+ link.href = '/' + response.data.setting.tab_logo_url;
+ if (oldLink) {
+ document.head.removeChild(oldLink);
+ }
+ document.head.appendChild(link);
+ }
+
+ getAppdata=()=>{
+ let url = "/setting.json";
+ axios.get(url).then((response) => {
+ // console.log("app.js开始请求/setting.json");
+ // console.log("获取当前定制信息");
+ if(response){
+ if(response.data){
+ this.setState({
+ mygetHelmetapi2:response.data.setting
+ });
+ try {
+ if (response.data.setting.tab_logo_url) {
+ this.gettablogourldata(response);
+ } else {
+ this.gettablogourlnull();
+ }
+ } catch (e) {
+ this.gettablogourlnull();
+ }
+
+
+ } else {
+
+ this.gettablogourlnull();
+
+ }
+
+ } else {
+ this.gettablogourlnull();
+
+ }
+
+ }).catch((error) => {
+ this.gettablogourlnull();
+
+ });
+ };
+ render() {
+ const isLogin = true; // 这里不会出现未登录的情况,服务端在服务端路由时发现如果是未登录,则跳转到登录页了。
+ const {match,} = this.props;
+
+ let {Addcoursestypes,
+ tojoinitemtype,
+ tojoinclasstitle,
+ Checkboxteacherchecked,
+ Checkboxstudentchecked,
+ Checkboxteachingchecked,
+ Checkboxteachertype,
+ Checkboxteachingtype,
+ code_notice,
+ checked_notice,
+ AccountProfiletype,
+ submitapplications,
+ submitapplicationsvalue,
+ user,
+ isRender,
+ showSearchOpentype,
+ headtypesonClickbool,
+ headtypess,
+ mygetHelmetapi2,
+ }=this.state;
+ /*
+ 用户名称 用户头像url
+ */
+ let activeIndex = false;
+ let activeForums = false;
+ let activeShixuns = false;
+ let activePaths = false;
+ let coursestype=false;
+ let activePackages=false;
+ let activeMoopCases=false;
+
+
+ if (match.path === '/forums') {
+ activeForums = true;
+ } else if (match.path.startsWith('/shixuns')) {
+ activeShixuns = true;
+ }else if (match.path.startsWith('/paths')) {
+ activePaths = true;
+ } else if (match.path.startsWith('/courses')) {
+ coursestype = true;
+ }else if (match.path.startsWith('/crowdsourcing')) {
+ activePackages = true;
+ }else if(match.path.startsWith('/moop_cases')){
+ activeMoopCases = true;
+ }else {
+ activeIndex = true;
+ }
+
+ let headtypes='/';
+
+ // console.log("mygetHelmetapi2");
+ // console.log(mygetHelmetapi2);
+ if(mygetHelmetapi2){
+ if(mygetHelmetapi2.navbar){
+ if(mygetHelmetapi2.navbar.length>0){
+ // console.log("mygetHelmetapi2.navbar.length>0====-=-=--=-=-=-=");
+ //
+ // console.log(match.path);
+ if(match.path==='/'){
+ if(headtypesonClickbool===false){
+ headtypes=undefined;
+ }else{
+ headtypes=headtypess;
+ }
+
+ }else {
+ const developer = {
+ name: '开发者社区',
+ link: '/developer',
+ hidden: false
+ };
+ mygetHelmetapi2.navbar.push(developer);
+ for(var i=0;i{
+ var reg = RegExp(item.link);
+ if(shixun.match(reg)){
+ if(item.hidden===true){
+ shixuntype=true
+ }
+ }
+ if(paths.match(reg)){
+ if(item.hidden===true){
+ pathstype=true
+ }
+ }
+ if(courses.match(reg)){
+ if(item.hidden===true){
+ coursestypes=true
+ }
+ }
+ })
+ }
+ return (
+
+
+
+
+
+ );
+ }
+}
+
+export default NewHeader;
+
diff --git a/public/react/src/tpm/SiderBar.js b/public/react/src/tpm/SiderBar.js
new file mode 100644
index 000000000..9312b24fd
--- /dev/null
+++ b/public/react/src/tpm/SiderBar.js
@@ -0,0 +1,143 @@
+import React, { Component } from 'react';
+import { getImageUrl} from 'educoder';
+import './TPMIndex.css';
+
+const $ = window.$;
+
+$(window).resize(function(){
+ rightSlider();
+});
+
+$(window).scroll(function(){
+ if($(".gotop").length>0){
+ if($(document).scrollTop()>0){
+ $(".-task-sidebar .gotop").show();
+ $(".gotop").click(function(){
+ $("html,body").scrollTop(0);
+ });
+ }
+ if($(document).scrollTop()==0){
+ $(".-task-sidebar .gotop").hide();
+ }
+ }
+});
+
+function rightSlider(){
+ var poi=parseInt((parseInt($(window).width())- 1200 )/2)-81;
+ // console.log(parseInt($(window).width())+" "+poi);
+ if(poi>0){
+ $(".-task-sidebar").css("right",poi);
+ }else{
+ $(".-task-sidebar").css("right","0px");
+ }
+ $(".-task-sidebar").show();
+}
+
+
+function _initSider() {
+ var $descSide = $("").appendTo("body");
+ $(".-task-sidebar>div").hover(function(){
+ //移入显示二维码
+ if($(this).hasClass("scan")){
+ $(".scan_ewm").show().css({right:"75px",opacity:0}).stop().animate({
+ right:"45px",opacity:1
+ })
+ return;
+ }
+ var $tool = $(this).attr("tooltips");
+ $descSide.html($tool+"");
+ $descSide.data('_dom', this)
+ $descSide.show().css({
+ left:$(this).offset().left - $descSide.width()-30,
+ opacity:0,
+ top:$(this).offset().top
+ }).stop().animate({
+ left:$(this).offset().left - $descSide.width()-5,
+ opacity:1
+ },400);
+ },function(){
+ if($(this).hasClass("scan")){
+ $(".scan_ewm").stop().animate({right:"75px",opacity:0},200).hide();
+ }
+ $descSide.stop().animate({
+ left:$(this).offset().left - $descSide.width()-30,
+ opacity:0
+ },200).hide();
+ });
+ rightSlider();
+
+ $(window).scroll(function() {
+ if ($descSide.height()) {
+ var hoverIcon = $descSide.data('_dom')
+ $descSide.css('top', $(hoverIcon).offset().top)
+ }
+ })
+}
+
+class SiderBar extends Component {
+ constructor(props) {
+ super(props)
+
+ }
+
+ componentDidMount() {
+ _initSider();
+
+ }
+
+ render() {
+
+ // console.log(this.props)
+ return (
+
+
+ {this.props.mygetHelmetapi&&this.props.mygetHelmetapi.main_site===true?
+
+
+
+
+
+
+
+
+
+
+
+
+
微信扫一扫
+
关注公众号
+
+
+
+
+
+
+
:""}
+
+
+
+ );
+ }
+}
+
+export default SiderBar;
diff --git a/public/react/src/tpm/TPMBanner.js b/public/react/src/tpm/TPMBanner.js
new file mode 100644
index 000000000..b660001c6
--- /dev/null
+++ b/public/react/src/tpm/TPMBanner.js
@@ -0,0 +1,1056 @@
+import React, { Component } from 'react';
+
+import { Redirect } from 'react-router';
+
+import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
+
+import PropTypes from 'prop-types';
+
+import { Rating ,Progress} from "@icedesign/base";
+
+import {Modal,Input,Radio,Pagination,message,Spin,Icon,Tooltip,Rate} from 'antd';
+
+import AccountProfile from"../user/AccountProfile";
+
+import 'antd/lib/pagination/style/index.css';
+
+import axios from 'axios'
+
+import Modals from '../modals/Modals';
+
+import './shixuns/css/TPMBanner.css';
+
+let $ = window.$;
+
+const Search = Input.Search;
+
+const RadioGroup = Radio.Group;
+
+class TPMBanner extends Component {
+ constructor(props) {
+ super(props)
+ this.state={
+ Forkvisible: false,
+ Senttothetype:false,
+ Senttothevcalue:undefined,
+ courses_count:1,
+ course_list:[],
+ pagenum:1,
+ publishbox:"",
+ publishboxstatus:0,
+ pages:1,
+ Issuevisible:false,
+ evaluation_set_position:[],
+ tag_position:[],
+ Forkauthentication:false,
+ can_fork:undefined,
+ certi_url:undefined,
+ showradios:false,
+ startbtn:false,
+ Searchvalue:"",
+ startshixunCombattype:false,
+ shixunsmessage:"",
+ shixunsreplace:false,
+ hidestartshixunsreplacevalue:"",
+ isIE:false,
+ Forkvisibletype: false,
+ isSpin:false,
+ Senttothevcaluetype:false
+ }
+ }
+
+ // star_info:[0, 0, 0, 0, 0, 0],
+ // star_infos:[0, 0, 0, 0, 0, 0],
+ // shixunsDetails:{},
+ // shixunId: undefined,
+ // componentWillReceiveProps(newProps, newContext){
+ // this.setState({
+ // shixunsDetails: newProps.shixunsDetails
+ // });
+ // }
+
+ IEVersion=()=>{
+ var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
+ var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1; //判断是否IE<11浏览器
+ var isEdge = userAgent.indexOf("Edge") > -1 && !isIE; //判断是否IE的Edge浏览器
+ var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1;
+ if(isIE) {
+ var reIE = new RegExp("MSIE (\\d+\\.\\d+);");
+ reIE.test(userAgent);
+ var fIEVersion = parseFloat(RegExp["$1"]);
+ if(fIEVersion == 7) {
+ return 7;
+ } else if(fIEVersion == 8) {
+ return 8;
+ } else if(fIEVersion == 9) {
+ return 9;
+ } else if(fIEVersion == 10) {
+ return 10;
+ } else {
+ return 6;//IE版本<=7
+ }
+ } else if(isEdge) {
+ return 'edge';//edge
+ } else if(isIE11) {
+ return 11; //IE11
+ }else{
+ return -1;//不是ie浏览器
+ }
+ }
+ componentDidMount() {
+ let thiisie=this.IEVersion();
+ if(thiisie!=-1){
+ this.setState({
+ isIE:true
+ })
+ }else{
+ this.setState({
+ isIE:false
+ })
+ }
+ }
+ /*
+ * Fork
+ * */
+ copyForkvisible = () => {
+ let {shixunsDetails} = this.props;
+ if (shixunsDetails.can_fork === null) {
+ this.setState({
+ Forkvisible: true
+ })
+ } else {
+ this.setState({
+ Forkvisible: false,
+ Forkauthentication: true,
+ can_fork: shixunsDetails.can_fork.can_fork,
+ certi_url: shixunsDetails.can_fork.certi_url,
+ })
+ }
+
+ }
+
+ hideForkvisible = () => {
+ this.setState({
+ Forkvisible: false,
+ Forkauthentication:false
+ })
+ }
+
+ addForkvisible = () => {
+ this.setState({
+ Forkvisibletype: true,
+ })
+ let id = this.props.match.params.shixunId;
+ let url = "/shixuns/" + id + "/copy.json";
+ axios.post(url).then((response) => {
+ if(response.data.status===401){
+
+ }else{
+ this.setState({
+ Forkvisible: false,
+ Forkauthentication: false,
+ // Forkvisibletype:false
+ })
+ window.location.href = "/shixuns/" + response.data.shixun + "/challenges";
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ });
+
+ }
+ /*
+ * 发送至按钮
+ * */
+ Senttothe=()=>{
+ if(this.props.checkIfLogin()===false){
+ this.props.showLoginDialog()
+ return
+ }
+
+ // if(this.props.checkIfProfileCompleted()===false){
+ // this.setState({
+ // AccountProfiletype:true
+ // })
+ // return
+ // }
+ //
+ // if(this.props.checkIfProfessionalCertification()===false){
+ // this.setState({
+ // AccountProfiletype:true
+ // })
+ // return
+ // }
+ let id = this.props.match.params.shixunId;
+ let url="/shixuns/" + id +"/search_user_courses.json";
+ this.setState({
+ Senttothetype:true
+ })
+
+ axios.get(url, {
+ params: {
+ page:1,
+ limit:10
+ }}).then((response) => {
+ this.setState({
+ courses_count:response.data.courses_count,
+ course_list:response.data.course_list
+ })
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ SenttotheSearch=(value)=>{
+ let id = this.props.match.params.shixunId;
+ let url="/shixuns/" + id +"/search_user_courses.json?search="+value;
+ axios.get(encodeURI(url), {
+ params: {
+ page:1,
+ limit:10
+ }}).then((response) => {
+ this.setState({
+ courses_count:response.data.courses_count,
+ course_list:response.data.course_list,
+ pages:1,
+ Searchvalue:value
+ })
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ onChangeSenttothevcalue=(e)=>{
+ this.setState({
+ Senttothevcalue:e.target.value
+ })
+ }
+ onChangesendeSenttothe=(pageNumber)=>{
+ let{Searchvalue}=this.state;
+ let id = this.props.match.params.shixunId;
+ let url="/shixuns/" + id +"/search_user_courses.json?search="+Searchvalue;
+ axios.get(url, {
+ params: {
+ page:pageNumber,
+ limit:10
+ }}).then((response) => {
+ this.setState({
+ courses_count:response.data.courses_count,
+ course_list:response.data.course_list,
+ pagenum: pageNumber,
+ pages: pageNumber
+ })
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+ sendeSenttothevcalue=()=>{
+
+ let {Senttothevcalue}=this.state;
+
+ if(Senttothevcalue===undefined){
+ this.setState({
+ Senttothevcaluetype:true
+ })
+ return
+ }
+ let id = this.props.match.params.shixunId;
+ let url="/shixuns/" + id +"/send_to_course.json";
+ axios.post(url,{
+ course_id:Senttothevcalue
+ }).then((response) => {
+
+ this.props.showSnackbar(response.data.message);
+ this.setState({
+ Senttothetype:false,
+ Searchvalue:"",
+ pages:1
+ })
+ // window.location.href = response.data.url;
+ // response.data.course_id
+ this.props.history.replace(response.data.first_category_url);
+
+ }).catch((error) => {
+ console.log(error)
+ });
+
+ }
+
+ hideSenttothevcalue=()=>{
+ this.setState({
+ Senttothetype:false,
+ Searchvalue:"",
+ pages:1
+ })
+
+
+ }
+
+ /*
+ * 撤销发布按钮
+ * */
+
+ ModalCancel=()=>{
+ this.setState({
+ Modalstype:false
+ })
+ }
+ ModalSave=()=>{
+ let id = this.props.match.params.shixunId;
+ let url="/shixuns/" + id +"/cancel_publish.json";
+ axios.get(url).then((response) => {
+ this.props.showSnackbar(response.data.message);
+ window.location.reload()
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+ cancel_publish=()=>{
+ this.setState({
+ Modalstype:true,
+ Modalstopval:"是否确认撤销发布?",
+ ModalCancel:this.ModalCancel,
+ ModalSave:this.ModalSave,
+ })
+ }
+
+
+ /*
+ * 申请发布按钮
+ * */
+ applyrelease=()=>{
+ let id = this.props.match.params.shixunId;
+ let url="/shixuns/" + id +"/publish.json";
+ axios.get(url).then((response) => {
+ let evaluation_set_position
+ if(response.data.evaluation_set_position===null){
+ evaluation_set_position=[]
+ }else{
+ evaluation_set_position=response.data.evaluation_set_position
+ }
+ this.setState({
+ Issuevisible:true,
+ tag_position:response.data.tag_position,
+ evaluation_set_position:evaluation_set_position,
+ publishboxstatus:response.data.status,
+ })
+ }).catch((error) => {
+ console.log(error)
+ });
+ };
+
+ hiddenIssuevisible=(val)=>{
+ this.setState({
+ Issuevisible:false
+ })
+ if(val===0||val===1){
+ window.location.reload()
+ }
+
+ }
+
+ //重置按钮
+ // resetshixunCombat=(id)=>{
+ // let zrl="/myshixuns/"+id+"/reset_my_game.json";
+ // axios.get(zrl).then((response) => {
+ // window.location.href = "/shixuns/" + response.data.shixun_identifier + "/challenges";
+ // message.success('重置成功');
+ // }).catch((error) => {
+ // console.log(error)
+ // });
+ // }
+
+ // reset_my_game
+ hidestartshixunsreplace=(url)=>{
+ this.setState({
+ isSpin:true,
+ })
+ axios.get(url).then((response) => {
+ if(response.status===200){
+ // let path="/shixuns/"+response.data.shixun_identifier+"/challenges";
+ // this.props.history.push(path);
+ message.success('重置成功,正在进入实训!');
+ this.startshixunCombat(response.data.shixun_identifier, 1);
+ this.setState({
+ shixunsreplace:false,
+ isSpin:false,
+ })
+
+ // message.success('重置成功,正在进入实训!');
+ // this.startshixunCombat();
+ }}
+ ).catch((error) => {
+ this.setState({
+ startbtn:false,
+ shixunsreplace:false,
+ isSpin:false
+ })
+ });
+
+ }
+
+
+ //开始实战按钮
+ startshixunCombat=(id, reset)=>{
+
+ if(this.props.checkIfLogin()===false){
+ this.props.showLoginDialog()
+ return
+ }
+
+ if(this.props.checkIfProfileCompleted()===false){
+ this.setState({
+ AccountProfiletype:true
+ })
+ return
+ }
+
+ // if(this.props.checkIfProfessionalCertification()===false){
+ // this.setState({
+ // AccountProfiletype:true
+ // })
+ // return
+ // }
+
+ let {shixunsDetails} = this.props
+ if( shixunsDetails.shixun_status>1){
+ this.setState({
+ startbtn:true,
+ hidestartshixunsreplacevalue:""
+ })
+ }else{
+ this.setState({
+ hidestartshixunsreplacevalue:""
+ })
+ }
+
+
+ let url="/shixuns/"+id+"/shixun_exec.json" ;
+ if (reset) {
+ url += '?reset=' + reset
+ }
+ axios.get(url).then((response) => {
+ if(response.status===200){
+ if(response.data.status===-2){
+ // this.resetshixunCombat(response.data.message);
+ this.setState({
+ startbtn:false,
+ shixunsreplace:true,
+ hidestartshixunsreplacevalue:response.data.message+".json"
+ })
+ // this.shixunexec(response.data.message+".json")
+ }else if(response.data.status===-1){
+ console.log(response)
+ }else if(response.data.status===-3){
+ this.setState({
+ shixunsmessage:response.data.message,
+ startshixunCombattype:true,
+ startbtn:false
+ })
+ }else{
+ // let path="/tasks/"+response.data.game_identifier;
+ // this.props.history.push(path);
+
+
+ // this.context.router.history.push(path);
+ if(response.data.status!=401){
+ window.location.href = "/tasks/"+response.data.game_identifier;
+ }
+
+ }
+ }
+ }).catch((error) => {
+ this.setState({
+ startbtn:false
+ })
+ });
+ }
+
+ tocertification=()=>{
+ let{certi_url}=this.state;
+ this.setState({
+ Forkauthentication:false
+ })
+ window.location.href=certi_url;
+ }
+
+ SenttotheValue=(e)=>{
+ this.setState({
+ Searchvalue:e.target.value
+ })
+ }
+
+ hidestartshixunCombattype=()=>{
+ this.setState({
+ startshixunCombattype:false
+ })
+ }
+
+ hideAccountProfile=()=>{
+ this.setState({
+ AccountProfiletype:false
+ })
+ }
+
+
+ showonMouseOver=()=>{
+ $("#ratePanel").show();
+ this.setState({
+ showradios:true
+ })
+ }
+
+ hideonMouseOut=()=>{
+ $("#ratePanel").hide();
+ this.setState({
+ showradios:false
+ })
+ }
+
+ render() {
+ let {
+ Forkvisible,
+ Senttothetype,
+ Senttothevcalue,
+ evaluation_set_position,
+ Forkauthentication,
+ can_fork,
+ certi_url,
+ tag_position,
+ courses_count,
+ course_list,
+ Issuevisible,
+ publishboxstatus,
+ showradios,
+ startbtn,
+ Searchvalue,
+ startshixunCombattype,
+ shixunsmessage,
+ pages,
+ shixunsreplace,
+ hidestartshixunsreplacevalue,
+ Forkvisibletype,
+ AccountProfiletype,
+ isIE} = this.state;
+ let {shixunsDetails, shixunId, star_info, star_infos} = this.props;
+ let challengeBtnTipText = '';
+ let challengeBtnText = '模拟实战';
+ // let star_info=[]
+ // if (shixunsDetails.status === 0) {
+ //
+ // } else if (shixunsDetails.status === 1) {
+ //
+ // } else if (shixunsDetails.status === 2) {
+ // challengeBtnTipText = '开始学习并完成实战任务'
+ //
+ // }
+ if(shixunsDetails!=undefined){
+ if (shixunsDetails.shixun_status === 0 ) {
+ challengeBtnText = '继续实战'
+ } else if (shixunsDetails.shixun_status === 1) {
+ challengeBtnText = '查看实战'
+ } else if (shixunsDetails.shixun_status === 3) {
+ challengeBtnText = '继续实战'
+ }else{
+ challengeBtnText = "开始实战"
+ }
+ }
+
+
+ // let list=shixunsDetails.task_operation;
+ // if(list!=undefined){
+ // if (shixunsDetails.status === 0 ) {
+ // for(var i=0; i;
+ const MyRate = ({ defaultValue, ...rest }) => {
+ let myValue = defaultValue;
+ // console.log(myValue-Math.floor(myValue))
+ // if (myValue < Math.ceil(myValue)) {
+ // myValue = Math.floor(myValue) + 0.5;
+ // }
+
+ return ;
+ };
+ return (
+
+ shixunsDetails===undefined?"":
+
+
+
+ {AccountProfiletype===true?
this.hideAccountProfile()}
+ {...this.props}
+ {...this.state}
+ />:""}
+
+
+ {this.state.Modalstype===true?:""}
+
+
+
+ {shixunsDetails.name}
+ {
+ shixunsDetails.fork_from === undefined || shixunsDetails.fork_from === null ? "" :
+
+
+
+ }
+
+
+
+ {/**/}
+
+ -
+ 学习人数
+ {shixunsDetails.stu_num}
+
+ {/*- */}
+ {/*经验值*/}
+ {/*{shixunsDetails.experience}*/}
+ {/*
*/}
+ -
+ 难度系数
+ {shixunsDetails.diffcult}
+
+
+
+
+
+
+ {
+ startbtn === false && shixunsDetails.shixun_status != -1 ?
+
+ this.startshixunCombat(this.props.match.params.shixunId)}
+ className="fr user_default_btn task-btn-orange font-18"
+ id="shixun_operation" data-remote="true"
+ >
+ {shixunsDetails.task_operation === undefined ? "" : shixunsDetails.shixun_status > 1 ? shixunsDetails.task_operation[0] : "模拟实战"}
+
+
+ : ""
+ }
+
+
+
+
目前该实训项目尚在内测中,将于{shixunsmessage}之后开放,谢谢!
+
+
+ {/**/}
+ {/*知道了*/}
+ {/*
*/}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ startbtn === true ?
+
开启中 : ""
+ }
+
+ {/*{*/}
+ {/*shixunsDetails.status=== 3 && shixunsDetails.task_operation[0]==="开始实战"?*/}
+ {/*
{shixunsDetails.task_operation===undefined?"":shixunsDetails.task_operation[0]}:""*/}
+ {/*}*/}
+
+ {shixunsDetails.shixun_status === 0 && this.props.identity < 5 ?
+
申请发布 : ""
+ }
+
+
+ {
+ publishboxstatus === 0 ?
+
+ 发布申请已提交,请等待管理员的审核
+
+
: publishboxstatus === 1 ?
+
+
+ 发布申请已提交,请等待管理员的审核
+ • 我们将在1-2个工作日内完成审核
+
+
: publishboxstatus === 2 ?
+
+ 第
+ {
+ evaluation_set_position.map((item, key) => {
+ return (
+ {item},
+ )
+ })
+ }
+ 关评测设置尚未完成,无法申请发布
+
+
: publishboxstatus === 3 ?
+
+
+ 每一个关卡至少需要一个技能标签
+ 第
+ {
+ tag_position.map((item, key) => {
+ return (
+ {item},
+ )
+ })
+ }
+ 关尚未设置技能标签,请补充
+
+
:
+
+ }
+
+
+
+
+ {shixunsDetails.shixun_status === 1 && this.props.identity < 5 ?
+
撤销发布 : ""
+ }
+
+ {
+
+
+ 发送至
+
+
+ }
+
+
+
+
+
+
+ 选择的实训将会发送到指定课堂
+
+
+
+ this.SenttotheSearch(value)}
+ style={{width: '100%'}}
+ />
+
+
+
+
12?"cdefault ":"cdefault "}>
+
+
+
+ {
+ course_list === undefined ? "" : course_list.map((item, key) => {
+ return (
+ {item.name}
+ )
+ })
+ }
+
+
+
+
+ {this.state.Senttothevcaluetype===true?
请选择你要发送的课堂
:""}
+
12 ? "block" : "none"}}>
+
+
+
+
+
+
+
+
+
+ {shixunsDetails.shixun_status === 3 &&
+
已关闭
+ }
+
+ {shixunsDetails.shixun_status === -1 &&
+
已删除
+ }
+
+
+ {this.props.identity < 8&&shixunsDetails.shixun_status != -1 ?
+
+
+ Fork
+
+
+
+
+ {Forkvisibletype===true?
+
+ :
+
+
复制将在后台执行,平台将为你创建
一个新的同名实训和内容,请问是否继续?
+
+
+
+ }
+
+
+
+
+
+
+
+
+ {!!shixunsDetails.fork_num &&
+
+ {shixunsDetails.fork_num}
+
+ }
+
+
:""}
+
+
+
+
+
+
+
正在等待管理员的审核。在审核通过前,可以随时撤销发布
+
+
+ );
+ }
+}
+
+export default TPMBanner;
+
diff --git a/public/react/src/tpm/TPMChallenge.js b/public/react/src/tpm/TPMChallenge.js
new file mode 100644
index 000000000..847e8b965
--- /dev/null
+++ b/public/react/src/tpm/TPMChallenge.js
@@ -0,0 +1,54 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import PropTypes from 'prop-types';
+
+import { CircularProgress } from 'material-ui/Progress';
+
+import './TPMShixunDiscuss.css'
+
+import Challenges from './shixunchild/Challenges/Challenges'
+
+import TPMRightSection from './component/TPMRightSection'
+
+import TPMNav from './component/TPMNav'
+
+class TPMChallenge extends Component {
+ constructor(props) {
+ super(props)
+
+ }
+
+ render() {
+ const { loadingContent, shixun, user, match
+ } = this.props;
+ return (
+
+
+
+
+ );
+ }
+}
+
+export default TPMChallenge;
diff --git a/public/react/src/tpm/TPMChallengeContainer.js b/public/react/src/tpm/TPMChallengeContainer.js
new file mode 100644
index 000000000..a7c3c8a2b
--- /dev/null
+++ b/public/react/src/tpm/TPMChallengeContainer.js
@@ -0,0 +1,34 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+import TPMChallenge from './TPMChallenge';
+class TPMChallengeContainer extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ tpmLoading: true,
+ creator: {
+ owner_id: '',
+ }
+ }
+ }
+
+ render() {
+ const { tpmLoading } = this.props;
+ const user = this.props.current_user;
+
+ return (
+
+
+ { tpmLoading ? :
+
+
+ }
+
+
+ );
+ }
+}
+
+export default TPMChallengeContainer;
diff --git a/public/react/src/tpm/TPMCollaborators.js b/public/react/src/tpm/TPMCollaborators.js
new file mode 100644
index 000000000..cfab39ca5
--- /dev/null
+++ b/public/react/src/tpm/TPMCollaborators.js
@@ -0,0 +1,53 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import PropTypes from 'prop-types';
+
+import { CircularProgress } from 'material-ui/Progress';
+
+import './TPMShixunDiscuss.css'
+
+import Collaborators from './shixunchild/Collaborators/Collaborators'
+import TPMRightSection from './component/TPMRightSection'
+import TPMNav from './component/TPMNav'
+
+class TPMCollaborators extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+
+ render() {
+ const { loadingContent, creator, shixun, myshixun, recommend_shixuns, current_user, watched,
+ aboutFocus, user, match
+ } = this.props;
+ return (
+
+
+
+
+ );
+ }
+}
+
+export default TPMCollaborators;
diff --git a/public/react/src/tpm/TPMCollaboratorsContainer.js b/public/react/src/tpm/TPMCollaboratorsContainer.js
new file mode 100644
index 000000000..80049cee9
--- /dev/null
+++ b/public/react/src/tpm/TPMCollaboratorsContainer.js
@@ -0,0 +1,47 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import PropTypes from 'prop-types';
+
+import TPMCollaborators from './TPMCollaborators'
+
+import axios from 'axios';
+
+class TPMChallengeContainer extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ }
+ }
+
+ componentWillReceiveProps(newProps, newContext) {
+
+ }
+
+ componentDidMount() {
+ // this.props.showShixun();
+ }
+
+
+
+ render() {
+ const { tpmLoading } = this.props;
+ const user = this.props.current_user;
+ return (
+
+ { tpmLoading ? :
+
+
+ }
+
+ );
+ }
+}
+
+export default TPMChallengeContainer;
diff --git a/public/react/src/tpm/TPMFork/TPMForklist.js b/public/react/src/tpm/TPMFork/TPMForklist.js
new file mode 100644
index 000000000..59d9d23b8
--- /dev/null
+++ b/public/react/src/tpm/TPMFork/TPMForklist.js
@@ -0,0 +1,213 @@
+import React, {Component} from 'react';
+
+import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Pagination,Tooltip,Spin} from 'antd';
+
+import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
+
+// import "antd/dist/antd.css";
+
+import { Rating } from "@icedesign/base";
+
+import axios from 'axios';
+
+import {getImageUrl, toPath, getUrl} from 'educoder'
+
+import './shixunCss/fork.css';
+
+let origin = getUrl();
+
+let path = getUrl("/editormd/lib/")
+
+const $ = window.$;
+
+let timeout;
+
+let currentValue;
+
+
+
+export default class TPMFork_listComponent extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ shixuns:undefined,
+ total_count:0,
+ shixunsID:undefined,
+ Forkvisible: true,
+ Forkcurrent: 1
+ }
+ }
+
+
+ componentDidMount() {
+ let id = this.props.match.params.shixunId;
+
+ let Url="/shixuns/"+id+"/fork_list.json";
+ axios.get(Url, {
+ params: {
+ page:1,
+ limit:8
+ }
+ }).then((response)=> {
+ this.setState({
+ shixunsID:id,
+ shixuns:response.data.shixuns,
+ total_count:response.data.total_count,
+ Forkvisible:false
+ })
+ }).catch((error)=>{
+ console.log(error)
+ });
+ }
+
+
+ TPMForkonChange=(pageNumber)=>{
+ let id = this.props.match.params.shixunId;
+ this.setState({
+ Forkvisible:true
+ })
+ let Url="/shixuns/"+id+"/fork_list.json";
+ axios.get(Url, {
+ params: {
+ page:pageNumber,
+ limit:8
+ }
+ }).then((response)=> {
+ this.setState({
+ shixunsID:id,
+ shixuns:response.data.shixuns,
+ total_count:response.data.total_count,
+ Forkvisible: false,
+ Forkcurrent: pageNumber
+ })
+ }).catch((error)=>{
+ console.log(error)
+ });
+ }
+ render() {
+
+ let {shixuns, total_count, shixunsID, Forkvisible, Forkcurrent} = this.state;
+
+ const MyRate = ({ defaultValue, ...rest }) => {
+ let myValue = defaultValue;
+ // console.log(myValue-Math.floor(myValue))
+ // if (myValue < Math.ceil(myValue)) {
+ // myValue = Math.floor(myValue) + 0.5;
+ // }
+
+ return ;
+ };
+ return (
+
+
+
+
+
+
+ {/*
*/}
+
+
+
+ { shixuns===undefined?" ":shixuns.map((item,key)=>{
+ return(
+
+
+
+
{item.tag_name}
+ {/*
}/)
*/}
+
+
+
+
})
+
非试用内容,需要授权
+
+
+
+
+
+
+
+
+
+ {item.name}
+
+
+
+
+
+
+
+ {item.score_info===null?"5分":item.score_info+"分"}
+
+
+
+
+
+
+ {item.challenges_count}
+
+
+
+ {/**/}
+ {/**/}
+ {/*{item.exp}*/}
+ {/**/}
+ {/**/}
+
+
+
+ {item.stu_num}
+
+
+
+
+ {item.level}
+
+
+
+
+ )
+ })
+ }
+
+
+ {/*{total_count}
*/}
+ 8 ? "block" : "none"}}>
+ {/*
+
+ {/**/}
+
+
+ )
+ }
+}
+
+
diff --git a/public/react/src/tpm/TPMFork/shixunCss/fork.css b/public/react/src/tpm/TPMFork/shixunCss/fork.css
new file mode 100644
index 000000000..8cd2b9304
--- /dev/null
+++ b/public/react/src/tpm/TPMFork/shixunCss/fork.css
@@ -0,0 +1,3 @@
+.ml105 {
+ margin-left: 15%;
+}
\ No newline at end of file
diff --git a/public/react/src/tpm/TPMFork/shixunCss/tag2.png b/public/react/src/tpm/TPMFork/shixunCss/tag2.png
new file mode 100644
index 0000000000000000000000000000000000000000..423d2f7e39a62908f164fd3315dcc03b82007541
GIT binary patch
literal 1170
zcmeAS@N?(olHy`uVBq!ia0vp^0zfRo!3HEV4DF?Wlw^r(L`iUdT1k0gQ7VIDN`6wR
zf@f}GdTLN=VoGJ<$y6H#24=O)kcg59UmvUF{9L_6kQ%*;+ybC(1_m4Zih{)C?9>v4
zq}24xJX@vryZ0+8WTx0Eg`4^s_!c;)W@LI)6{QAO`Gq7`WhYyvDB0U7*i={n4aiL`
zNmQuF&B-gas<2f8n`;GRgM{^!6u?SKvTcwn`Gt*5rG`3JMx70H<
zwX`rY(NQomFf`LQu+%p+(KRr%GO)BVFjRm7C7^9ZDQQ+gE^bh}fIM5JjFOT9D}DX)
z@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7^KE~&-IMVSR9nfZANAQKal
z@=Hr>m4GgVcpfZU!c9<|c-Qt`
+ { tpmLoading ? :
+
+
+ }
+
+ );
+ }
+}
+
+export default TPMRanking_listContainer;
diff --git a/public/react/src/tpm/TPMForklist.js b/public/react/src/tpm/TPMForklist.js
new file mode 100644
index 000000000..251821209
--- /dev/null
+++ b/public/react/src/tpm/TPMForklist.js
@@ -0,0 +1,63 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import PropTypes from 'prop-types';
+
+import { CircularProgress } from 'material-ui/Progress';
+
+import './TPMShixunDiscuss.css'
+
+import Shixunfork_list from './shixunchild/Shixunfork_list'
+import TPMRightSection from './component/TPMRightSection'
+import TPMNav from './component/TPMNav'
+
+class TPMForklist extends Component {
+ constructor(props) {
+ super(props)
+
+ }
+
+ componentWillReceiveProps(newProps, newContext) {
+
+ }
+
+ componentDidMount() {
+
+ }
+
+
+
+ render() {
+ const { loadingContent, creator, shixun, myshixun, recommend_shixuns, current_user, watched,
+ aboutFocus, user, match
+ } = this.props;
+
+ return (
+
+
+
+
+
+ { loadingContent ?
+ :
+
+
+ }
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+export default TPMForklist;
diff --git a/public/react/src/tpm/TPMIndex.css b/public/react/src/tpm/TPMIndex.css
new file mode 100644
index 000000000..bbec3d34d
--- /dev/null
+++ b/public/react/src/tpm/TPMIndex.css
@@ -0,0 +1,229 @@
+html{
+ height: 100%;
+ overflow: hidden;
+}
+body {
+ overflow: auto !important;
+ font-family: "Microsoft YaHei";
+}
+
+#root {
+ /* ie兼容性 */
+ position: relative;
+ min-height: 100%;
+}
+body>.-task-title {
+ opacity: 1 !important;
+}
+/*�����Ŵ�����·Ŵ�λ��*/
+#root .search-all {
+ width: 219px;
+}
+
+/*Header START*/
+.newHeader .logoimg {
+ margin-top: 16px;
+ float: left;
+ width: 97px;
+}
+.head-right i {
+ font-size: 20px;
+ float: none !important;
+}
+.headIcon, #header_keyword_search {
+ padding-top: 13px !important;
+}
+.search-icon {
+ height: 30px !important;
+}
+.search-icon i {
+ font-size: 20px;
+}
+#header_keyword_search i {
+ color: #4cacff;
+}
+.ant-select-selection--multiple{
+ padding-bottom: 0px!important;
+ padding-top:3px;
+}
+/* 先注释掉下面2个样式,这样写影响范围太广了,并不是所有的select都需要40px高 */
+/* .ant-select-selection--single{
+ height:40px!important;
+}
+.ant-select-selection__rendered{
+ line-height: 40px!important;
+} */
+.ant-select-selection--multiple .ant-select-selection__rendered>ul>li, .ant-select-selection--multiple>ul>li{
+ height: 25px!important;
+ line-height: 23px!important;
+ margin-bottom:3px;
+ margin-top:0px;
+}
+/*Main START*/
+
+
+.newContainer{
+ background: #fafafa!important;
+}
+
+.ant-modal-title{
+ font-size: 16px;
+ font-weight: bold !important;
+ color: #333;
+}
+
+.ant-modal-title{
+ text-align: center;
+}
+/*.ant-modal{*/
+ /*top:10rem !important;*/
+/*}*/
+
+@-moz-document url-prefix() {
+ .ant-radio-inner {
+ width: 17px !important;
+ height: 17px !important;
+ }
+}
+/* IE只能用padding,不能用上下居中 */
+.shixunDetail_top{
+ display: block!important;
+ padding-top: 48px;
+}
+.totalScore{
+ display: block!important;
+ padding-top: 28px;
+}
+.head-nav ul#header-nav li{
+ /*font-weight: 600;*/
+}
+
+/*.newFooter{*/
+ /*position: fixed !important;*/
+/*}*/
+
+.edu-menu-panel .edu-menu-listnew:hover .careersiconfont{
+ color: #000 !important;
+}
+
+
+.newHeader {
+ background: #24292D !important;
+ height: 60px !important;
+}
+
+
+/*-------------------个人主页:右侧提示区域--------------------------*/
+.-task-sidebar{position:fixed;width:40px;height:180px;right:0;bottom:30px;z-index: 10;}
+.-task-sidebar>div{height: 40px;line-height: 40px;box-sizing: border-box;width:40px;background:#4CACFF;color:#fff;font-size:20px;text-align:center;margin-bottom:5px;border-radius: 4px;}
+.-task-sidebar>div i{ color:#fff;}
+.-task-sidebar>div i:hover{color: #fff!important;}
+.gotop{background-color: rgba(208,207,207,0.5)!important;padding: 0px!important;}
+.-task-desc{background:#494949;width:90px;line-height: 36px;text-align: center;
+ position: absolute;color: #fff;font-size: 13px;z-index: 999999;opacity: 0;}
+.-task-desc div{position: absolute;top:10px;right: -7px;height: 13px;}
+.-task-desc div img{float: left}
+.-task-sidebar .scan_ewm{
+ position: absolute !important;
+ right: 45px !important;
+ bottom: 0px !important;
+ background-color: #494949 !important;
+ -webkit-box-sizing: border-box !important;
+ box-sizing: border-box !important;
+ font-size: 14px !important;
+ line-height: 16px !important;
+ display: none;
+ height: 213px !important;
+}
+.trangle_right{position: absolute;right: -5px;bottom: 15px;width: 0;height: 0px;border-top: 6px solid transparent;border-left: 5px solid #494949;border-bottom: 6px solid transparent}
+
+.HeaderSearch{
+ margin-top: 18px;
+ margin-right: 20px;
+}
+.HeaderSearch .ant-input-search .ant-input{
+ /*height:30px;*/
+ background: #373e3f !important;
+ border: 1px solid #373e3f !important;
+
+}
+.ant-input-search .ant-input-affix-wrapper{
+ border:transparent;
+}
+.ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled) {
+ /* 比较奇怪的需求,先注释掉了,如果需要启用,麻烦增加class限制,别影响别的地方的使用 */
+ /* border-color: transparent; */
+}
+
+.ant-input:focus {
+ /*border-color: transparent;*/
+ border-right-width: 1px !important;
+ outline: 0;
+ -webkit-box-shadow: 0 0 0 2px transparent;
+ box-shadow: 0 0 0 2px transparent;
+ border: 1px solid #d9d9d9;
+}
+
+.HeaderSearch .ant-input-search .ant-input::-webkit-input-placeholder{
+ color: #999;
+ font-size: 14px;
+}
+
+.HeaderSearch .ant-input-search .ant-input:-moz-placeholder {
+ color: #999;
+ font-size: 14px;
+}
+
+.HeaderSearch .ant-input-search .ant-input::-moz-placeholder{
+ color: #999;
+ font-size: 14px;
+}
+
+.HeaderSearch .ant-input-search .ant-input:-ms-input-placeholder{
+ color: #999;
+ font-size: 14px;
+}
+
+.HeaderSearch .ant-input-search .ant-input-suffix .anticon-search {
+ color: #999;
+}
+
+.HeaderSearch .ant-input-search .ant-input{
+ color: #fff;
+}
+
+.HeaderSearch .ant-input-search .ant-input-suffix{
+ background: transparent !important;
+}
+
+.roundedRectangles{
+ position: absolute;
+ top: 10px;
+ right: -22px;
+}
+
+.HeaderSearch{
+ width: 325px;
+ /*right: 20px;*/
+}
+.HeaderSearch .ant-input-search{
+ right: 20px;
+}
+.mainheighs{
+ height: 100%;
+ display: block;
+}
+
+.ml18a{
+ margin-left:18%;
+}
+
+.logoimg{
+ float: left;
+ min-width: 40px;
+ height:40px;
+}
+
+.headwith100b{
+ width: 100%;
+}
\ No newline at end of file
diff --git a/public/react/src/tpm/TPMIndex.js b/public/react/src/tpm/TPMIndex.js
new file mode 100644
index 000000000..9b3308e04
--- /dev/null
+++ b/public/react/src/tpm/TPMIndex.js
@@ -0,0 +1,416 @@
+import React, { Component } from 'react';
+
+import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
+
+import Loading from '../../Loading';
+
+import Loadable from 'react-loadable';
+
+import { TPMIndexHOC } from './TPMIndexHOC';
+
+import { SnackbarHOC } from 'educoder';
+
+import TPMBanner from './TPMBanner';
+
+import axios from 'axios';
+
+import TPMShixunDiscussContainer from './TPMShixunDiscussContainer';
+
+import TPMRepositoryComponent from './TPMRepositoryComponent';
+
+import TPMRepositoryCommits from './shixunchild/Repository/TPMRepositoryCommits';
+
+import TPMsettings from './TPMsettings/TPMsettings';
+
+import TPMChallengeComponent from './TPMChallengeContainer';
+import TPMPropaedeuticsComponent from './TPMPropaedeuticsComponent';
+import TPMRanking_listComponent from './TPMRanking_listContainer';
+import TPMCollaboratorsComponent from './TPMCollaboratorsContainer';
+import Audit_situationComponent from './Audit_situationComponent';
+
+import '../page/tpiPage.css'
+
+const $ = window.$
+//任务
+// const TPMChallengeComponent = Loadable({
+// loader: () => import('./TPMChallengeContainer'),
+// loading: Loading,
+// })
+
+//背景知识
+// const TPMPropaedeuticsComponent = Loadable({
+// loader: () => import('./TPMPropaedeuticsComponent'),
+// loading: Loading,
+// })
+
+//版本库
+// const TPMRepositoryComponent = Loadable({
+// loader: () => import('./TPMRepositoryComponent'),
+// loading: Loading,
+// })
+
+// const TPMRepositoryComponent = Loadable({
+// loader: () => import('./TPMRepositoryComponent'),
+// loading: Loading,
+// })
+
+//合作
+// const TPMCollaboratorsComponent = Loadable({
+// loader: () => import('./TPMCollaboratorsContainer'),
+// loading: Loading,
+// })
+
+
+//评论
+// const TPMShixunDiscussComponent = Loadable({
+// loader: () => import('./TPMShixunDiscussContainer'),
+// loading: Loading,
+// })
+
+//排行版
+// const TPMRanking_listComponent = Loadable({
+// loader: () => import('./TPMRanking_listContainer'),
+// loading: Loading,
+// })
+
+// //编辑实训
+// const TPMModifysettings = Loadable({
+// loader: () =>import('./modules/tpm/TPMsettings/TPMsettings'),
+// loading: Loading,
+// })
+
+//新建实训
+const TPMchallengesnew = Loadable({
+ loader: () => import('./challengesnew/TPMchallengesnew'),
+ loading: Loading,
+})
+
+//新建tab2
+const TPMevaluation = Loadable({
+ loader: () => import('./challengesnew/TPMevaluation'),
+ loading: Loading,
+})
+
+//新建tab3答案
+// const TPManswer = Loadable({
+// loader: () => import('./challengesnew/TPManswer'),
+// loading: Loading,
+// })
+const TPManswer = Loadable({
+ loader: () => import('./challengesnew/TPManswer2'),
+ loading: Loading,
+})
+
+//选择题
+const TPMquestion = Loadable({
+ loader: () => import('./challengesnew/TPMquestion'),
+ loading: Loading,
+})
+
+//fork列表
+const TPMFork_listComponent = Loadable({
+ loader: () => import('./TPMFork/TPMForklist'),
+ loading: Loading,
+})
+//背景知识修改
+const TPMUpdatepropaede = Loadable({
+ loader: () => import('./TPMUpdatepropaede/TPMUpdatepropaede'),
+ loading: Loading,
+})
+
+
+
+// 版本库添加文件
+const AddFile = Loadable({
+ loader: () => import('./shixunchild/Repository/RepositoryAddFile'),
+ loading: Loading,
+})
+
+const interceptorUrlArray = ['repository.json', 'commits.json', 'propaedeutics.json'
+ , 'challenges.json', 'discusses.json', 'ranking_list.json', 'collaborators.json']
+const cacheInterceptorUrlMap = {}
+class TPMIndex extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ loadingContent: false,
+ power: false,
+ shixunsDetails: {},
+ shixunId: undefined,
+ star_info: [0, 0, 0, 0, 0, 0],
+ star_infos: [0, 0, 0, 0, 0, 0],
+ identity:undefined,
+ TPMRightSectionData:undefined,
+ PropaedeuticsList: undefined,
+ }
+ }
+
+ componentDidMount = () => {
+
+ let id = this.props.match.params.shixunId;
+
+ // let collaborators = `/shixuns/` + id + `/propaedeutics.json`;
+ //
+ // axios.get(collaborators).then((response) => {
+ // if (response.status === 200) {
+ // if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+ //
+ // }else{
+ // this.setState({
+ // PropaedeuticsList: response.data,
+ // shixunId: id
+ // });
+ // }
+ //
+ // }
+ // }).catch((error) => {
+ // console.log(error)
+ // });
+
+ let Url = `/shixuns/` + id + `.json`;
+ axios.get(Url).then((response) => {
+ if (response.status === 200) {
+ document.title=response.data.name;
+ let newstar_info = [];
+ // let start1=
+ for (var i = 0; i < response.data.score_info.length; i++) {
+
+ if (i === 0) {
+ newstar_info.push(response.data.score_info[i])
+ } else {
+ newstar_info.push((response.data.score_info[i] / 100) * 5)
+ }
+ }
+ let newstar_infos = response.data.score_info;
+ this.setState({
+ shixunsDetails: response.data,
+ shixunId: id,
+ star_info: newstar_info,
+ star_infos: newstar_infos,
+ power: response.data.power,
+ identity: response.data.identity,
+ propaedeutics:response.data.propaedeutics,
+ status: response.data.shixun_status,
+ secret_repository: response.data.secret_repository,
+
+ });
+ }
+ }).catch((error) => {
+ this.setState({
+ shixunsDetails: undefined,
+ shixunId: undefined,
+ star_info: undefined,
+ star_infos: undefined,
+ power: undefined,
+ identity: undefined,
+ status: undefined,
+ propaedeutics:undefined
+ });
+ });
+
+ this.tpmContentRequestInterceptor = axios.interceptors.request.use((config) => {
+ let url = config.url;
+ // console.log('tpmContentRequestInterceptor:', url)
+ for ( let i = 0; i < interceptorUrlArray.length; i++ ) {
+ if (url.indexOf(interceptorUrlArray[i]) != -1) {
+ url = url.split('?')[0]
+ console.log('loadingContent, url:', url)
+
+ this.setState({ loadingContent: true })
+
+ cacheInterceptorUrlMap[url] = true
+ }
+ }
+ return config;
+ }, function (error) {
+ return Promise.reject(error);
+ });
+
+ // Add a response interceptor
+ this.tpmContentResponseInterceptor = axios.interceptors.response.use((response) => {
+ // console.log('loadingContent finished, url:', response.config.url)
+ // TODO 依赖了api这个前缀
+ let url = response.config.url.split('api')[1];
+ url = url.split('?')[0]
+ if (cacheInterceptorUrlMap[url]) {
+
+ this.setState({ loadingContent: false })
+ delete cacheInterceptorUrlMap[response.url]
+ }
+ return response;
+ }, function (error) {
+ // Do something with response error
+ return Promise.reject(error);
+ });
+
+
+ //右侧数据
+ let shixunsDetailsURL=`/shixuns/`+id+`/show_right.json`;
+ axios.get(shixunsDetailsURL).then((response)=> {
+ this.setState({
+ TPMRightSectionData: response.data
+ });
+ })
+
+ }
+ componentWillUnmount = () => {
+ axios.interceptors.request.eject(this.tpmContentRequestInterceptor);
+ this.tpmContentRequestInterceptor = null;
+ axios.interceptors.request.eject(this.tpmContentResponseInterceptor);
+ this.tpmContentResponseInterceptor = null;
+ }
+
+
+ setLoadingContent = (isLoadingContent) => {
+ this.setState({ loadingContent: isLoadingContent })
+ }
+
+ // TpmTPMBannertype(type){
+ //
+ // }
+
+ render() {
+ let url = window.location.href;
+ let flag = url.indexOf("add_file")>-1;
+ return (
+
+ {
+ !flag &&
+
+ }
+
+
+
+ ()
+ }>
+ ()
+ }>
+
+ ()
+ }>
+
+ ()
+ }>
+
+ ()
+ }>
+ ()
+ }>
+
+ {/* */}
+
+ ()
+ }>
+
+
+ ()
+ }>
+
+
+ {/* */}
+
+
+ (this.initForumState(data)}
+ setSearchValue={this.setSearchValue}
+ setHotLabelIndex={this.setHotLabelIndex}
+ />)
+ }>
+
+
+ ()
+ }>
+
+
+ ()
+ }>
+
+ ()
+ }>
+
+ ()
+ }>
+
+ ()
+ }>
+
+ {/*评测设置*/}
+ ()
+ }>
+
+
+ {/*参考答案*/}
+ ()
+ }>
+
+ {/*新建关卡*/}
+ ()
+ }>
+
+ {/*编辑关卡*/}
+ ()
+ }>
+
+ {/*新建选择题*/}
+ ()
+ }>
+
+ {/*修改选择题*/}
+ ()
+ }>
+
+ {/*修改选择题*/}
+ ()
+ }>
+
+ ()
+ }>
+
+
+ {/**/}
+
+
+
+ );
+ }
+}
+
+export default SnackbarHOC() (TPMIndexHOC ( TPMIndex ));
diff --git a/public/react/src/tpm/TPMIndexHOC.js b/public/react/src/tpm/TPMIndexHOC.js
new file mode 100644
index 000000000..451344a56
--- /dev/null
+++ b/public/react/src/tpm/TPMIndexHOC.js
@@ -0,0 +1,754 @@
+import React, { Component } from 'react';
+
+import PropTypes from 'prop-types';
+
+import NewHeader from './NewHeader'
+import NewFooter from './NewFooter'
+import SiderBar from './SiderBar'
+import { getUrl, downloadFile } from 'educoder'
+import axios from 'axios';
+import { Spin } from 'antd';
+import './TPMIndex.css';
+import LoginDialog from '../login/LoginDialog';
+import AccountProfile from '../user/AccountProfile';
+
+import Trialapplication from "../login/Trialapplication";
+// import "antd/dist/antd.css";
+// import '../../css/educoder/edu-common.css'
+// import '../../css/educoder/edu-all.css'
+// import '../../css/educoder/edu-main.css'
+
+const $ = window.$;
+const versionNum = '0001';
+// let _url_origin = getUrl()
+let _url_origin='';
+if(window.location.port === "3007"){
+ _url_origin="http://pre-newweb.educoder.net";
+}
+
+// let _url_origin=`https://www.educoder.net`;
+
+if (!window['indexHOCLoaded']) {
+ window.indexHOCLoaded = true;
+ //解决首屏加载问题
+
+ // $('head').append($('')
+ // .attr('href', `${_url_origin}/stylesheets/educoder/antd.min.css?1525440977`));
+ $('head').append($('')
+ .attr('href', `${_url_origin}/stylesheets/css/edu-common.css?8`));
+
+ $('head').append($('')
+ .attr('href', `${_url_origin}/stylesheets/educoder/edu-main.css?8`));
+
+ // index.html有加载
+ $('head').append($('')
+ .attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?8`));
+
+
+ // $('head').append($('')
+ // .attr('href', `${_url_origin}/stylesheets/educoder/css_min_all.css?1525440977`));
+ // 加timeout 为了覆盖掉antd的样式
+ // setTimeout(() => {
+ // $('head').append( $('')
+ // .attr('href', `${_url_origin}/stylesheets/css/edu-common.css?1525440977`) );
+
+ // $('head').append( $('')
+ // .attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?1525440977`) );
+ // $('head').append( $('')
+ // .attr('href', `${_url_origin}/stylesheets/educoder/edu-main.css?1525440977`) );
+ // }, 1000);
+
+ $("script").append('')
+ .attr('src', `${_url_origin}/javascripts/jquery-1.8.3-ui-1.9.2-ujs-2.0.3.js?_t=${versionNum}`);
+
+}
+ // `${_url_origin}/javascripts/jquery-1.8.3-ui-1.9.2-ujs-2.0.3.js?_t=${versionNum}`
+// TODO css加载完成后再打开页面,行为和tpm其他页面一致
+export function TPMIndexHOC(WrappedComponent) {
+ // 这里如果extends WrappedComponent 会出现 WrappedComponent mount twice的问题
+ return class II extends React.Component {
+ constructor(props) {
+ super(props)
+ window.$('#root').css('position', 'relative')
+
+ this.state = {
+ tpmLoading: true,
+ resLoading: true,
+ Headertop:undefined,
+ Footerdown:undefined,
+ coursedata: {},
+
+ isRender: false,
+ AccountProfiletype: false,
+
+ globalLoading: false,
+ dataquerys:{},
+ isloginCancel:undefined,
+ mygetHelmetapi: null,
+ }
+ }
+
+ // header里面需要有user
+ initCommonState(user) {
+ // 更新头像后,需要改变参数,不然会被图片缓存影响到 --> 后台已加 ?t=${new Date().getTime()
+ const newUser = Object.assign({}, {...user}, { image_url: `${user.image_url}`});
+ this.setState({
+ user: newUser,
+ current_user: newUser
+ })
+ }
+ showShixun = () => {
+ const { shixunId } = this.props.match.params
+ const url = `/api/v1/shixuns/${shixunId}/show_shixun`
+
+ this.setState({ tpmLoading: true })
+ axios.get(url,
+ {
+ withCredentials: true
+ }
+ ).then((response) => {
+ if (response.data && response.data.shixun) {
+ this.initCommonState(response.data.current_user)
+ response.data.tpmLoading = false;
+ this.setState(response.data);
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ })
+ }
+ aboutFocus = () => {
+ const { creator, watched } = this.state
+ /*http://localhost:3000/api/v1/users/155/watch?object_id=156&object_type=user*/
+
+ const focusUrl = `/api/v1/users/${creator.owner_id}/${watched ? 'unwatch' : 'watch'}?object_id=${creator.owner_id}&object_type=user`
+
+ axios.get(focusUrl,{
+ })
+ .then((response) => {
+ const status = response.data.status;
+ if(status == 1){
+ const new_author_info = Object.assign({}, creator)
+ this.setState({
+ watched: !watched
+ })
+ }
+ }).catch((error) => {
+ console.log(error)
+ })
+ }
+
+ keyupListener = (e) => {
+ if (e.key === "Escape") {
+ this.setState({ globalLoading: false })
+ }
+ }
+ componentWillUnmount() {
+ window.removeEventListener('keyup', this.keyupListener)
+ }
+
+ componentDidMount() {
+ // console.log("TPMIndexHOC========");
+ // console.log(this.props);
+ window.addEventListener('keyup', this.keyupListener)
+
+ if(this.props.match.path==="/"){
+ // document.title="创新源于实践";
+ }else if(this.props.match.path==="/403"){
+ document.title="你没有权限访问";
+ }else if(this.props.match.path==="/nopage"){
+ document.title="没有找到该页面";
+ }else if(this.props.match.path==="/shixuns"){
+ document.title="实训项目";
+ }else if(this.props.match.path==="/paths"){
+ document.title="实践课程";
+ }else if(this.props.match.path==="/courses"){
+ document.title="翻转课堂";
+ }
+
+
+ $.ajaxSetup({
+ cache: true
+ });
+
+ //帮助后台传参数
+ const query = this.props.location.search;
+ // const type = query.split('?chinaoocTimestamp=');
+ // console.log("Eduinforms12345");
+ // console.log(this.foo(query));
+ // console.log(JSON.stringify(this.foo(query)));
+ var dataqueryss={}
+ try {
+ var foqus=this.foo(query);
+ if(JSON.stringify(foqus) ==="{}"){
+ this.setState({
+ dataquerys:{},
+ });
+ }else{
+ this.setState({
+ dataquerys:foqus,
+ });
+ dataqueryss=foqus;
+ }
+ }catch (e) {
+ this.setState({
+ dataquerys:{},
+ })
+ }
+ this.fetchUsers(dataqueryss);
+
+ let url=`/users/get_navigation_info.json`;
+ axios.get(url, {
+
+ }).then((response) => {
+ // console.log("开始请求/get_navigation_info.json");
+ // console.log(response);
+ if(response!=undefined){
+ if(response.status===200){
+ this.setState({
+ Headertop:response.data.top,
+ Footerdown:response.data.down
+ })
+ }
+ }
+ });
+ ///请求定制化的信息
+ this.getAppdata();
+ }
+ /**
+ 课堂权限相关方法,暂时写这里了 ----------------------------------------START
+ ADMIN = 0 # 超级管理员
+ CREATOR = 1 # 课程创建者
+ PROFESSOR = 2 # 课程老师
+ ASSISTANT_PROFESSOR = 3 # 课程助教
+ STUDENT = 4 # 学生
+ NORMAL = 5 # 普通用户
+
+ v2
+ # 课程权限判断
+ ADMIN = 0 # 超级管理员
+ BUSINESS = 1 # 运营人员
+ CREATOR = 2 # 课程创建者 课堂管理员
+ PROFESSOR = 3 # 课程老师
+ ASSISTANT_PROFESSOR = 4 # 课程助教
+ STUDENT = 5 # 学生
+ NORMAL = 6 # 普通用户
+ Anonymous = 7 # 普未登录
+ */
+ //超管0
+ isSuperAdmin = () => {
+ // return false
+ return this.state.coursedata&&this.state.coursedata.course_identity === 0
+ }
+ isCourseAdmin = () => {
+ return this.state.coursedata&&this.state.coursedata.course_identity === 2
+ }
+ //超管、运维0-1
+ isClassManagement = () => {
+ return this.state.coursedata&&this.state.coursedata.course_identity < 2
+ }
+ //超管、运维、课堂管理0-2
+ isAdminOrCreator = () => {
+ return this.state.coursedata&&this.state.coursedata.course_identity < 3
+ }
+ //超管、运维、课堂管理、老师0-3
+ isAdminOrTeacher = () => {
+ return this.state.coursedata&&this.state.coursedata.course_identity < 4
+ }
+ // 超管、运维、课堂管理、老师、助教0-4
+ isAdmin = () => {
+ return this.state.coursedata&&this.state.coursedata.course_identity < 5
+ }
+ // 学生5
+ isStudent = () => {
+ return this.state.coursedata&&this.state.coursedata.course_identity === 5
+ }
+ // 超管、运维、课堂管理、老师、助教、学生0-5
+ isAdminOrStudent = () => {
+ return this.state.coursedata&&this.state.coursedata.course_identity <= 5
+ }
+ // 游客未登录/非课堂成员6>
+ isNotMember = () => {
+ return this.state.coursedata&&this.state.coursedata.course_identity >= 6
+ }
+ //课堂是否已结束
+ isCourseEnd = () => {
+ return this.state.current_user ? this.state.current_user.course_is_end : false
+ }
+
+ // setTrialapplication = ()=>{
+ // this.setState({
+ // isRenders:true
+ // })
+ //
+ // }
+
+ //获取数据为空的时候
+ gettablogourlnull = () => {
+ this.setState({
+ mygetHelmetapi: undefined
+ });
+ document.title = "EduCoder";
+ var link = document.createElement('link'),
+ oldLink = document.getElementById('dynamic-favicon');
+ link.id = 'dynamic-favicon';
+ link.rel = 'shortcut icon';
+ link.href = "/react/build/./favicon.ico";
+ if (oldLink) {
+ document.head.removeChild(oldLink);
+ }
+ document.head.appendChild(link);
+ };
+
+ //获取数据的时候
+ gettablogourldata = (response) => {
+ document.title = response.data.setting.name;
+ var link = document.createElement('link'),
+ oldLink = document.getElementById('dynamic-favicon');
+ link.id = 'dynamic-favicon';
+ link.rel = 'shortcut icon';
+ link.href = '/' + response.data.setting.tab_logo_url;
+ if (oldLink) {
+ document.head.removeChild(oldLink);
+ }
+ document.head.appendChild(link);
+ }
+ //获取当前定制信息
+ getAppdata = () => {
+ let url = "/setting.json";
+ axios.get(url).then((response) => {
+ // console.log("app.js开始请求/setting.json");
+ // console.log("获取当前定制信息");
+ if (response) {
+ if (response.data) {
+ this.setState({
+ mygetHelmetapi: response.data.setting
+ });
+ try {
+ if (response.data.setting.tab_logo_url) {
+ this.gettablogourldata(response);
+ } else {
+ this.gettablogourlnull();
+ }
+ } catch (e) {
+ this.gettablogourlnull();
+ }
+
+
+ } else {
+
+ this.gettablogourlnull();
+
+ }
+
+ } else {
+ this.gettablogourlnull();
+
+ }
+
+ }).catch((error) => {
+ this.gettablogourlnull();
+
+ });
+ };
+ /**
+ 课堂权限相关方法,暂时写这里了 ----------------------------------------END
+ */
+ fetchUser = () => {
+ let url = `/users/get_user_info.json`
+ let courseId;
+ let query = this.props.location.pathname;
+ const type = query.split('/');
+ if (type[1] == 'courses' && type[2]) {
+ courseId = parseInt(type[2])
+ // url += `?course_id=${courseId}`
+ }
+ var datay={};
+ if(JSON.stringify(this.state.dataquerys) ==="{}"){
+ datay={
+ course_id:isNaN(courseId)?undefined:courseId,
+ school:1
+ }
+ }else{
+ datay={
+ course_id:isNaN(courseId)?undefined:courseId,
+ school:1,
+ chinaoocTimestamp:this.state.dataquerys.chinaoocTimestamp,
+ websiteName:this.state.dataquerys.websiteName,
+ chinaoocKey:this.state.dataquerys.chinaoocKey,
+ }
+ }
+ axios.get(url,{params:
+ datay
+ },
+ {
+ // withCredentials: true
+ }
+ ).then((response) => {
+ /*
+ {
+ "username": "黄井泉",
+ "login": "Hjqreturn",
+ "user_id": 12,
+ "image_url": "avatar/User/12",
+ "admin": true,
+ "is_teacher": false,
+ "tidding_count": 0
+ }
+ */
+ if(response=== undefined){
+ return
+ }
+ if (response.data) {
+ this.initCommonState(response.data)
+ this.setState({
+ tpmLoading: false,
+ coursedata: {
+ course_identity: response.data.course_identity >= 0 ? response.data.course_identity : undefined,
+ course_public: response.data.course_public,
+ name: response.data.course_name,
+ userid:response.data.user_id
+ },
+
+ })
+
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ })
+ };
+ fetchUsers = (yslurlobject) => {
+ let url = `/users/get_user_info.json`
+ let courseId;
+ let query = this.props.location.pathname;
+ const type = query.split('/');
+ if (type[1] == 'courses' && type[2]) {
+ courseId = parseInt(type[2])
+ // url += `?course_id=${courseId}`
+ }
+ var datay={};
+ if(JSON.stringify(yslurlobject) ==="{}"){
+ datay={
+ course_id:isNaN(courseId)?undefined:courseId,
+ school:1
+ }
+ }else{
+ datay={
+ course_id:isNaN(courseId)?undefined:courseId,
+ school:1,
+ chinaoocTimestamp:yslurlobject.chinaoocTimestamp,
+ websiteName:yslurlobject.websiteName,
+ chinaoocKey:yslurlobject.chinaoocKey,
+ }
+ }
+ axios.get(url,{params:
+ datay
+ },
+ {
+ // withCredentials: true
+ }
+ ).then((response) => {
+ /*
+ {
+ "username": "黄井泉",
+ "login": "Hjqreturn",
+ "user_id": 12,
+ "image_url": "avatar/User/12",
+ "admin": true,
+ "is_teacher": false,
+ "tidding_count": 0
+ }
+ */
+ if(response=== undefined){
+ return
+ }
+ if (response.data) {
+ this.initCommonState(response.data)
+ this.setState({
+ tpmLoading: false,
+ coursedata: {
+ course_identity: response.data.course_identity >= 0 ? response.data.course_identity : undefined,
+ course_public: response.data.course_public,
+ name: response.data.course_name,
+ userid:response.data.user_id
+ },
+
+ })
+
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ })
+ };
+ //截取url 数据的
+ foo=(url)=> {
+ var json = {};
+ var regExp = /[\?\&](\w+)(=?)(\w*)/g;
+ var arr;
+ do {
+ arr = regExp.exec(url);
+ // console.log(arr); // arr = [完整的字符串, key, 等号或'', value或'']
+
+ if (arr) {
+ var key = arr[1];
+ var value = arr[3];
+ // arr[2] === ''时, value = undefined
+ if (!arr[2])
+ value = undefined;
+
+ json[key] = value;
+ }
+ } while (arr);
+
+ return json;
+ };
+ hideLoginDialog = () => {
+ this.setState({
+ isRender: false,
+ isloginCancel:undefined
+ })
+ }
+ showLoginDialog = () => {
+ this.setState({
+ isRender: true,
+ isloginCancel:"iscancel"
+ })
+ }
+ //验证登录是否成功方法
+ checkIfLogin = () => {
+ return this.state.current_user && this.state.current_user.login != ''
+ }
+
+ hideAccountProfile = () => {
+ this.setState({
+ AccountProfiletype: false
+ })
+ }
+ showProfileCompleteDialog = () => {
+ this.dialogObj = {}
+ this.setState({
+ AccountProfiletype: true
+ })
+ }
+ //验证是否完善资料
+ checkIfProfileCompleted = () => {
+ return this.state.current_user && this.state.current_user.profile_completed
+ }
+ showProfessionalCertificationDialog = () => {
+ this.dialogObj = {
+ content: '您需要去完成您的职业认证,才能使用此功能',
+ okText: '立即完成',
+ okHref: '/account/certification'
+ }
+ this.setState({
+ AccountProfiletype: true,
+ })
+ }
+ checkIfProfessionalCertification = () => {
+ return this.state.current_user && this.state.current_user.professional_certification
+ }
+
+
+ ShowOnlinePdf = (url) => {
+ return axios({
+ method:'get',
+ url:url,
+ responseType: 'arraybuffer',
+ }).then((result)=>{
+ var binaryData = [];
+ binaryData.push(result.data);
+ this.url =window.URL.createObjectURL(new Blob(binaryData, {type:"application/pdf"}));
+ window.open(this.url);
+ })
+ }
+ DownloadFileA=(title,url)=>{
+ let link = document.createElement('a');
+ document.body.appendChild(link);
+ link.href =url;
+ link.download = title;
+ //兼容火狐浏览器
+ let evt = document.createEvent("MouseEvents");
+ evt.initEvent("click", false, false);
+ link.dispatchEvent(evt);
+ document.body.removeChild(link);
+ }
+
+ DownloadOpenPdf=(type,url)=>{
+ type===true?window.open(url):window.location.href=url;
+ }
+ slowDownload = (url, tip) => {
+ this._gLoadingTip = tip || '正在生成文件,请稍后...';
+ this.setState({ globalLoading: true })
+ const fileUrl = url;
+ downloadFile({
+ url: fileUrl,
+ successCallback: (url) => {
+ this.setState({ globalLoading: false })
+ console.log('successCallback')
+ },
+ failCallback: (responseHtml, url) => {
+ this.setState({ globalLoading: false })
+ console.log('failCallback')
+ }
+ })
+ }
+ yslslowCheckresults =(tip) =>{
+ this._gLoadingTip = tip || '成绩计算中,请稍候...';
+ this.setState({ globalLoading: true })
+ }
+ yslslowCheckresultsNo =() =>{
+ this.setState({ globalLoading: false })
+ }
+
+ showGlobalLoading = (tip) => {
+ this._gLoadingTip = tip || '加载中,请稍后...';
+ this.setState({ globalLoading: true })
+ }
+ hideGlobalLoading = () => {
+ this.setState({ globalLoading: false })
+ }
+
+ MdifHasAnchorJustScorll=()=>{
+ //mdhash滚动
+ let anchor = decodeURI(this.props.location.hash).replace('#', '');
+ // 对应id的话, 滚动到相应位置
+ if (!!anchor) {
+ let anchorElement = document.getElementsByName(anchor);
+ if (anchorElement) {
+ if (anchorElement.length>0){
+ anchorElement[anchorElement.length-1].scrollIntoView();
+ }
+ }
+ }
+ }
+
+ render() {
+ let{Headertop,Footerdown, isRender, AccountProfiletype,mygetHelmetapi}=this.state;
+ const common = {
+ isSuperAdmin:this.isSuperAdmin,
+ isAdminOrCreator:this.isAdminOrCreator,
+ isClassManagement:this.isClassManagement,
+ isCourseAdmin:this.isCourseAdmin,
+
+ isAdmin: this.isAdmin,
+ isAdminOrTeacher: this.isAdminOrTeacher,
+ isStudent: this.isStudent,
+ isAdminOrStudent: this.isAdminOrStudent,
+ isNotMember: this.isNotMember,
+ isCourseEnd: this.isCourseEnd,
+
+ isUserid:this.state.coursedata&&this.state.coursedata.userid,
+ fetchUser: this.fetchUser,
+
+ showLoginDialog: this.showLoginDialog,
+ checkIfLogin: this.checkIfLogin,
+ showProfileCompleteDialog: this.showProfileCompleteDialog,
+ checkIfProfileCompleted: this.checkIfProfileCompleted,
+ checkIfProfessionalCertification: this.checkIfProfessionalCertification,
+ showProfessionalCertificationDialog: this.showProfessionalCertificationDialog,
+
+ ShowOnlinePdf:(url)=>this.ShowOnlinePdf(url),
+ DownloadFileA:(title,url)=>this.DownloadFileA(title,url),
+ DownloadOpenPdf:(type,url)=>this.DownloadOpenPdf(type,url),
+
+ slowDownload: this.slowDownload,
+ showGlobalLoading: this.showGlobalLoading,
+ hideGlobalLoading: this.hideGlobalLoading,
+ yslslowCheckresults:this.yslslowCheckresults,
+ yslslowCheckresultsNo:this.yslslowCheckresultsNo,
+ MdifHasAnchorJustScorll:this.MdifHasAnchorJustScorll
+
+ };
+ // console.log("this.props.mygetHelmetapi");
+ // console.log(this.props.mygetHelmetapi);
+ return (
+
+ {isRender===true ?
this.hideLoginDialog()}
+ {...this.props}
+ {...this.state}
+ /> : ""}
+ {/* AccountProfile 也用作职业认证 */}
+ {AccountProfiletype===true ? this.hideAccountProfile()}
+ {...this.props}
+ {...this.state}
+ {...this.dialogObj}
+ />:""}
+
+ {/* 注释掉了1440 影响到了手机屏幕的展示 */}
+
+
+
+
+
+
+ this.initCommonState(user)}
+ {...this.props} {...this.state}
+ showShixun={this.showShixun} aboutFocus={this.aboutFocus}
+ {...common}
+ >
+
+
+
+
+
+
+
+
+
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/react/src/tpm/TPMPropaedeutics.js b/public/react/src/tpm/TPMPropaedeutics.js
new file mode 100644
index 000000000..88a05fde7
--- /dev/null
+++ b/public/react/src/tpm/TPMPropaedeutics.js
@@ -0,0 +1,74 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import PropTypes from 'prop-types';
+
+import { CircularProgress } from 'material-ui/Progress';
+
+import './TPMShixunDiscuss.css'
+
+import Propaedeutics from './shixunchild/Propaedeutics/Propaedeu_tics'
+
+import TPMRightSection from './component/TPMRightSection'
+
+import TPMNav from './component/TPMNav'
+
+import axios from 'axios';
+
+class TPMPropaedeutics extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ shixunId: undefined
+ }
+ }
+
+ componentWillReceiveProps(newProps, newContext) {
+ }
+
+ componentDidMount() {
+
+
+ }
+
+
+ render() {
+ const { loadingContent, creator, shixun, myshixun, recommend_shixuns, current_user, watched,
+ aboutFocus, user, match
+ } = this.props;
+ //
+ return (
+
+
+
+
+ );
+ }
+}
+
+export default TPMPropaedeutics;
diff --git a/public/react/src/tpm/TPMPropaedeuticsComponent.js b/public/react/src/tpm/TPMPropaedeuticsComponent.js
new file mode 100644
index 000000000..7c3eadb89
--- /dev/null
+++ b/public/react/src/tpm/TPMPropaedeuticsComponent.js
@@ -0,0 +1,39 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import PropTypes from 'prop-types';
+
+import TPMPropaedeutics from './TPMPropaedeutics'
+
+import axios from 'axios';
+
+class TPMPropaedeuticsComponent extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ // tpmLoading: true,
+ // creator: {
+ // owner_id: ''
+ // }
+ }
+ }
+
+ render() {
+ const { tpmLoading } = this.props;
+
+ return (
+
+ { tpmLoading ? :
+
+
+ }
+
+
+
+ );
+ }
+}
+
+export default TPMPropaedeuticsComponent ;
diff --git a/public/react/src/tpm/TPMRanking_list.js b/public/react/src/tpm/TPMRanking_list.js
new file mode 100644
index 000000000..7171692a7
--- /dev/null
+++ b/public/react/src/tpm/TPMRanking_list.js
@@ -0,0 +1,59 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import PropTypes from 'prop-types';
+
+import { CircularProgress } from 'material-ui/Progress';
+
+import './TPMShixunDiscuss.css'
+
+import Ranking_list from './shixunchild/Ranking_list/Ranking_list'
+import TPMRightSection from './component/TPMRightSection'
+import TPMNav from './component/TPMNav'
+
+class TPMRanking_list extends Component {
+ constructor(props) {
+ super(props)
+
+ }
+
+ render() {
+ const { loadingContent, creator, shixun, myshixun, recommend_shixuns, current_user, watched,
+ aboutFocus, user, match
+ } = this.props;
+
+ //
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+export default TPMRanking_list;
diff --git a/public/react/src/tpm/TPMRanking_listContainer.js b/public/react/src/tpm/TPMRanking_listContainer.js
new file mode 100644
index 000000000..98841b1ab
--- /dev/null
+++ b/public/react/src/tpm/TPMRanking_listContainer.js
@@ -0,0 +1,37 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import PropTypes from 'prop-types';
+
+import TPMRanking_list from './TPMRanking_list'
+
+import axios from 'axios';
+
+class TPMRanking_listContainer extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ }
+ }
+
+ render() {
+ const { tpmLoading } = this.props;
+ const user = this.props.current_user;
+
+ return (
+
+ { tpmLoading ? :
+
+
+ }
+
+ );
+ }
+}
+
+export default TPMRanking_listContainer;
diff --git a/public/react/src/tpm/TPMRepository.js b/public/react/src/tpm/TPMRepository.js
new file mode 100644
index 000000000..0f8e31258
--- /dev/null
+++ b/public/react/src/tpm/TPMRepository.js
@@ -0,0 +1,58 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import PropTypes from 'prop-types';
+
+import { CircularProgress } from 'material-ui/Progress';
+
+import './TPMShixunDiscuss.css'
+
+import Repository from './shixunchild/Repository/Repository'
+import TPMRightSection from './component/TPMRightSection'
+import TPMNav from './component/TPMNav'
+
+// import RepositoryChooseModal from './component/modal/RepositoryChooseModal'
+
+class TPMRepository extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+
+ render() {
+ const { loadingContent, creator, shixun, myshixun, recommend_shixuns, current_user, watched,
+ aboutFocus, user, match, isContentWidth100
+ } = this.props;
+
+ return (
+
+
+ {/* 可能会影响到其他页面的样式,需要测试、协商 */}
+
+
+ {/* */}
+ { loadingContent ?
+ :
+
+ }
+
+
+ { !isContentWidth100 &&
+
+
}
+
+
+
+ );
+ }
+}
+
+export default TPMRepository;
diff --git a/public/react/src/tpm/TPMRepositoryComponent.js b/public/react/src/tpm/TPMRepositoryComponent.js
new file mode 100644
index 000000000..027f3f705
--- /dev/null
+++ b/public/react/src/tpm/TPMRepositoryComponent.js
@@ -0,0 +1,229 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import PropTypes from 'prop-types';
+
+import TPMRepository from './TPMRepository'
+
+import axios from 'axios';
+
+import { trace_collapse, info } from 'educoder'
+
+import RepositoryCodeEditor from './shixunchild/Repository/RepositoryCodeEditor'
+
+
+class TPMRepositoryComponent extends Component {
+ constructor(props) {
+ super(props)
+ this.nameTypeMap = {}
+ let pathArray = []
+ var splitArray = window.location.pathname.split('shixun_show/');
+ if (splitArray[1]) {
+ pathArray = splitArray[1].split('/')
+ if (pathArray[pathArray.length - 1] == '') {
+ // 有可能是这么访问的: http://localhost:3007/shixuns/3ozvy5f8/repository/fsu7tkaw/master/shixun_show/src/
+ pathArray.length = pathArray.length - 1;
+ }
+ }
+ this.state = {
+ repositoryLoading: true,
+ pathArray: pathArray,
+ isContentWidth100: this._isFileInPathArray(pathArray)
+ }
+ }
+ componentDidUpdate(prevProps, prevState) {
+ if (this.props.secret_repository_tab != prevProps.secret_repository_tab) {
+ this.fetchRepo()
+ }
+ }
+
+
+ componentDidMount = () => {
+
+ this.fetchRepo()
+ }
+ setContentWidth100 = (flag) => {
+ const newFileContent = flag === false ? '' : this.state.fileContent
+ this.setState({
+ // isCodeFile
+ isContentWidth100: flag,
+ fileContent: newFileContent
+ })
+ }
+ saveCode = (content) => {
+ const path = this.state.pathArray.join('/')
+ let id = this.props.match.params.shixunId;
+ let url = `/shixuns/${id}/update_file.json`;
+ axios.post(url, {
+ path: path,
+ content
+ }).then((response) => {
+ if(response.status === 200){
+ this.setState({
+ fileContent: response.data.content,
+ repositoryLoading: false
+ });
+ }
+ trace_collapse('tpm save code res: ', response)
+ this.props.showSnackbar('文件保存成功')
+
+ }).catch((error)=>{
+ console.log(error)
+ });
+ }
+ fetchCode = (newPathArray) => {
+ const path = newPathArray.join('/')
+
+ // https://testeduplus2.educoder.net/shixuns/3ozvy5f8/file_content.json
+ this.setContentWidth100(true)
+ this.setState({ repositoryLoading: true, pathArray: newPathArray })
+ let id = this.props.match.params.shixunId;
+ let url = `/shixuns/${id}/file_content.json`;
+ axios.post(url, {
+ path: path,
+ secret_repository: this.props.secret_repository_tab
+ }).then((response) => {
+ trace_collapse('repository res: ', response)
+
+ if (response.data.status == -1) {
+ this.props.showSnackbar('无法找到对应的资源,请变更地址或联系管理员!')
+ return;
+ }
+ if(response.status === 200){
+ this.setState({
+ fileContent: response.data.content,
+ repositoryLoading: false
+ });
+ this.props.history
+ .replace(`${this.props.match.url}/master/shixun_show/${newPathArray.join('/')}`)
+ }
+
+ }).catch((error)=>{
+ this.props.showSnackbar('无法找到对应的资源,请变更地址或联系管理员!')
+ console.log(error)
+ });
+ }
+ _isFileName = (name) => {
+ return name.indexOf('.') !== -1
+ }
+ _isFileInPathArray = (array) => {
+ if (!array || array.length === 0) {
+ return false
+ }
+ return this.nameTypeMap[array[array.length - 1]] !== 'tree' && this._isFileName( array[array.length - 1] )
+ }
+ // listItem 如果是num,则是通过面包屑点击过来的,取pathArray的子集
+ fetchRepo = (listItem) => {
+ const { pathArray } = this.state;
+ let newPathArray = pathArray.slice(0)
+
+ if (listItem === 0 || listItem) {
+ this.setContentWidth100(false)
+ this.nameTypeMap[listItem.name] = listItem.type
+ if (typeof listItem == 'number') { // 参数是数字的话,做截取
+ // if (this._isFileName(newPathArray[listItem])) { // 面包屑中的文件不让点击了
+ // listItem--;
+ // }
+ newPathArray = newPathArray.slice(0, listItem)
+ } else if (listItem.type === 'tree') {
+ newPathArray.push(listItem.name)
+ } else if (listItem.type === 'blob') {
+ newPathArray.push(listItem.name)
+ this.setState({ pathArray: newPathArray })
+ this.fetchCode(newPathArray)
+ return;
+ }
+ }
+ // https://testeduplus2.educoder.net/shixuns/3ozvy5f8/repository.json
+ this.setState({ repositoryLoading: true, pathArray: newPathArray })
+ let urlNewPathArray = newPathArray;
+ let fileInPathArray = false;
+ if (newPathArray.length) {
+ fileInPathArray = this.nameTypeMap[newPathArray[newPathArray.length - 1]] ? this.nameTypeMap[newPathArray[newPathArray.length - 1]] !== 'tree'
+ : (listItem ? listItem.type !== 'tree' : this._isFileName( newPathArray[newPathArray.length - 1] ))
+ if ( fileInPathArray ) {
+ urlNewPathArray = newPathArray.slice(0, newPathArray.length - 1)
+ }
+ }
+ const path = urlNewPathArray.join('/')
+
+ let id = this.props.match.params.shixunId;
+ let url = `/shixuns/${id}/${this.props.secret_repository_tab ? 'secret_repository' : 'repository'}.json`;
+ // this.props.setLoadingContent(true)
+ axios.post(url, {
+ path: path ? path : ''
+ }).then((response) => {
+ // this.props.setLoadingContent(false)
+
+ const trees = response.data.trees
+ const treeIsFileMap = {}
+ if (!trees || !Array.isArray(trees)) {
+ // this.props.showSnackbar('无法找到对应的资源,请变更地址或联系管理员!')
+ // return;
+ } else {
+ trees.forEach(item => {
+ treeIsFileMap[item.name] = item.type == 'blob'
+ })
+ }
+ if(response.status === 200){
+ this.setState({
+ treeIsFileMap,
+ ...response.data,
+ repositoryLoading: false
+ });
+ this.props.history
+ .replace(`${this.props.match.url}` +
+ (newPathArray.length ? `/master/shixun_show/${newPathArray.join('/')}` : ''))
+ }
+
+ // 初始化时,repo接口完毕后需要看是否需要fetchCode
+ if (fileInPathArray) {
+ this.fetchCode(newPathArray)
+ }
+ // info(response)
+ trace_collapse('repository res: ', response)
+
+ }).catch((error)=>{
+ console.log(error)
+ });
+ }
+
+
+ render() {
+ const { isContentWidth100 } = this.state;
+
+ // 需要重构
+ return (
+
+ { !isContentWidth100 ?
+
+ :
+
+ {/* 可能会影响到其他页面的样式,需要测试、协商 */}
+
+
+
+
+ }
+
+
+
+
+ );
+ }
+}
+
+export default TPMRepositoryComponent ;
diff --git a/public/react/src/tpm/TPMShixunDiscuss.css b/public/react/src/tpm/TPMShixunDiscuss.css
new file mode 100644
index 000000000..3af4ec269
--- /dev/null
+++ b/public/react/src/tpm/TPMShixunDiscuss.css
@@ -0,0 +1,47 @@
+.tpmComment .-fit {
+ position: inherit;
+}
+.tpmComment .rc-pagination {
+ margin-left: auto;
+ margin-right: auto;
+ margin-top: 12px;
+ margin-bottom: 20px;
+}
+.tpmComment .paginationSection {
+ background: #FAFAFA;
+}
+.tpmComment .comment_item_cont.df.clearfix:nth-last-child(1) {
+ border-bottom: none;
+}
+
+/*.tpmComment .fl.edu-back-white {*/
+/*min-height: 600px;*/
+/*}*/
+
+
+.user_watch_btn {
+ cursor: pointer;
+}
+
+
+/*md编辑器*/
+.tpmComment .commentItemMDEditor a.task-btn {
+ background: #4cacff!important;
+ margin-right: 16px;
+ margin-top: 16px;
+}
+/* md编辑器 resizeBar*/
+ .tpmComment .commentItemMDEditor .editor__resize {
+ transform: translateX(-176%)
+}
+
+#ratePanel > div > div > div.fr div.rateYo.fl.mt3 {
+ height: 20px;
+ line-height: 20px;
+ cursor: default;
+ width: 110px;
+}
+
+.tpmComment .icon-jiangli {
+ /* margin-top: 2px; */
+}
\ No newline at end of file
diff --git a/public/react/src/tpm/TPMShixunDiscuss.js b/public/react/src/tpm/TPMShixunDiscuss.js
new file mode 100644
index 000000000..9350060cc
--- /dev/null
+++ b/public/react/src/tpm/TPMShixunDiscuss.js
@@ -0,0 +1,72 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import PropTypes from 'prop-types';
+
+import { CircularProgress } from 'material-ui/Progress';
+
+import './TPMShixunDiscuss.css'
+
+import ShixunDiscuss from './shixunchild/ShixunDiscuss/ShixunDiscuss'
+import TPMRightSection from './component/TPMRightSection'
+import TPMNav from './component/TPMNav'
+
+import Comments from '../comment/Comments'
+import { commentHOC } from '../comment/CommentsHOC'
+
+class TPMShixunDiscuss extends Component {
+ constructor(props) {
+ super(props)
+
+ }
+
+ componentWillReceiveProps(newProps, newContext) {
+ }
+
+ componentDidMount() {
+ // TODO 加了HOC后 mount了两次
+ this.props.fetchCommentIfNotFetched &&
+ this.props.fetchCommentIfNotFetched();
+ }
+
+ render() {
+ const { loadingContent, creator, shixun, myshixun, recommend_shixuns, current_user, watched,
+ aboutFocus, user, match
+ } = this.props;
+
+ return (
+
+
+
+
+
+ { loadingContent ?
+ :
+
+ // onPaginationChange={this.onPaginationChange}
+ //
+ }
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+export default commentHOC ( TPMShixunDiscuss );
diff --git a/public/react/src/tpm/TPMShixunDiscussContainer.js b/public/react/src/tpm/TPMShixunDiscussContainer.js
new file mode 100644
index 000000000..535840772
--- /dev/null
+++ b/public/react/src/tpm/TPMShixunDiscussContainer.js
@@ -0,0 +1,45 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import PropTypes from 'prop-types';
+
+import TPMShixunDiscuss from './TPMShixunDiscuss'
+
+import axios from 'axios';
+
+class TPMShixunDiscussContainer extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ }
+ }
+
+ componentWillReceiveProps(newProps, newContext) {
+
+ }
+
+ componentDidMount() {
+
+ }
+
+ render() {
+ const { tpmLoading } = this.props;
+ const user = this.props.current_user;
+ return (
+
+ { tpmLoading ? :
+
+
+ }
+
+ );
+ }
+}
+
+export default TPMShixunDiscussContainer;
diff --git a/public/react/src/tpm/TPMUpdatepropaede/TPMUpdatepropaede.js b/public/react/src/tpm/TPMUpdatepropaede/TPMUpdatepropaede.js
new file mode 100644
index 000000000..63872b133
--- /dev/null
+++ b/public/react/src/tpm/TPMUpdatepropaede/TPMUpdatepropaede.js
@@ -0,0 +1,100 @@
+import React, {Component} from 'react';
+
+import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal} from 'antd';
+
+import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
+
+import axios from 'axios';
+
+import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
+
+import {getUrl} from 'educoder';
+
+
+
+export default class TPMUpdatepropaede extends Component {
+ constructor(props) {
+ super(props)
+ this.neweditanswerRef=React.createRef();
+ this.state = {
+ shixunId:undefined,
+ }
+ }
+
+ componentDidMount() {
+ let id = this.props.match.params.shixunId;
+ let url="/shixuns/"+id+"/propaedeutics.json";
+ axios.get(url).then((response) => {
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else{
+ this.setState({
+ shixunId:id,
+ })
+ if(response.data.content[0]!=null){
+ this.setState({
+ editanswersRefval:response.data.content,
+ })
+ this.neweditanswerRef.current.setValue(response.data.content)
+ }else{
+ this.setState({
+ editanswersRefval:"",
+ })
+ this.neweditanswerRef.current.setValue('')
+ }
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+
+ }
+
+ updatepropaedeuticsvalue=()=>{
+ let id = this.props.match.params.shixunId;
+ let url="/shixuns/"+id+"/update_propaedeutics.json";
+ const update_propaedeuticsvalue = this.neweditanswerRef.current.getValue().trim();
+ axios.post(url,{
+ content:update_propaedeuticsvalue
+ }
+ ).then((response) => {
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else{
+ this.props.showSnackbar(response.data.message);
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+ render() {
+ let {shixunId} = this.state;
+ return (
+
+
+
+ )
+ }
+}
+
+
diff --git a/public/react/src/tpm/TPMsettings/TPMsettings.js b/public/react/src/tpm/TPMsettings/TPMsettings.js
new file mode 100644
index 000000000..7acaf98d6
--- /dev/null
+++ b/public/react/src/tpm/TPMsettings/TPMsettings.js
@@ -0,0 +1,2437 @@
+import React, { Component } from 'react';
+
+import MonacoEditor from 'react-monaco-editor';
+
+//MonacoDiffEditor 对比模式
+import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Icon,DatePicker,Breadcrumb,Upload,Button,notification, Tooltip} from 'antd';
+
+// import "antd/dist/antd.css";
+
+import locale from 'antd/lib/date-picker/locale/zh_CN';
+
+import moment from 'moment';
+
+import axios from 'axios';
+
+import './css/TPMsettings.css';
+
+import { getImageUrl, toPath, getUrl ,appendFileSizeToUploadFileAll, getUploadActionUrl} from 'educoder';
+
+let origin = getUrl();
+
+let path = getUrl("/editormd/lib/")
+
+const $ = window.$;
+
+let timeout;
+
+let currentValue;
+
+const Option = Select.Option;
+
+const RadioGroup = Radio.Group;
+const confirm = Modal.confirm;
+// 处理整点 半点
+// 取传入时间往后的第一个半点
+export function handleDateStrings(dateString) {
+ if (!dateString) return dateString;
+ const ar = dateString.split(':')
+ if (ar[1] == '00' || ar[1] == '30') {
+ return dateString
+ }
+ const miniute = parseInt(ar[1]);
+ if (miniute < 30 || miniute == 60) {
+ return [ar[0], '30'].join(':')
+ }
+ if (miniute < 60) {
+ // 加一个小时
+ const tempStr = [ar[0], '00'].join(':');
+ const format = "YYYY-MM-DD HH:mm";
+ const _moment = moment(tempStr, format)
+ _moment.add(1, 'hours')
+ return _moment.format(format)
+ }
+
+ return dateString
+}
+
+// 恢复数据
+function md_rec_data(k,mdu,id, editor){
+ if(window.sessionStorage.getItem(k+mdu) !== null){
+ editor.setValue(window.sessionStorage.getItem(k+mdu));
+ md_clear_data(k,mdu,id);
+ }
+}
+
+// 保存数据
+function md_add_data(k,mdu,d){
+ window.sessionStorage.setItem(k+mdu,d);
+}
+
+// 清空保存的数据
+function md_clear_data(k,mdu,id){
+ window.sessionStorage.removeItem(k+mdu);
+ var id1 = "#e_tip_"+id;
+ var id2 = "#e_tips_"+id;
+ if(k == 'content'){
+ $(id2).html("");
+ }else{
+ $(id1).html("");
+ }
+}
+
+function md_elocalStorage(editor,mdu,id){
+ if (window.sessionStorage){
+ var oc = window.sessionStorage.getItem('content'+mdu);
+ if(oc !== null ){
+ $("#e_tips_"+id).data('editor', editor);
+ var h = '您上次有已保存的数据,是否恢复 ? / 不恢复';
+ $("#e_tips_"+id).html(h);
+ }
+ setInterval(function() {
+ var d = new Date();
+ var h = d.getHours();
+ var m = d.getMinutes();
+ var s = d.getSeconds();
+ h = h < 10 ? '0' + h : h;
+ m = m < 10 ? '0' + m : m;
+ s = s < 10 ? '0' + s : s;
+ if(editor.getValue().trim() != ""){
+ md_add_data("content",mdu,editor.getValue());
+ var id1 = "#e_tip_"+id;
+ var id2 = "#e_tips_"+id;
+
+ $(id1).html(" 数据已于 " + h + ':' + m + ':' + s +" 保存 ");
+ $(id2).html("");
+ }
+ },10000);
+
+ }else{
+ $("#e_tip_"+id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!');
+ }
+}
+
+function create_editorMD(id, width, high, placeholder, imageUrl,initValue, callback) {
+ var editorName = window.editormd(id, {
+ width: width,
+ height: high,
+ path: path, // "/editormd/lib/"
+ markdown : initValue,
+ syncScrolling: "single",
+ tex: true,
+ tocm: true,
+ emoji: true,
+ taskList: true,
+ codeFold: true,
+ searchReplace: true,
+ htmlDecode: "style,script,iframe",
+ sequenceDiagram: true,
+ autoFocus: false,
+ placeholder: placeholder,
+ toolbarIcons: function () {
+ // Or return editormd.toolbarModes[name]; // full, simple, mini
+ // Using "||" set icons align right.
+ return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"]
+ },
+ toolbarCustomIcons: {
+ testIcon: "",
+ testIcon1: ""
+ },
+ //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。
+ saveHTMLToTextarea: true,
+ // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标
+ dialogMaskOpacity: 0.6,
+ imageUpload: true,
+ imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"],
+ imageUploadURL: imageUrl,//url
+ onload: function () {
+ // this.previewing();
+ $("#" + id + " [type=\"latex\"]").bind("click", function () {
+ editorName.cm.replaceSelection("```latex");
+ editorName.cm.replaceSelection("\n");
+ editorName.cm.replaceSelection("\n");
+ editorName.cm.replaceSelection("```");
+ var __Cursor = editorName.cm.getDoc().getCursor();
+ editorName.cm.setCursor(__Cursor.line - 1, 0);
+ });
+
+ $("#" + id + " [type=\"inline\"]").bind("click", function () {
+ editorName.cm.replaceSelection("`$$$$`");
+ var __Cursor = editorName.cm.getDoc().getCursor();
+ editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3);
+ editorName.cm.focus();
+ });
+ $("[type=\"inline\"]").attr("title", "行内公式");
+ $("[type=\"latex\"]").attr("title", "多行公式");
+
+ callback && callback()
+ }
+ });
+ return editorName;
+}
+
+
+function updatamakedown(id){
+ setTimeout(()=>{
+ var shixunDescr = window.editormd.markdownToHTML(id, {
+ htmlDecode: "style,script,iframe",
+ taskList: true,
+ tex: true,
+ flowChart: true,
+ sequenceDiagram: true
+ });
+ $("#"+id+" p:first").addClass("ReactMarkdown");
+ $('#collaborators_list_info').show()
+ }, 200)
+}
+
+function range(start, end) {
+ const result = [];
+ for (let i = start; i < end; i++) {
+ result.push(i);
+ }
+ return result;
+}
+function disabledDateTime() {
+ return {
+ // disabledHours: () => range(0, 24).splice(4, 20),
+ disabledMinutes: () => range(1, 30).concat(range(31, 60)),
+ // disabledSeconds: () => [0, 60],
+ };
+}
+
+function disabledDate(current) {
+ return current && current < moment().endOf('day').subtract(1, 'days');
+}
+export default class TPMsettings extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ fileList: [],
+ commandLine: 0,
+ Openpublic: 0,
+ settingsData: undefined,
+ webssh: 0,
+ use_scope: 0,
+ shixunsstatus: 0,
+ shixunsID: undefined,
+ exec_time: undefined,
+ trainee: undefined,
+ can_copy: undefined,
+ task_pass: undefined,
+ test_set_permission: undefined,
+ code_edit_permission: undefined,
+ hide_code: undefined,
+ code_hidden: undefined,
+ forbid_copy: undefined,
+ vnc: undefined,
+ name: undefined,
+ scope_partment: undefined,
+ scopetype: false,
+ departmentslist: undefined,
+ description: '',
+ evaluate_script:undefined,
+ standard_scripts: undefined,
+ choice_main_type: "",
+ choice_small_type: [],
+ choice_standard_scripts:undefined,
+ editordescriptios: undefined,
+ editorevaluate_scripts: undefined,
+ choice_standard_scriptssum: undefined,
+ visibleTemplate: false,
+ Executiveordervalue: "",
+ Compilecommandvalue: "",
+ Executivetyoe: false,
+ postapplyvisible: false,
+ sendsure_applyvalue: undefined,
+ postapplytitle: false,
+ shixunnametype: false,
+ shixunmaintype: false,
+ evaluate_scripttype: false,
+ exec_timetype: false,
+ traineetype: false,
+ standard_scriptsModal:false,
+ standard_scriptsModals:false,
+ SelectTheCommandtype:false,
+ multi_webssh:false,
+ status:0,
+ opers:false,
+ operss:false,
+ testscripttiptype:false,
+ opersss:false,
+ operateshixunstype:false,
+ opening_time:"",
+ opensmail:false,
+ scope_partmenttype:false,
+ newuse_scope:undefined,
+ scope_partments:0,
+ shixun_service_configs:undefined,
+ shixun_service_configlist:undefined,
+ pod_exist_time: undefined,
+ pod_exist_timetype: false,
+ shixunmemoMDvalue:"",
+ language:"",
+ deleteisnot:true
+ }
+ }
+ descriptionMD=(initValue, id)=> {
+
+ this.contentChanged = false;
+ const placeholder = "";
+// amp;
+// 编辑时要传memoId
+ const imageUrl = `/api/attachments.json`;
+// 创建editorMd
+
+ const description_editormd =create_editorMD(id, '100%', 400, placeholder, imageUrl, initValue,()=> {
+ setTimeout(() => {
+ description_editormd.resize()
+ description_editormd.cm && description_editormd.cm.refresh()
+ }, 500)
+
+ if (initValue != undefined) {
+ description_editormd.setValue(initValue)
+ }
+ description_editormd.cm.on("change", (_cm, changeObj) => {
+ console.log('....contentChanged')
+ this.contentChanged = true;
+ })
+ });
+ md_elocalStorage(description_editormd, `MemoQuestion_${id}`, `${id}Question`);
+ this.description_editormd = description_editormd;
+ window.description_editormd = description_editormd;
+ }
+
+ evaluate_scriptMD=(initValue, id)=> {
+ this.contentChanged = false;
+ const placeholder = "";
+// amp;
+// 编辑时要传memoId
+ const imageUrl = `/api/attachments.json`;
+// 创建editorMd
+
+ const evaluate_script_editormd =create_editorMD(id, '100%', 400, placeholder, imageUrl, initValue,()=> {
+ setTimeout(() => {
+ evaluate_script_editormd.resize()
+ evaluate_script_editormd.cm && evaluate_script_editormd.cm.refresh()
+ }, 500)
+
+ if (initValue != undefined) {
+ evaluate_script_editormd.setValue(initValue)
+ }
+ evaluate_script_editormd.cm.on("change", (_cm, changeObj) => {
+ console.log('....contentChanged')
+ this.contentChanged = true;
+ })
+ });
+ md_elocalStorage(evaluate_script_editormd, `MemoQuestion_${id}`, `${id}Question`);
+ this.evaluate_script_editormd = evaluate_script_editormd;
+ window.evaluate_script_editormd = evaluate_script_editormd;
+
+ }
+
+
+
+ componentDidMount() {
+
+ let id=this.props.match.params.shixunId;
+
+ let Url=`/shixuns/`+id+`/settings.json`;
+
+ axios.get(Url).then((response)=> {
+ // alert(response.data.shixun.choice_standard_scripts)
+ if(response.status===200){
+ this.setState({
+ shixunsID: id,
+ settingsData: response.data,
+ webssh: response.data.shixun.webssh,
+ use_scope: response.data.shixun.use_scope,
+ shixunsstatus: response.data.shixun.status,
+ exec_time: response.data.shixun.exec_time,
+ trainee: response.data.shixun.trainee,
+ can_copy: response.data.shixun.can_copy,
+ task_pass: response.data.shixun.task_pass,
+ test_set_permission: response.data.shixun.test_set_permission,
+ hide_code: response.data.shixun.hide_code,
+ code_edit_permission: response.data.shixun.code_edit_permission,
+ code_hidden: response.data.shixun.code_hidden,
+ is_secret_repository: response.data.shixun.is_secret_repository,
+ init_is_secret_repository: response.data.shixun.is_secret_repository,
+ forbid_copy: response.data.shixun.forbid_copy,
+ vnc: response.data.shixun.vnc,
+ vnc_evaluate: response.data.shixun.vnc_evaluate,
+ name: response.data.shixun.name,
+ scope_partment: response.data.shixun.scope_partment,
+ description: response.data.shixun.description,
+ evaluate_script: response.data.shixun.evaluate_script,
+ choice_main_type: response.data.shixun.choice_main_type,
+ choice_small_type: response.data.shixun.choice_small_type,
+ choice_standard_scripts: response.data.shixun.choice_standard_scripts,
+ standard_scripts:response.data.shixun.standard_scripts,
+ multi_webssh:response.data.shixun.multi_webssh,
+ status:response.data.shixun.status,
+ opening_time:response.data.shixun.opening_time,
+ newuse_scope:response.data.shixun.use_scope,
+ scope_partments: response.data.shixun.scope_partment.length,
+ shixunmemoMDvalue:response.data.shixun.evaluate_script,
+ shixun_service_configs:response.data.shixun.shixun_service_configs,
+ shixun_service_configlist:response.data.shixun.shixun_service_configs,
+ })
+
+ // if(response.data.status===403){
+ // message: "您没有权限进行该操作"
+ // this.setState({
+ // :true
+ // message403:response.data.message
+ // })
+ // }
+
+
+ if(response.data.shixun.multi_webssh===true){
+ this.setState({
+ SelectTheCommandtype:true
+ })
+ }else{
+ this.setState({
+ SelectTheCommandtype:false
+ })
+ }
+ if (response.data.shixun.scope_partment.length > 0) {
+ this.setState({
+ scopetype: true
+ })
+ }
+ // console.log(response.data.shixun.description)
+ // console.log(response.data.shixun.evaluate_script)
+ // console.log(response.data.shixun.description)
+ // this.props.identity<4&&this.props.status==0||this.props.identity===1&&this.props.status==2
+
+
+ // this.evaluate_scriptMD(response.data.shixun.evaluate_script, "shixunmemoMD");
+
+ this.descriptionMD(response.data.shixun.description, "shixundescription");
+
+ // this.bigClass()
+ // if (response.data.shixun.status === 2) {
+ //
+ // } else if (response.data.shixun.status === 1) {
+ // this.props.showSnackbar("这个实训已发布不能修改!");
+ // } else if (response.data.shixun.status === 3) {
+ // this.props.showSnackbar("这个实训已关闭不能修改!");
+ // }
+ }
+
+ });
+
+
+ let departmentsUrl = `/shixuns/departments.json`;
+ axios.get(departmentsUrl).then((response) => {
+ if (response.status === 200) {
+ if (response.data.message === undefined) {
+ this.setState({
+ departmentslist: response.data.shools_name
+ });
+ }
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+
+
+
+ }
+
+ SelectshixunCommand=(e)=>{
+ // console.log( e.target.value)
+ const webssh = e.target.value
+ if (webssh == 2) {
+ this.setState({
+ webssh: webssh,
+ SelectTheCommandtype: true,
+ multi_webssh:false
+ });
+ } else {
+ if (this.state.init_is_secret_repository && !this.state.vnc && this.state.is_secret_repository == true) {
+ this.confirmDeleteSecretRepo({
+ onOk: () => {
+ this.setState({
+ webssh: webssh,
+ SelectTheCommandtype: false,
+ multi_webssh:false
+ });
+ }
+ })
+ } else {
+ if (!this.state.vnc) {
+ this.setState({
+ is_secret_repository: false,
+ })
+ }
+ this.setState({
+ webssh: webssh,
+ SelectTheCommandtype: false,
+ multi_webssh:false
+ });
+ }
+ }
+
+ // this.setState({
+ // webssh: webssh,
+ // });
+ // if(webssh===2){
+ // this.setState({
+ // SelectTheCommandtype: true,
+ // multi_webssh:false
+ // });
+ // }else{
+ // this.setState({
+ // SelectTheCommandtype: false,
+ // multi_webssh:false
+ // });
+ // }
+ }
+
+ SelectOpenpublic=(e)=>{
+ this.setState({
+ Openpublic: e.target.value
+ });
+ }
+
+ can_copy=(e)=>{
+ let sum = ""
+ if (e.target.checked === false) {
+ sum = 0
+ } else if (e.target.checked === true) {
+ sum = 1
+ }
+ this.setState({
+ can_copy: sum,
+ });
+
+ }
+
+ task_pass=(e)=>{
+
+ let sum = ""
+ if (e.target.checked === false) {
+ sum = 0
+ } else if (e.target.checked === true) {
+ sum = 1
+ }
+ this.setState({
+ task_pass: sum,
+ });
+ }
+
+ test_set_permission=(e)=>{
+ let sum = ""
+ if (e.target.checked === false) {
+ sum = 0
+ } else if (e.target.checked === true) {
+ sum = 1
+ }
+ this.setState({
+ test_set_permission: sum,
+ });
+
+ }
+
+ hide_code=(e)=>{
+ let sum = ""
+ if (e.target.checked === false) {
+ sum = 0
+ } else if (e.target.checked === true) {
+ sum = 1
+ }
+ this.setState({
+ hide_code: sum,
+ });
+
+ }
+ code_edit_permission = (e) => {
+ this.setState({
+ code_edit_permission: e.target.checked
+ })
+ }
+ code_hidden=(e)=>{
+ let sum = ""
+ if (e.target.checked === false) {
+ sum = 0
+ } else if (e.target.checked === true) {
+ sum = 1
+ }
+ this.setState({
+ code_hidden: sum,
+ });
+
+ }
+ confirmDeleteSecretRepo = ({title, onOk}) => {
+ confirm({
+ title: title ||
+
已创建的私密版本库及其内容,将在“保存”时被删除。
+
是否确认取消勾选?
+
,
+ okText: '确定',
+ cancelText: '取消',
+ onOk: () => {
+ this.setState({ is_secret_repository: false })
+ onOk && onOk()
+ },
+ onCancel() {
+ },
+ });
+ }
+ is_secret_repository = (e) => {
+ const checked = e.target.checked
+ if (!checked) {
+ if (this.state.init_is_secret_repository) {
+ this.confirmDeleteSecretRepo({
+ })
+ } else {
+ this.setState({ is_secret_repository: false })
+ }
+ } else {
+ this.setState({ is_secret_repository: true })
+ }
+ }
+ forbid_copy = (e) => {
+ let sum = ""
+ if (e.target.checked === false) {
+ sum = 0
+ } else if (e.target.checked === true) {
+ sum = 1
+ }
+ this.setState({
+ forbid_copy: sum,
+ });
+ }
+ shixun_vnc_evaluate=(e) => {
+ this.setState({
+ vnc_evaluate: e.target.checked,
+ });
+
+ }
+
+ shixun_vnc=(e)=>{
+ // let sum = ""
+ // if (e.target.checked === false) {
+ // sum = 0
+ // } else if (e.target.checked === true) {
+ // sum = 1
+ // }
+ const vnc = e.target.checked;
+ if (!vnc) {
+ if (this.state.init_is_secret_repository && this.state.webssh != 2 && this.state.is_secret_repository == true) {
+ this.confirmDeleteSecretRepo({
+ onOk: () => {
+ this.setState({
+ vnc: e.target.checked,
+ vnc_evaluate: false,
+ });
+ }
+ })
+ } else {
+ if (this.state.webssh != 2) {
+ this.setState({
+ is_secret_repository: false
+ })
+ }
+ this.setState({
+ vnc: e.target.checked,
+ vnc_evaluate: false,
+ });
+ }
+ } else {
+ this.setState({
+ vnc: e.target.checked,
+ vnc_evaluate: false,
+ });
+ }
+ }
+ shixunsname = (e) => {
+ // let {shixunsstatus}=this.state;
+ // if(shixunsstatus>0){
+ // return
+ // }
+ this.setState({
+ name: e.target.value,
+ shixunnametype:false
+ })
+ }
+
+ bigClass = (value) => {
+ // choice_main_type
+ // choice_small_type
+ let {settingsData,shixun_service_configs,choice_main_type,choice_small_type}=this.state;
+
+ let list=[]
+ list.push(choice_main_type)
+ choice_small_type.map((item,key)=>{
+ list.push(item)
+ })
+
+ let newshixun_service_configs=shixun_service_configs;
+
+ let newshixun_service_configsagin=[]
+
+ newshixun_service_configs.map((item,key)=>{
+ list.map((its,index)=>{
+ if(item.mirror_repository_id===its){
+ newshixun_service_configsagin.push(item)
+ }
+ })
+ })
+
+
+ settingsData.shixun.main_type.some((item,key)=> {
+ if (item.id === value) {
+ newshixun_service_configsagin[0]={
+ mirror_repository_id:value,
+ name:item.type_name,
+ cpu_limit:1,
+ lower_cpu_limit:0.1,
+ memory_limit:1024,
+ request_limit:10
+ }
+ return true
+ }
+ }
+ )
+ let url = `/shixuns/get_mirror_script.json?mirror_id=`+value;
+ axios.get(url).then((response) => {
+ if (response.status === 200) {
+ // console.log(response.data)
+ this.setState({
+ choice_main_type: value,
+ standard_scripts:response.data,
+ choice_standard_scripts:null,
+ shixun_service_configs:newshixun_service_configsagin,
+ shixun_service_configlist:newshixun_service_configsagin,
+ })
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+
+
+
+ }
+ Deselectlittle=(value)=>{
+
+ let {shixun_service_configs,choice_small_type}=this.state;
+ let newshixun_service_configs=shixun_service_configs;
+ let newchoice_small_type=choice_small_type;
+
+ newshixun_service_configs.some((item,key)=> {
+ if (item.mirror_repository_id === value) {
+ newshixun_service_configs.splice(key, 1)
+ return true
+ }
+ }
+ )
+
+ newchoice_small_type.some((item,key)=> {
+ if (item === value) {
+ newchoice_small_type.splice(key, 1)
+ return true
+ }
+ }
+ )
+
+
+ this.setState({
+ choice_small_type: newchoice_small_type,
+ shixun_service_configs:newshixun_service_configs,
+ shixun_service_configlist:newshixun_service_configs,
+ })
+ }
+ littleClass = (value) => {
+
+ let {settingsData,shixun_service_configs,choice_small_type,choice_main_type}=this.state;
+ let newshixun_service_configs=shixun_service_configs;
+ let newchoice_small_type=choice_small_type;
+ // if(Array.isArray(value)===true){
+ // value.map((item,key)=>{
+ // settingsData.shixun.small_type.some((items,keys)=> {
+ // if (items.id === item) {
+ // newshixun_service_configs.push({
+ // mirror_repository_id:value,
+ // name:items.type_name,
+ // cpu_limit:1,
+ // lower_cpu_limit:0.1,
+ // memory_limit:1024,
+ // request_limit:10
+ // })
+ // return true
+ // }
+ // }
+ // )
+ // })
+ // }
+
+ let list=[]
+ list.push(choice_main_type)
+ choice_small_type.map((item,key)=>{
+ list.push(item)
+ })
+
+ let newshixun_service_configsagin=[]
+
+ newshixun_service_configs.map((item,key)=>{
+ list.map((its,index)=>{
+ if(item.mirror_repository_id===its){
+ newshixun_service_configsagin.push(item)
+ }
+ })
+ })
+
+ settingsData.shixun.small_type.some((items,keys)=> {
+ if (items.id === value) {
+ newshixun_service_configsagin.push({
+ mirror_repository_id:value,
+ name:items.type_name,
+ cpu_limit:1,
+ lower_cpu_limit:0.1,
+ memory_limit:1024,
+ request_limit:10
+ })
+ return true
+ }
+ }
+ )
+
+ newchoice_small_type.push(value)
+
+ this.setState({
+ choice_small_type: newchoice_small_type,
+ shixun_service_configs:newshixun_service_configsagin,
+ shixun_service_configlist:newshixun_service_configsagin,
+ })
+ }
+ onPodExistTimeChange = (e) => {
+ this.setState({
+ pod_exist_time: e.target.value,
+ pod_exist_timetype: false,
+ })
+ }
+ Timevalue = (e) => {
+ this.setState({
+ exec_time: e.target.value
+ })
+ }
+ SelectOpenpublic = (e) => {
+ this.setState({
+ scopetype: false,
+ use_scope: e.target.value,
+ });
+ if (e.target.value === 1) {
+ this.setState({
+ scopetype: true
+ });
+ }
+
+ }
+ deleteScopeInput = (key) => {
+ let {scope_partment} = this.state;
+ let datalist = scope_partment;
+ datalist.splice(key, 1);
+ this.setState({
+ scope_partment: datalist
+ });
+ }
+
+ shixunScopeInput = (e) => {
+ let {scope_partment} = this.state;
+ let datalist = scope_partment;
+ if (datalist===undefined) {
+ datalist=[]
+ }
+
+ datalist.push(e)
+ // else {
+ // datalist[id] = e
+ // }
+ this.setState({
+ scope_partment: datalist
+ });
+ }
+ // adduse_scopeinput = () => {
+ // let {scope_partment} = this.state;
+ // let array = scope_partment;
+ // let newarray = ""
+ // array.push(newarray)
+ // this.setState({
+ // scope_partment: array,
+ // });
+ // }
+ submit_edit_shixun = () => {
+ if (this.saving == true) return;
+ this.saving = true;
+ if(this.state.status===-1){
+ this.props.showSnackbar("该实训已被删除,保存失败!");
+ return
+ }
+
+ let {
+ name, choice_main_type, choice_small_type, choice_standard_scripts, scope_partment, choice_standard_scriptssum, vnc_evaluate,
+ evaluate_script, webssh, use_scope, trainee, can_copy, task_pass, test_set_permission, hide_code, code_hidden, forbid_copy, vnc,multi_webssh,
+ opening_time,shixunmemoMDvalue,shixun_service_configlist, is_secret_repository, code_edit_permission
+ } = this.state;
+
+ let newshixun_service_configlist = shixun_service_configlist.map(v => {
+ let v1 = Object.assign({},v);
+ delete v1.name;
+ return v1
+ });
+
+ // let operateauthority=
+ // this.props.identity===1?true:this.props.identity<5&&this.state.status==0?true:false;
+ // this.props.identity<5&&this.state.status==0||this.props.identity===1&&this.state.status==2||this.props.identity===1&&this.state.status==1;
+
+ const description_editormd = this.description_editormd.getValue();
+
+ let evaluate_script_editormd;
+
+ if(this.state.status==0||this.state.status==1||this.state.status==2&&this.props.identity===1){
+ // evaluate_script_editormd = this.evaluate_script_editormd.getValue();
+ evaluate_script_editormd = shixunmemoMDvalue
+ }else{
+ evaluate_script_editormd = evaluate_script;
+ }
+
+
+
+ if (name === "") {
+ this.setState({
+ shixunnametype: true
+ })
+ $('html').animate({
+ scrollTop: 10
+ }, 1000);
+ return
+ }
+ if (choice_main_type === "") {
+ this.setState({
+ shixunmaintype: true
+ })
+ $('html').animate({
+ scrollTop: 800
+ }, 1000);
+ return
+ }
+ if (evaluate_script_editormd === "") {
+ this.setState({
+ evaluate_scripttype: true
+ })
+ $('html').animate({
+ scrollTop: 1200
+ }, 1000);
+ return
+ }
+ if(use_scope===1){
+
+ if(scope_partment===undefined||scope_partment.length===0){
+ this.setState({
+ scope_partmenttype: true
+ })
+ $('html').animate({
+ scrollTop: 2500
+ }, 1000);
+ this.props.showSnackbar("公开程度,指定单位为空");
+ return
+ }
+ }
+ // if (exec_time === "") {
+ // this.setState({
+ // exec_timetype: true
+ // })
+ // $('html').animate({
+ // scrollTop: 1500
+ // }, 1000);
+ // return
+ // }
+
+ // if (!pod_exist_time) {
+ // this.setState({
+ // pod_exist_timetype: true
+ // })
+ // $("html, body").animate({ scrollTop: $('#pod_exist_time').offset().top - 100 }, 1000)
+ // return
+ // }
+
+ if (trainee === "") {
+ this.setState({
+ traineetype: true
+ })
+ return
+ }
+
+ let id = this.props.match.params.shixunId;
+
+ let newmulti_webssh=multi_webssh;
+
+
+ if(newmulti_webssh===null){
+ newmulti_webssh=false
+ }
+
+ //exec_time: exec_time,
+ let Url = `/shixuns/` + id + `.json`;
+ let data = {
+ shixun:{
+
+ name: name,
+ webssh: webssh,
+ use_scope: use_scope,
+ can_copy: can_copy,
+ vnc: vnc===null?undefined:vnc,
+ vnc_evaluate: vnc_evaluate===null?undefined:vnc_evaluate,
+ test_set_permission: test_set_permission,
+ code_hidden: code_hidden,
+ code_edit_permission: code_edit_permission,
+ trainee: trainee,
+ task_pass: task_pass,
+ hide_code: hide_code,
+ forbid_copy: forbid_copy,
+ multi_webssh:newmulti_webssh,
+ opening_time:opening_time,
+ mirror_script_id:choice_standard_scriptssum===undefined?choice_standard_scripts:choice_standard_scriptssum,
+ },
+ shixun_info:{
+ description: description_editormd,
+ evaluate_script: evaluate_script_editormd,
+ },
+ is_secret_repository: is_secret_repository,
+ main_type: choice_main_type,
+ small_type: choice_small_type,
+ scope_partment: scope_partment,
+ shixun_service_configs:newshixun_service_configlist
+ }
+
+ axios.put(Url, data).then((response) => {
+ // console.log(response)
+ this.saving = false;
+ if(response.status){
+ if (response.data.status === -1) {
+ this.props.showSnackbar(response.data.message);
+ return
+ } else {
+ window.location.href = "/shixuns/" + response.data.shixun_identifier + "/challenges";
+ }
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ this.saving = false;
+ })
+
+
+ }
+ shixunsfetch = (value, callback) => {
+ if (timeout) {
+ clearTimeout(timeout);
+ timeout = null;
+ }
+ currentValue = value;
+
+ function fake() {
+ let departmentsUrl = `/shixuns/departments.json?q=` + currentValue;
+ axios.get(departmentsUrl).then((response) => {
+ callback(response.data.shools_name);
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ timeout = setTimeout(fake, 300);
+ }
+ shixunHandleSearch = (value) => {
+ this.shixunsfetch(value, departmentslist => this.setState({departmentslist}));
+ }
+
+
+
+
+ shixunsclose = () => {
+ let id = this.props.match.params.shixunId;
+ let cul = `/shixuns/` + id + `/close.json`;
+ axios.post(cul).then((response) => {
+ if(response.data.status===1){
+ this.props.showSnackbar("操作成功");
+ this.setState({
+ operateshixunstype: false,
+ });
+
+ window.location.href = "/shixuns/" + id + "/challenges";
+ }
+ }).catch((error) => {
+ console.log(error)
+ })
+ }
+
+ shixunsdel= () => {
+ let id = this.props.match.params.shixunId;
+ let cul = `/shixuns/` + id +`.json`;
+
+ axios.delete(cul).then((response) => {
+ if(response.data.status===1){
+ this.props.showSnackbar("操作成功");
+ this.setState({
+ operateshixunstype: false,
+ });
+
+ window.location.href = "/shixuns";
+ }
+ }).catch((error) => {
+ console.log(error)
+ })
+ }
+
+ Executiveorder = (e) => {
+ this.setState({
+ Executiveordervalue: e.target.value
+ })
+ }
+
+ Compilecommand = (e) => {
+ this.setState({
+ Compilecommandvalue: e.target.value
+ })
+ }
+
+ handleCancelTemplate = (e) => {
+ this.setState({
+ Executiveordervalue: "",
+ Compilecommandvalue: "",
+ visibleTemplate: false
+ })
+ }
+
+ hideModalTemplate = (e) => {
+ let id = this.props.match.params.shixunId;
+ let {Executiveordervalue, Compilecommandvalue} = this.state;
+
+ if (Executiveordervalue === "") {
+ this.setState({
+ Executivetyoe: true,
+ });
+ return
+ }
+ // Executiveordervalue=String(Executiveordervalue);
+ // Compilecommandvalue=String(Compilecommandvalue);
+ let trl = `/shixuns/${id}/get_custom_script.json?compile=${Executiveordervalue}&excutive=${Compilecommandvalue}`
+ axios.get(trl).then((response) => {
+ // this.evaluate_scriptMD(response.data.shixun_script, "shixunmemoMD");
+ this.setState({
+ shixunmemoMDvalue:response.data.shixun_script
+ })
+ }).catch((error) => {
+ console.log(error)
+ });
+ this.setState({
+ visibleTemplate: false
+ })
+ }
+
+ showModal = () => {
+ this.setState({
+ visibleTemplate: true,
+ });
+ }
+ Selecttrainee = (value) => {
+ this.setState({
+ trainee: value,
+ });
+ }
+
+ post_apply = () => {
+ this.setState({
+ postapplyvisible: true
+ })
+ }
+
+ sendsure_applyvalues = (e) => {
+ this.setState({
+ sendsure_applyvalue: e.target.value
+ })
+ }
+
+ setlanguagewrite = (e)=>{
+ this.setState({
+ languagewrite: e.target.value
+ })
+ }
+
+ setsystemenvironment = (e) => {
+ this.setState({
+ systemenvironment: e.target.value
+ })
+ }
+
+ settestcoderunmode = (e) => {
+ this.setState({
+ testcoderunmode: e.target.value
+ })
+
+ }
+
+ sendsure_apply = () => {
+ let {languagewrite,systemenvironment,testcoderunmode} = this.state;
+ // console.log("点击确定")
+ // console.log("languagewrite"+languagewrite);
+ // console.log("systemenvironment"+systemenvironment);
+ // console.log("testcoderunmode"+testcoderunmode);
+
+ // let attachment_ids = undefined
+ // if (this.state.fileList) {
+ // attachment_ids = this.state.fileList.map(item => {
+ // return item.response ? item.response.id : item.id
+ // })
+ // }
+ if(languagewrite === undefined || languagewrite === "" ){
+ // this.props.showNotification(`请填写该镜像是基于什么语言`);
+ this.setState({
+ languagewritetype:true
+ })
+ return
+ }
+ if(systemenvironment === undefined || systemenvironment === ""){
+ // this.props.showNotification(`请填写该镜像是基于什么语言系统环境`);
+ this.setState({
+ systemenvironmenttype:true
+ })
+ return;
+
+ }
+ if(testcoderunmode === undefined || testcoderunmode === "") {
+ // this.props.showNotification(`请填写该镜像中测试代码运行方式`);
+ this.setState({
+ testcoderunmodetype:true
+ })
+ return;
+ }
+ var attachment_ids=undefined;
+ if (this.state.fileList) {
+ attachment_ids = this.state.fileList.map(item => {
+ return item.response ? item.response.id : item.id
+ })
+ }
+
+ if( attachment_ids === undefined || attachment_ids.length===0){
+
+ // notification.open(
+ // {
+ // message: '提示',
+ // description:
+ // '请上传附件!',
+ //
+ // }
+ // )
+ this.setState({
+ attachmentidstype:true
+ })
+ return;
+ }
+ // console.log("attachment_ids"+attachment_ids);
+
+ // alert(languagewrite +" "+systemenvironment +" "+testcoderunmode + " "+attachment_ids);
+
+ var data={
+ language:languagewrite,
+ runtime:systemenvironment,
+ run_method:testcoderunmode,
+ attachment_id:attachment_ids[0],
+ }
+ var url =`/shixuns/apply_shixun_mirror.json`;
+ axios.post(url,data
+ ).then((response) => {
+
+ try {
+ if (response.data) {
+ // const { id } = response.data;
+ // if (id) {
+ if(this.state.file !== undefined){
+ console.log("549");
+ // this.deleteAttachment(this.state.file);
+ this.setState({
+ file:undefined,
+ deleteisnot:true,
+ languagewrite:"",
+ systemenvironment:"",
+ testcoderunmode:"",
+ fileList:[]
+ })
+ }else {
+ this.setState({
+ file:undefined,
+ deleteisnot:true,
+ languagewrite:"",
+ systemenvironment:"",
+ testcoderunmode:"",
+ fileList:[]
+ })
+ }
+ // this.props.showNotification('提交成功!');
+ notification.open(
+ {
+ message: '提示',
+ description:
+ '提交成功!',
+
+ }
+ )
+ this.sendhideModaly()
+ // this.props.history.push(`/courses/${cid}/graduation_topics`);
+ // }
+ }
+ }catch (e) {
+
+ }
+
+ })
+
+ }
+
+ sendhideModaly = () => {
+ this.setState({
+ postapplyvisible: false,
+ })
+ if(this.state.file !== undefined){
+ console.log("580");
+ // this.deleteAttachment(this.state.file);
+ this.setState({
+ file:undefined,
+ deleteisnot:true,
+ languagewrite:"",
+ systemenvironment:"",
+ testcoderunmode:"",
+ fileList:[]
+ })
+ }else {
+ this.setState({
+ file:undefined,
+ deleteisnot:true,
+ languagewrite:"",
+ systemenvironment:"",
+ testcoderunmode:"",
+ fileList:[]
+ })
+ }
+ }
+
+ yeshidemodel = () => {
+ this.setState({
+ postapplytitle: false
+ })
+ }
+
+ SelectScput = (value, e) => {
+ this.setState({
+ choice_standard_scriptssum: value,
+ language:e.props.name,
+ choice_standard_scripts: {id:e.props.value,value:""},
+ standard_scriptsModal:true
+ })
+ }
+
+ hidestandard_scriptsModal=()=>{
+ this.setState({
+ standard_scriptsModal:false,
+ standard_scriptsModals:false
+ })
+ }
+
+ get_mirror_script=()=>{
+ let {choice_standard_scriptssum}=this.state;
+ let id = this.props.match.params.shixunId;
+ let pul = "/shixuns/" + id + "/get_script_contents.json?script_id=" + choice_standard_scriptssum;
+ axios.get(pul).then((response) => {
+ if(response.status===200){
+ // this.evaluate_scriptMD(response.data.content, "shixunmemoMD");
+ this.setState({
+ standard_scriptsModal:false,
+ standard_scriptsModals:true,
+ shixunmemoMDvalue:response.data.content
+ })
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ })
+ }
+
+
+ SelectTheCommandonChange=(e)=>{
+ this.setState({
+ multi_webssh:e.target.checked
+ })
+ }
+
+ bigopen=()=>{
+ this.setState({
+ opers:true
+ })
+
+ }
+
+ bigopens=()=>{
+ this.setState({
+ opers:false,
+ operss:false,
+ opersss:false,
+ opensmail:false
+ })
+
+ }
+ bigopensmal=(e)=>{
+ this.setState({
+ opensmail:true
+ })
+
+ }
+ sbigopen=(e)=>{
+ this.setState({
+ operss:true
+ })
+
+ }
+
+ sbigopens=()=>{
+ this.setState({
+ operss:false
+ })
+ }
+ sbigopenss=(e)=>{
+ this.setState({
+ opersss:true
+ })
+
+ }
+
+ sbigopensss=()=>{
+ this.setState({
+ opersss:false
+ })
+ }
+ testscripttip=(val)=>{
+ if(val===0){
+ this.setState({
+ testscripttiptype:true
+ })
+ }else if(val===1){
+ this.setState({
+ testscripttiptype:false
+ })
+ }
+ }
+
+ operateshixuns=(value)=>{
+ this.setState({
+ operateshixunstype:true,
+ delType:value
+ })
+ }
+
+ hideoperateshixuns=()=>{
+ this.setState({
+ operateshixunstype:false
+ })
+ }
+ onChangeTimePicker =(value, dateString)=> {
+ this.setState({
+ opening_time: dateString=== ""?"":moment(handleDateStrings(dateString))
+ })
+ }
+
+ getshixunmemoMDvalue=(value, e)=>{
+
+ this.setState({
+ shixunmemoMDvalue:value
+ })
+ }
+
+ setConfigsInputs=(e,keys,str)=>{
+
+ let {shixun_service_configs}=this.state;
+ let newshixun_service_configs=shixun_service_configs;
+ newshixun_service_configs.map((item,key)=>{
+ if(key===keys){
+ switch (str) {
+ case 1:
+ item.cpu_limit=e.target.value
+ break;
+ case 2:
+ item.lower_cpu_limit=e.target.value
+ break;
+ case 3:
+ item.memory_limit=e.target.value
+ break;
+ case 4:
+ item.request_limit=e.target.value
+ break;
+ }
+ }
+ })
+
+ this.setState({
+ shixun_service_configs:newshixun_service_configs,
+ shixun_service_configlist:newshixun_service_configs,
+ })
+
+ }
+
+ handleChange = (info) => {
+ let {fileList}=this.state;
+
+ if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
+ console.log("handleChange1");
+
+ // if(fileList.length===0){
+ let fileLists = info.fileList;
+ this.setState({ fileList:fileLists,
+ deleteisnot:false});
+ // }
+ }
+ }
+
+ onAttachmentRemove = (file) => {
+ if(!file.percent || file.percent == 100){
+ confirm({
+ title: '确定要删除这个附件吗?',
+ okText: '确定',
+ cancelText: '取消',
+ // content: 'Some descriptions',
+ onOk: () => {
+ console.log("665")
+ this.deleteAttachment(file)
+ },
+ onCancel() {
+ console.log('Cancel');
+ },
+ });
+ return false;
+ }
+
+ }
+
+ deleteAttachment = (file) => {
+ console.log(file);
+ let id=file.response ==undefined ? file.id : file.response.id
+ const url = `/attachments/${id}.json`
+ axios.delete(url, {
+ })
+ .then((response) => {
+ if (response.data) {
+ const { status } = response.data;
+ if (status == 0) {
+ // console.log('--- success')
+
+ this.setState((state) => {
+
+ const index = state.fileList.indexOf(file);
+ const newFileList = state.fileList.slice();
+ newFileList.splice(index, 1);
+ return {
+ fileList: newFileList,
+ deleteisnot:true
+ };
+ });
+ }
+ }
+ })
+ .catch(function (error) {
+ console.log(error);
+ });
+ }
+
+
+
+ render() {
+ let {
+ postapplyvisible,
+ postapplytitle,
+ shixunnametype,
+ shixunmaintype,
+ evaluate_scripttype,
+ traineetype,
+ standard_scripts,
+ name,
+ settingsData,
+ webssh,
+ is_secret_repository,
+ use_scope,
+ shixunsID,
+ can_copy,
+ choice_standard_scripts,
+ Executiveordervalue,
+ Executivetyoe,
+ Compilecommandvalue,
+ task_pass,
+ test_set_permission,
+ hide_code,
+ forbid_copy,
+ code_edit_permission,
+ code_hidden,
+ vnc,
+ vnc_evaluate,
+ scopetype,
+ scope_partment,
+ departmentslist,
+ trainee,
+ choice_main_type,
+ choice_small_type,
+ standard_scriptsModal,
+ standard_scriptsModals,
+ SelectTheCommandtype,
+ testscripttiptype,
+ operateshixunstype,
+ opening_time,
+ scope_partmenttype,
+ newuse_scope,
+ scope_partments,
+ shixunmemoMDvalue,delType,
+ shixun_service_configs,
+ fileList,
+ } = this.state;
+
+ let options;
+
+ if (departmentslist != undefined) {
+ options = this.state.departmentslist.map((d, k) => {
+ return (
+
+ )
+ })
+ }
+ const uploadProps = {
+ width: 600,
+ fileList,
+ multiple: true,
+ // https://github.com/ant-design/ant-design/issues/15505
+ // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
+ // showUploadList: false,
+ action: `${getUploadActionUrl()}`,
+ onChange: this.handleChange,
+ onRemove: this.onAttachmentRemove,
+ beforeUpload: (file, fileList) => {
+ if (this.state.fileList.length >= 1) {
+ return false
+ }
+ // console.log('beforeUpload', file.name);
+ const isLt150M = file.size / 1024 / 1024 < 50;
+ if (!isLt150M) {
+ // this.props.showNotification(`文件大小必须小于50MB`);
+ notification.open(
+ {
+ message: '提示',
+ description:
+ '文件大小必须小于50MB',
+
+ }
+ )
+ }
+ if(this.state.file !== undefined){
+ console.log("763")
+ this.setState({
+ file:file
+ })
+ }else {
+ this.setState({
+ file:file
+ })
+ }
+
+ console.log("handleChange2");
+ return isLt150M;
+ },
+ }
+ const dateFormat = 'YYYY-MM-DD HH:mm:ss';
+ let operateauthority=this.props.identity===1?true:this.props.identity<5&&this.state.status==0?true:false;
+
+ return (
+
+
+ 实训详情
+ 配置
+
+
+
+
+
+
+
+
实训名称
+
+
+
*
+
+
+ {settingsData === undefined ? "" :
+ }
+
+
+ 必填项
+
+
+
+
+
+
+
+
+
+
+
+
+
+
技术平台
+
+
+
+
*
+
+
+
+ 列表中没有?
+ 申请新建
+
+
+
+
+
+
+
+
+
{this.state.languagewritetype===true?"请填写该镜像语言":""}
+
+
+
+
+
{this.state.systemenvironmenttype===true?"请填写该镜像语言系统环境":""}
+
+
+
+
+
+
{this.state.testcoderunmodetype===true?"请填写该镜像测试代码运行方式":""}
+
+
+
+
+
+ 上传附件
+ (单个文件50M以内)
+
+
+
+
+ {this.state.attachmentidstype===true?"请上传附件":""}
+
+
+ this.sendhideModaly()}
+ >取消
+
+
+
+
+
+
+
+
+
+
+
+
+
新建申请已提交,请等待管理员的审核
+
我们将在1-2个工作日内与您联系
+
+
+
+
+
+
+
+
+
+
+
+ 必填项
+
+ {/*
请在配置页面完成后续的评测脚本设置操作
*/}
+
+
+
+ {/*
*/}
+ {/*
*/}
+
+
评测脚本
+
+
+
+
+
原有脚本将被新的脚本覆盖,无法撤销
+
是否确认执行覆盖操作
+
+
+
+
+
+
+
+
+
+
+ {
+ this.props.identity<5||this.props.power==true?
+
使用自定义脚本 : ""
+ }
+
+
this.testscripttip(0)}>)
+
+
+
+
+ 使用自定义模板,平台无法自动更新脚本,
+ 请在关卡创建完后手动更新脚本中的必填参
+ 数和以下2个数组元素:
+ challengeProgramNames
+ sourceClassNames
+ 示例:有2个关卡的实训
+ 各关卡的待编译文件为:
+ src/step1/HelloWorld.java
+ src/step2/Other.java
+ 各关卡的编译后生成的执行文件为:
+ step1.HelloWorld
+ step2.Other
+ 则数组元素更新如下:
+ challengeProgramNames=("src/step1/
+ HelloWorld.java" "src/step2/Other.java")
+ sourceClassNames=("step1.HelloWorld
+ " "step2.Other")
+ 其它参数可按实际需求定制
+
+
+
+ this.testscripttip(1)}>知道了
+
+
+
+
+
+
+
+
+
+ 执行命令不能为空
+
+
+
+
+
+
+
+
+
+
+
+
+
+
*
+
+
+
+
+ {/**/}
+
+
+
+
+ {/*
*/}
+ {/*{evaluate_script===undefined?"":evaluate_script}*/}
+
+ {/*
*/}
+
+
+
+
+
+
+
+
+
+ {/*
*/}
+ {/*
**/}
+
+ {/*
程序最大执行时间
*/}
+
+ {/*
秒*/}
+
+ {/*
*/}
+ {/*必填项*/}
+ {/*
*/}
+ {/*
*/}
+
+ {/*
+
*
+
+
Pod存活时间
+
+
秒
+
+
+ 必填项
+
+
*/}
+
+
+
+
命令行
+
+ 无命令行窗口 (选中则不给学员的实践任务提供命令窗口)
+ 命令行练习窗口 (选中则给学员提供用于练习操作的命令行窗口)
+ 命令行评测窗口 (选中则给学员提供用于关卡评测的命令行窗口)
+
+ 多个命令行窗口(选中则允许学员同时开启多个命令行窗口)
+
+
+
+
+
+
公开程度
+
+ 对所有公开 (选中则所有已被试用授权的用户可以学习)
+ 对指定单位公开 (选中则下方指定单位的已被试用授权的用户可以学习)
+
+
+
+
+
+
+
+
+ {/*{*/}
+ {/*scope_partment===undefined?"":scope_partment.map((item,key)=>{*/}
+ {/*return(*/}
+ {/*
*/}
+ {/*this.deleteScopeInput(key)} style={{ color: 'rgba(0,0,0,.25)' }} />}*/}
+ {/*value={item}*/}
+ {/*/>*/}
+ {/*
*/}
+
+ {/*)*/}
+ {/*})*/}
+ {/*}*/}
+
+
+
+ 请选择需要公开的单位
+
+
+
+
+
+
+
发布信息
+
+
+
*
+
面向学员:
+
+
+
+
+
实训难易度定位,不限定用户群体
+
+ 必填项
+
+
+
+
+ 复制:
+
+
+
+
+
+
+
+ 跳关:
+
+
+
+
+
+
+ 测试集解锁:
+
+
+
+
+
+
+ {!code_hidden && !hide_code &&
+ 代码开放修改:
+
+
+
+
+
}
+
+
+ 隐藏代码窗口:
+
+
+
+
+
+
+
+ 代码目录隐藏:
+
+
+
+
+
+
+ { (vnc || webssh == 2) &&
+ 私密版本库:
+
+
+
+
+
}
+
+
+ 禁用复制粘贴:
+
+
+
+
+
+
+
+ 开启时间:
+
+
+
+
+
+
+ {this.props.identity<3?
+ VNC图形化:
+
+
+
+
+
:""}
+ {this.props.identity<3 && vnc ?
+ VNC图形化评测:
+
+
+
+
+
:""}
+
+
+
+
+
+ {this.props.identity<3?
+
服务配置
+ { shixun_service_configs&&shixun_service_configs.map((item,key)=>{
+
+ return(
+
+
+
+ {item.name}
+ {/*this.Deselectlittle(item.mirror_repository_id)}>*/}
+
+
+
+
+ this.setConfigsInputs(e,key,1)}
+ className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" />
+
+
+
+
+
+
+ this.setConfigsInputs(e,key,2)}
+ className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" />
+
+
+
+
+
+
+ this.setConfigsInputs(e,key,3)}
+ className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" />
+
+
+
+
+
+
+ this.setConfigsInputs(e,key,4)}
+ className="panel-box-sizing task-form-100 task-height-40" placeholder="请输入类别名称" />
+
+
+
+
+
+
+ )
+
+ })}
+
:""}
+
+
+ {
+ // this.props.identity<4&&this.props.status==0?
+ this.props.identity<5?
+
:""
+ }
+
+
+
+
+ );
+ }
+}
+
+
diff --git a/public/react/src/tpm/TPMsettings/css/TPMsettings.css b/public/react/src/tpm/TPMsettings/css/TPMsettings.css
new file mode 100644
index 000000000..8047bbde8
--- /dev/null
+++ b/public/react/src/tpm/TPMsettings/css/TPMsettings.css
@@ -0,0 +1,113 @@
+.radioStyle{
+ display: block;
+ height: 30px;
+ }
+#settingsMarkdown{
+ background:transparent;
+}
+#challenge_begin{
+ height: 30px;
+ line-height: 30px;
+}
+#shixundescription .CodeMirror{
+ margin-top: 31px !important;
+ height: 364px !important;
+}
+#shixundescription .editormd-preview{
+ width:578px !important;
+ top: 40px !important;
+ height: 364px !important;
+}
+
+#shixunmemoMD .CodeMirror{
+ margin-top: 31px !important;
+ height: 578px !important;
+}
+
+#shixunmemoMD .editormd-preview{
+ width: 578px !important;
+ top: 40px !important;
+ height: 578px !important;
+}
+
+.radioStyle {
+ display: block;
+ height: 30px;
+}
+
+a.white-btn.use_scope-btn:hover {
+ color: #FFF !important;
+}
+
+.shixunScopeInput {
+ width: 218px;
+ height: 33px;
+ display: block;
+ margin-bottom: 15px;
+}
+
+.ant-modal-title {
+ text-align: center;
+}
+
+a.newuse_scope-btn:hover {
+ border: 1px solid #F06200;
+ color: #fff !important;
+ background: #FF7500;
+}
+
+a.newuse_scope-btn {
+ border: 1px solid #FF7500;
+ color: #FF7500 !important;
+}
+
+.tpmprompt {
+ padding-left: 20px;
+ margin-top: -4px;
+}
+.ml36{
+ margin-left: 26px;
+}
+
+#shixunmemoMD{
+ width:98% !important;
+ height: 620px !important;
+}
+#shixunmemoMDs{
+ width: 98% !important;
+ height: 420px !important;
+}
+#shixunmemoMDs .CodeMirror {
+ /* width: 548px !important; */
+ margin-top: 31px !important;
+ height: 402px !important;
+}
+.pdr20{
+ padding-right:20px;
+}
+
+.nonemodel{
+ width: 59%;
+ height: 468px;
+ /*background: rgba(0, 0, 0, 0.65);*/
+ background: #f5f5f5;
+ position: absolute;
+ z-index: 100;
+ opacity: 0.5;
+ left: 21.5%;
+}
+
+.shixunmemoMDdiv{
+ width: 99%;
+ height: 615px;
+}
+
+.shixunspanred{
+ margin-left: 142px;
+ margin-top: 5px;
+ margin-bottom: 5px;
+}
+
+.ml82{
+ margin-left:82px;
+}
diff --git a/public/react/src/tpm/beian.png b/public/react/src/tpm/beian.png
new file mode 100755
index 0000000000000000000000000000000000000000..9f763946dd6606addeab24e40e2369124d53a048
GIT binary patch
literal 19256
zcmeI4c{G&a_rPDYSRz?cRHh**jbW@aG4@bIvPT-TFwB@~W-OyD?Wzv>B_s{Rld(O-|_qor#_kBLkeeV0rob%2J%k9R3{F3|t
z00^3z7+NvUVlyw^Ma=h*6RQQ8CqA-?0~G)SL}y-HKwQEK0N^*r8yHwxx|3)msym4c
zGBq#&ktrk`o`3}azm~+EzV=b$%aQHl*rm4m&BNDY2nPVL41>2y*dbLo5_Jg5x422i0+8_A>U(Yr%K>1Rhwc|hyQVY6b(I8g
z1LQ_US&_n%Gm*+2%rNj(k;LhZUs~+T33kyRV#pNJ8xk4foK3A(D&AUo>^XyWe)cdW-8O
z41Fk1{o*-H0wdRsw0|i)&Ak8+-d;D<;?mXC#6zy+y5?QtnYjySu?5`QC!AGU`H~&^
zANx<7qH9j+u1QLYs+S*2-*
zruU+}e6p=VyQ>%ID|?N1%Y3Ok5;PsUq5ie%b*D|@Cr9j0t?AQ$&3A^Qd&KsRs{a#~U#0uXjnh0(_WAgW{{
zOjm&mcodWV1^^1*t#G;&En!x{3jl`62R2^QTfF417^74u;qL0fQVDLe2muY_~&Dr*XMcZfJ0=p#!k+Os0*-ipGbd<*od
zctufb5yzLghBkw1c_m^)7l2VFs*%Czpq}GmJHX{tlyvS)eUAud6PfoAiWoe^N%wPj
zYZVA~a_VHEv2yf*oEYwr>QP=4nCXeSudHpMmzXcYDWFGciuE0
z;AAK|xL#QZcltTX>GUz9JtyoXyX@6$!_?5L?KOPFrAm`fL%g!wr-DWMd3PTc
zzDGD19&T)JW^Zt5UB67ONCB@M-=V|G_tt}>E?MNR^B0*Y^K(U954YdKkQ-dPW^K~C
z-Rp%!U7}26g&st9Zs%XSE*xemVCreoY63~$nT~7_#wVD`^@S53yzJ!731)y|BJ#qQ
zhFe5VKDghRCx$3L{@RQ$Rn{s!T4bvlR;O#hh4V1|*yPJQ9%Uvy<-L3yao*9CnCxQ-
z-FYliRMk6f-J|&B2G!}1w8qDAcsKmGJG6&Z!1v^FYgxL-Wtp~xA;8QU{~
zXSy$2+fZ$E8tIn>tgqNCy|UXj;NljW8D%Oa&fIlZ&P2bN&%#M5ALu@_
zod(p)I0h~Pm-u$?BQBwe>m9@J=LuVD*VYQw?t}0^bRgH8JhE_Efms?Y{w>8Vt^<^T
z>-Na3aV+bN*+?%gJyV+UiI*m1Z7S1a7{S+o##1xe*N&_SC^JmyB9>1xu?~ermfGH8$9OrM$JzG
ziDQsfxiVB=V%t2mP_B4bYkFCFd1vv4N70^fxPtoJC$yTHs!eT-X2yg5P~Ef+cDc`4AUm3zD<3^COd+qlwJIi
zctm{ltxH+)S!F))#CEaQVqqH^HjM4`YEkZ=>gVr|>t8eg|A_jy?j!MI-RhcEBCDG=
z(>Cv?(7bDW2;{=P^jE6)Gs`mX_t?2fxusAON7W=QZVRs#iSdb%*h$Pdnc;Qbzxqs<
zVP9gsY5gU6FcdO_@h3yakjhAh0Z2)YC*
zuD^s&&_S9KMJkneFExQyX>;2YS1a$XfoY|VDWuZswc-w^oNf#%~dTMU*
z9`7(F9M6}=uZ)$L2oT$_5q4RzcSr6{+FsiDrY1(G!=zhL=tx-R>D!xIJ#JBa+!!7N
zD+0PdK0i4Ba{d9oW1oyhVnk@7vU~$4I?I~Nv`@UDa(5HrR1!Mltk2TW*BN2lu$NZ%5=!lEm~%Y3!y`@``^ER2d%LsEBK&&%Jc75O&N
z_RL4k7n=hNKD!^a*y3HG!e?QnK#y1%d0S@G+}5z^C8O^7-scc_bV77Onw22_Y_7sH
zr9AmO3!H*Nlwc?QE%BjL)Uk)-oiY>D(N=N75wrTVT&rwLq2*@KOA3CwR_yZ2Hz_i4
ze5%rp`_elhBXDr}{-W?}migCiH0S#{jC6oYjP5L#Iki*5S5ev7ssQ7MA8rV!cCXGk
zJ8k*e-pb~^2fgimsMVo{3l|I&4%(@n$&7wb?Unt(@itlQbWgAA?)vtN`}e)Ee3w#tzwQ2`_Sm4j
zG2T8Cxn%5Tu#m1<#jNy&-w+9MO42czC(
zU^0>tx9ey>jcuckn@z=fI`42UaxMl|rcD#DPPAi-C!MtyC{m_%3&mN_X)MuZbDLS907Y$YPOXYdVy;zmM
zu3+qw&&L4?U;aU}HfR4ZzpGQlEz`Y=KQHYK%KdU3TT1Nsw5N1W-F=6pLqdGVlD>U;qW75Es8<;|8KQL$18u+3`>0pC+oxYoZmYAOY91Dt
zI8|4YP0t*q3|+~*il~&SlrF5LYmZ!<%BpP*7|I_iXs;}ij+LL%{bD&<{~2AG@z`P<
z*}ebE6mxTEz1`pjS0fX=uZLpo1xso~A0PBu7@uy&S`fs;J`+K6{7_bhKU&{}{bU?(?P#`}d
z!HbIU(+1D_MKC|lG(*9l*)B9sZLr=vHoN;C3dUdi{7{V^cbnoh<-
zt*}&*HwBF~^1*u1Wd3v!{6iQ}uqYadVof3ukl(Uw?%Nad%hOC&
zf#mJ*UKo-ub%Pd^)nsnI=e%JJQ8X-)X{iQLR)#1mSt~P>Q5B)4q@bk9%*uIAzV&4B
zVb08b42p*O7cal`W%WbC;BoYS@-o-+S0Co)2vaXA4dsQ#ni?XRV^_rEF$hg1S2PN)
zsRmKS!CfKhSXB%JjzhyCSWTQN9Hy>;!Kq?r2l=b{Z>|kVXz!UkV7mUc@G&Gb)BVr1
zLSQi%6joCS4bjxlP-3#gszEeW;V6hJ8izrtE5S5zu%ChEIr}Y;1%iF`NvrP;O4hbCU`0{o9Oeh
zjG1e*m1ie*@2{;t6a@Ti1tFs-RP4;c)CT`pnLkU;&x$f*GrPbMDD+J2L852U7mLw?
z{?a;kSwAhmo8f<-&VNJj&Hp^}zsK-($9l0#|8K5ld;Q%Bm4u`Dq9|BBH)e+X%gX%b
z^;a`i_gc`IT1~+JA4~)l<@3LrhJRaC|1YLtE{oCbC@(iG1_}L#83
z8tTC{RA8DaYO2aGRipnY(f(5KTrn6N8mEq9U-15v!`}k_ddXVQe;e>TE(Rn5iDFK|
zV38{Gt>>EO=4GB0^H)a8Z$C03saD4NAX6g)b!E7^Is~T3ES_^0F|Xe|KNvIuN1_l>
zG$fvga>GK&UT#{@xyE@tXKwxoW))^u1k`NxV|xFsjkUl1Of@BV&-T}VDKQVI^33~p
z)A?#vQwR2@^VO`TbCxz#7UgY3n&xb|J!NmfEy~x4Eo)3$bgNp?Sdy#{SJs%b=
z2Nw$v_96!tdp;~$4lWiT>_rYP_Iy~h99%3w*oz!o?D?>0Ik;GWuopSF*z;l0a&WN#
zVJ~uUvFF30<=|og!d~RyV$X*~%fZD0guTeY#hwp~mV=802z!x(i#;C}Ee9715cVPm
z7kfS|S`IE2AnZjBF7|v_v>aS4K-h~MTyCiIq73_^$(i;6nf~@s)Y*0RV3$0O;KV0Elw{AVG?BDc=GB3zwN1>RJ1>
z7(VSI?HXHMIWm6x6Z7y%(DW(HS1^}p5oGWjV(XDlJ~W8&nkHT^9)UBq`#
zdJ?Et6SOUO36LopDa_rTeMmN(=RhhpcPWg?a=hbK+C5LOET6D^Pw_6AL5}-L?BNKmM~&;h3|ExBu?QU^7N~q4;5#z?
z**vMi?RNK|ma}hnz;Q
z6*mp1{a+JplzQQp2Jf7ZiHT}iPi>`>?--2|cqaT;KR7Mo%ulv>DVvimRn%iS(TA@X
zB&m#)%e|aZl9x@lT|##kXFzRFzN#FO=Do1ulKKYE&Zt1g5>0^sp)I}$@2!w<`
z%r$U{SsZDYwLx@X$5O(oHM{b-Yn}Xujtx-gno*CFMUBMxF~|1d!Pf?RLAW=3mIUD$SCA(?T@?8@3G$HIFr
zCwUNo++W{my$G6IbsMUG$9Qc`CdOA>-puI&Wmqfg*1cx;!x(RoD=DdRUA)2k!YaiG
zMN+=HWap&cYpLanKl}R?X&u+ucVMtrmV!7+O*yI-o|dp-*cZNNL)7}>+q&x=$_fqc
zRWabVxDO_X3f^stE>Ar4Wa^_`tKZ1PvQWqPlvgSqc0DlcOT^jq6I>X-!EVInMRKw6
z3!LJwp^461HaCijqH5mMO-3(Qd|&-a9{pyoTxhFPWZrP;MW}q)Mq22H`fNDkx%+V6
z;_SVnPt^!6#&sT-F5X&}Kenpy?fNiVi?4&%RN5=9e6ox~O&b^(jv^M=9K5`hdUtJ6
zwm_4QLFT;=tucEe9Ym)2T#FX<90=Havu0c;{ID=UbNm`W=$Sh3jQg3X9WucZfs&D?-Eu+@Lke}9aJ|NSbNy((&o`0*Er=e{`d^2D6Y($o+8
z&(#h|f-dFpG8V0nJc&y!PcCXpx4E2hbzlqh?Z{bTTh2OH&p7!^vFlJznHIYppWYp5
zdlp#~Va9cJjmV;nsN@bsN05F?BjV8mBiVJ_k%#xC>C4JRef3#;Wo1*H{;@`g=hl<%
z8i>A|heqs103%Lk@{07bBdr~)XsW#%skOpUf1X6x@c_#dhPKRf^c
literal 0
HcmV?d00001
diff --git a/public/react/src/tpm/challengesnew/TPMMDEditor.js b/public/react/src/tpm/challengesnew/TPMMDEditor.js
new file mode 100644
index 000000000..11b88a037
--- /dev/null
+++ b/public/react/src/tpm/challengesnew/TPMMDEditor.js
@@ -0,0 +1,355 @@
+import React, {Component} from 'react';
+
+import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal} from 'antd';
+
+import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
+
+// import "antd/dist/antd.css";
+
+import { getImageUrl, toPath, getUrl } from 'educoder';
+import '../../courses/css/Courses.css'
+
+import axios from 'axios';
+
+import './css/TPMchallengesnew.css';
+require('codemirror/lib/codemirror.css');
+
+let origin = getUrl();
+
+let path = '/editormd/lib/'
+ path = getUrl("/editormd/lib/")
+const $ = window.$;
+
+let timeout;
+
+let currentValue;
+
+const Option = Select.Option;
+
+const RadioGroup = Radio.Group;
+
+
+
+// 保存数据
+function md_add_data(k,mdu,d){
+ window.sessionStorage.setItem(k+mdu,d);
+}
+
+// 清空保存的数据
+function md_clear_data(k,mdu,id){
+ window.sessionStorage.removeItem(k+mdu);
+ var id1 = "#e_tip_"+id;
+ var id2 = "#e_tips_"+id;
+ if(k == 'content'){
+ $(id2).html(" ");
+ }else{
+ $(id1).html(" ");
+ }
+}
+window.md_clear_data = md_clear_data
+// editor 存在了jquery对象上,应用不需要自己写md_rec_data方法了
+function md_rec_data(k, mdu, id) {
+ if (window.sessionStorage.getItem(k + mdu) !== null) {
+ var editor = $("#e_tips_" + id).data('editor');
+ editor.setValue(window.sessionStorage.getItem(k + mdu));
+ // debugger;
+ // /shixuns/b5hjq9zm/challenges/3977/tab=3 setValue可能导致editor样式问题
+ md_clear_data(k, mdu, id);
+ }
+}
+window.md_rec_data = md_rec_data;
+
+function md_elocalStorage(editor,mdu,id){
+ if (window.sessionStorage){
+ var oc = window.sessionStorage.getItem('content'+mdu);
+ if(oc !== null && oc != editor.getValue()){
+ console.log("#e_tips_"+id)
+ $("#e_tips_"+id).data('editor', editor);
+ var h = '您上次有已保存的数据,是否恢复 ? / 不恢复';
+ $("#e_tips_"+id).html(h);
+ }
+ setInterval(function() {
+ var d = new Date();
+ var h = d.getHours();
+ var m = d.getMinutes();
+ var s = d.getSeconds();
+ h = h < 10 ? '0' + h : h;
+ m = m < 10 ? '0' + m : m;
+ s = s < 10 ? '0' + s : s;
+ if(editor.getValue().trim() != ""){
+ md_add_data("content",mdu,editor.getValue());
+ var id1 = "#e_tip_"+id;
+ var id2 = "#e_tips_"+id;
+
+ var textStart = " 数据已于 "
+ var text = textStart + h + ':' + m + ':' + s +" 保存 ";
+ // 占位符
+ var oldHtml = $(id2).html();
+ if (oldHtml && oldHtml != ' ' && oldHtml.startsWith(textStart) == false) {
+ $(id2).html( oldHtml.split(' (')[0] + ` (${text})`);
+ } else {
+ $(id2).html(text);
+ }
+ // $(id2).html("");
+ }
+ },10000);
+
+ }else{
+ $("#e_tip_"+id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!');
+ }
+}
+
+
+function create_editorMD(id, width, high, placeholder, imageUrl, callback, initValue,
+ onchange, watch, { noStorage, showNullButton, emoji }, that) {
+ // 还是出现了setting只有一份,被共用的问题
+
+ var editorName = window.editormd(id, {
+ width: width,
+ height: high===undefined?400:high,
+ path: path, // "/editormd/lib/"
+ markdown : initValue,
+
+ dialogLockScreen: false,
+ watch:watch===undefined?true:watch,
+ syncScrolling: "single",
+ tex: true,
+ tocm: true,
+ emoji: !!emoji ,
+ taskList: true,
+ codeFold: true,
+ searchReplace: true,
+ htmlDecode: "style,script,iframe",
+ sequenceDiagram: true,
+ autoFocus: false,
+
+ // mine
+
+ toolbarIcons: function (mdEditor) {
+ let react_id = `react_${mdEditor.id}`;
+ const __that = window[react_id]
+
+ // Or return editormd.toolbarModes[name]; // full, simple, mini
+ // Using "||" set icons align right.
+ const icons = ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "link", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"];
+ // 试卷处用到的填空题新增按钮
+ if (__that.props.showNullButton) {
+ icons.push('nullBtton')
+ }
+ return icons
+ },
+ toolbarCustomIcons: {
+ testIcon: "",
+ testIcon1: "",
+ nullBtton: "
点击插入填空项",
+ },
+ //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。
+ saveHTMLToTextarea: true,
+ // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标
+ dialogMaskOpacity: 0.6,
+ placeholder: placeholder,
+ imageUpload: true,
+ imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"],
+ imageUploadURL: imageUrl,//url
+ onchange: onchange,
+ onload: function() {
+ let _id = this.id // 如果要使用this,这里不能使用箭头函数
+ let _editorName = this;
+ let react_id = `react_${_editorName.id}`;
+ const __that = window[react_id]
+
+ // this.previewing();
+ // let _id = id;
+ $("#" + _id + " [type=\"latex\"]").bind("click", function () {
+ _editorName.cm.replaceSelection("```latex");
+ _editorName.cm.replaceSelection("\n");
+ _editorName.cm.replaceSelection("\n");
+ _editorName.cm.replaceSelection("```");
+ var __Cursor = _editorName.cm.getDoc().getCursor();
+ _editorName.cm.setCursor(__Cursor.line - 1, 0);
+ });
+
+ $("#" + _id + " [type=\"inline\"]").bind("click", function () {
+ _editorName.cm.replaceSelection("`$$$$`");
+ var __Cursor = _editorName.cm.getDoc().getCursor();
+ _editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3);
+ _editorName.cm.focus();
+ });
+ $("[type=\"inline\"]").attr("title", "行内公式");
+ $("[type=\"latex\"]").attr("title", "多行公式");
+
+ if (__that.props.showNullButton) {
+ const NULL_CH = '▁'
+ // const NULL_CH = '〇'
+ // const NULL_CH = '🈳'
+
+ $("#" + _id + " [type=\"nullBtton\"]").bind("click", function () {
+ _editorName.cm.replaceSelection(NULL_CH);
+ // var __Cursor = _editorName.cm.getDoc().getCursor();
+ // _editorName.cm.setCursor(__Cursor.line - 1, 0);
+ });
+ }
+
+ if (noStorage == true) {
+
+ } else {
+ md_elocalStorage(_editorName, `MDEditor__${_id}`, _id);
+ }
+
+ callback && callback(_editorName)
+ }
+ });
+ return editorName;
+}
+
+
+export default class TPMMDEditor extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ initValue: ''
+ }
+ }
+ componentDidUpdate(prevProps, prevState) {
+ // 不能加,影响了试卷填空题
+ // if (this.props.initValue != prevProps.initValue) {
+ // this.answers_editormd.setValue(this.props.initValue)
+ // }
+ }
+
+ // react_mdEditor_
+ componentDidMount = () => {
+ const { mdID, initValue, placeholder, showNullButton} = this.props;
+
+ let _id = `mdEditor_${mdID}`
+ this.contentChanged = false;
+ const _placeholder = placeholder || "";
+ // amp;
+ // 编辑时要传memoId
+ const imageUrl = `/api/attachments.json`;
+ // 创建editorMd
+ let react_id = `react_${_id}`;
+ // 将实例存到了window
+ window[react_id] = this
+ const answers_editormd = create_editorMD(_id, '100%', this.props.height, _placeholder, imageUrl, (_editorName) => {
+ const __editorName = _editorName;
+ react_id = `react_${__editorName.id}`;
+ const that = window[react_id]
+
+ // 一个延迟的recreate或resize,不加这段代码,md初始化可能会出现样式问题
+ setTimeout(() => {
+ if (that.props.needRecreate == true) {
+ __editorName.recreate() // 注意 必须在setValue之前触发,不然会清空
+ } else {
+ __editorName.resize()
+ }
+ console.log('timeout', __editorName.id)
+ __editorName.cm && __editorName.cm.refresh()
+ }, that.props.refreshTimeout || 500)
+ if (this.props.noSetValueOnInit) {
+ that.onEditorChange()
+ } else {
+ if (that.props.initValue != undefined && that.props.initValue != '') {
+ __editorName.setValue(that.props.initValue)
+ }
+ if (that.state.initValue) {
+ __editorName.setValue(that.state.initValue)
+ }
+ }
+
+ __editorName.cm.on("change", (_cm, changeObj) => {
+ that.contentChanged = true;
+ if (that.state.showError) {
+ that.setState({showError: false})
+ }
+ that.onEditorChange()
+ })
+ that.props.onCMBlur && __editorName.cm.on('blur', () => {
+ that.props.onCMBlur()
+ })
+ that.props.onCMBeforeChange && __editorName.cm.on('beforeChange', (cm,change) => {
+ that.props.onCMBeforeChange(cm,change)
+ })
+ that.answers_editormd = __editorName;
+ // 这里应该可以去掉了,方便调试加的
+ window[__editorName.id+'_'] = __editorName;
+ }, initValue, this.onEditorChange,this.props.watch, {
+ noStorage: this.props.noStorage,
+ showNullButton: this.props.showNullButton,
+ emoji: this.props.emoji
+ }, this);
+
+ }
+ // 用在form里时,validate失败时出现一个红色边框
+ showError = () => {
+ this.setState({showError: true})
+ }
+ onEditorChange = () => {
+ if (!this.answers_editormd) return;
+ const val = this.answers_editormd.getValue();
+ //console.log('onEditorChange', this.props.id, val)
+ try {
+ this.props.onChange && this.props.onChange(val)
+ } catch(e) {
+ // http://localhost:3007/courses/1309/common_homeworks/6566/setting
+ // 从这个页面,跳转到编辑页面,再在编辑页面点击返回的时候,这里会报错
+ console.error('出错')
+ console.error(e)
+ }
+ }
+ resize = () => {
+ if (!this.answers_editormd) { // 还未初始化
+ return;
+ }
+ this.answers_editormd.resize()
+ this.answers_editormd.cm && this.answers_editormd.cm.refresh()
+ this.answers_editormd.cm.focus()
+ }
+
+ getValue = () => {
+ try {
+ return this.answers_editormd.getValue()
+ } catch (e) {
+ return ''
+ }
+ }
+ setValue = (val) => {
+ try {
+ this.answers_editormd.setValue(val)
+ } catch (e) {
+ // TODO 这里多实例的时候,前一个实例的state会被后面这个覆盖 参考NewWork.js http://localhost:3007/courses/1309/homework/9300/edit/1
+ // 未初始化
+ this.setState({ initValue: val })
+ }
+ }
+
+ render() {
+
+ let {
+ showError
+ } = this.state;
+ let { mdID, className, noStorage, imageExpand } = this.props;
+ let _style = {}
+ if (showError) {
+ _style.border = '1px solid red'
+ }
+ return (
+
+
+ {/* padding10-20 */}
+
+
+
+ {noStorage == true ? ' ' :
}
+ {/* {noStorage == true ? ' ' :
} */}
+
+
+ )
+ }
+}
+
+
diff --git a/public/react/src/tpm/challengesnew/TPManswer.js b/public/react/src/tpm/challengesnew/TPManswer.js
new file mode 100644
index 000000000..bc9523422
--- /dev/null
+++ b/public/react/src/tpm/challengesnew/TPManswer.js
@@ -0,0 +1,366 @@
+import React, {Component} from 'react';
+
+import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal} from 'antd';
+
+import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
+
+// import "antd/dist/antd.css";
+
+import { getImageUrl, toPath, getUrl } from 'educoder';
+
+import axios from 'axios';
+
+import './css/TPMchallengesnew.css';
+
+let origin = getUrl();
+
+let path = getUrl("/editormd/lib/")
+
+const $ = window.$;
+
+let timeout;
+
+let currentValue;
+
+const Option = Select.Option;
+
+const RadioGroup = Radio.Group;
+
+
+// 恢复数据
+function md_rec_data(k,mdu,id, editor){
+ if(window.sessionStorage.getItem(k+mdu) !== null){
+ editor.setValue(window.sessionStorage.getItem(k+mdu));
+ md_clear_data(k,mdu,id);
+ }
+}
+
+// 保存数据
+function md_add_data(k,mdu,d){
+ window.sessionStorage.setItem(k+mdu,d);
+}
+
+// 清空保存的数据
+function md_clear_data(k,mdu,id){
+ window.sessionStorage.removeItem(k+mdu);
+ var id1 = "#e_tip_"+id;
+ var id2 = "#e_tips_"+id;
+ if(k == 'content'){
+ $(id2).html("");
+ }else{
+ $(id1).html("");
+ }
+}
+
+function md_elocalStorage(editor,mdu,id){
+ if (window.sessionStorage){
+ var oc = window.sessionStorage.getItem('content'+mdu);
+ if(oc !== null ){
+ console.log("#e_tips_"+id)
+ $("#e_tips_"+id).data('editor', editor);
+ var h = '您上次有已保存的数据,是否恢复 ? / 不恢复';
+ $("#e_tips_"+id).html(h);
+ }
+ setInterval(function() {
+ var d = new Date();
+ var h = d.getHours();
+ var m = d.getMinutes();
+ var s = d.getSeconds();
+ h = h < 10 ? '0' + h : h;
+ m = m < 10 ? '0' + m : m;
+ s = s < 10 ? '0' + s : s;
+ if(editor.getValue().trim() != ""){
+ md_add_data("content",mdu,editor.getValue());
+ var id1 = "#e_tip_"+id;
+ var id2 = "#e_tips_"+id;
+
+ $(id1).html(" 数据已于 " + h + ':' + m + ':' + s +" 保存 ");
+ $(id2).html("");
+ }
+ },10000);
+
+ }else{
+ $("#e_tip_"+id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!');
+ }
+}
+
+
+function create_editorMD(id, width, high, placeholder, imageUrl, callback) {
+ var editorName = window.editormd(id, {
+ width: width,
+ height: high,
+ path: path, // "/editormd/lib/"
+
+ syncScrolling: "single",
+ tex: true,
+ tocm: true,
+ emoji: true,
+ taskList: true,
+ codeFold: true,
+ searchReplace: true,
+ htmlDecode: "style,script,iframe",
+ sequenceDiagram: true,
+ autoFocus: false,
+ toolbarIcons: function () {
+ // Or return editormd.toolbarModes[name]; // full, simple, mini
+ // Using "||" set icons align right.
+ return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"]
+ },
+ toolbarCustomIcons: {
+ testIcon: "",
+ testIcon1: ""
+ },
+ //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。
+ saveHTMLToTextarea: true,
+ // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标
+ dialogMaskOpacity: 0.6,
+ placeholder: placeholder,
+ imageUpload: true,
+ imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"],
+ imageUploadURL: imageUrl,//url
+ onload: function () {
+ // this.previewing();
+ $("#" + id + " [type=\"latex\"]").bind("click", function () {
+ editorName.cm.replaceSelection("```latex");
+ editorName.cm.replaceSelection("\n");
+ editorName.cm.replaceSelection("\n");
+ editorName.cm.replaceSelection("```");
+ var __Cursor = editorName.cm.getDoc().getCursor();
+ editorName.cm.setCursor(__Cursor.line - 1, 0);
+ });
+
+ $("#" + id + " [type=\"inline\"]").bind("click", function () {
+ editorName.cm.replaceSelection("`$$$$`");
+ var __Cursor = editorName.cm.getDoc().getCursor();
+ editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3);
+ editorName.cm.focus();
+ });
+ $("[type=\"inline\"]").attr("title", "行内公式");
+ $("[type=\"latex\"]").attr("title", "多行公式");
+
+ md_elocalStorage(editorName, `answers__${id}`, "Memoanswers");
+
+ callback && callback()
+ }
+ });
+ return editorName;
+}
+
+
+export default class TPManswer extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ choice_url: undefined,
+ practice_url: undefined,
+ go_back_url: undefined,
+ value: 1,
+ answer:"",
+ id:undefined,
+ checkpointId:undefined,
+ power: false,
+ prev_challenge: undefined,
+ next_challenge: undefined,
+ }
+ }
+
+ answerMD(initValue, id) {
+
+ this.contentChanged = false;
+ const placeholder = "";
+ // amp;
+ // 编辑时要传memoId
+ const imageUrl = `/api/attachments.json`;
+ // 创建editorMd
+
+ const answers_editormd = create_editorMD(id, '100%', 400, placeholder, imageUrl, () => {
+ setTimeout(() => {
+ answers_editormd.resize()
+ answers_editormd.cm && answers_editormd.cm.refresh()
+ }, 500)
+
+ if (initValue != undefined) {
+ answers_editormd.setValue(initValue)
+ }
+ answers_editormd.cm.on("change", (_cm, changeObj) => {
+ console.log('....contentChanged')
+ this.contentChanged = true;
+ })
+ });
+ this.answers_editormd = answers_editormd;
+ window.answers_editormd = answers_editormd;
+
+ }
+
+ componentDidMount() {
+ let id = this.props.match.params.shixunId;
+ let checkpointId=this.props.match.params.checkpointId;
+
+ let newchoice_url= "/shixuns/"+id+"/challenges/newquestion";
+ let newpractice_url= "/shixuns/"+id+"/challenges/new";
+ let newgo_back_url="/shixuns/"+id+"/challenges";
+ this.setState({
+ shixunId:id,
+ checkpointId:checkpointId
+ })
+
+
+ let url = "/shixuns/" + id + "/challenges/" + checkpointId + "/edit.json?tab=2";
+ axios.get(url).then((response) => {
+ let newprev_challenge = response.data.prev_challenge;
+ let next_challenge = response.data.next_challenge;
+ if (newprev_challenge != undefined) {
+ if(newprev_challenge.st===0){
+ newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint";
+ }else{
+ newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion";
+ }
+ }
+ if (next_challenge != undefined) {
+
+ if(next_challenge.st===0){
+ next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint";
+ }else{
+ next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion";
+ }
+ }
+ this.setState({
+ answer:response.data.answer,
+ power: response.data.power,
+ choice_url: newchoice_url, // 导航中的新建选择题url
+ practice_url: newpractice_url, //string 导航中新建实践题url
+ go_back_url: newgo_back_url, //string 导航中的返回url
+ position: response.data.position, //int 关卡位置,导航栏中的第几关
+ prev_challenge: newprev_challenge,
+ next_challenge: next_challenge,
+ })
+
+ if(response.data.power===false){
+ this.props.showSnackbar("没有权限修改");
+ }
+ if(response.data.answer===undefined||response.data.answer===null){
+ this.answerMD("", "answerMD");
+ }else{
+ this.answerMD(response.data.answer, "answerMD");
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ challenge_answer_submit=()=> {
+ let id = this.props.match.params.shixunId;
+ let{checkpointId}=this.state;
+ let url = "/shixuns/"+id+"/challenges/"+checkpointId+".json";
+ const answer_editormdvalue = this.answers_editormd.getValue();
+
+ axios.put(url,{
+ tab:2,
+ identifier:id,
+ id:checkpointId,
+ challenge:{
+ answer:answer_editormdvalue
+ }
+ }
+ ).then((response) => {
+ this.props.showSnackbar(response.data.messages);
+
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ render() {
+
+ let {
+ choice_url,
+ practice_url,
+ go_back_url,
+ position,
+ task_pass_default,
+ submit_url,
+ shixunId,
+ checkpointId,
+ power,
+ prev_challenge,
+ next_challenge,
+ } = this.state;
+ let tab1url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/editcheckpoint";
+ let tab2url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=2";
+ let tab3url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=3";
+ // console.log(this.props)
+ return (
+
+
+
+
+
+
+
第{position}关
+
返回
+
+ {prev_challenge === undefined ? "" :
+
上一关
+ }
+
+ {next_challenge === undefined ? "" :
+
下一关
+ }
+
+
+ 实践类型
+
+ 选择题类型
+
+
+
+
+
+
+ 本关任务
+
+
+
+ 评测设置
+
+
+
+ 参考答案
+
+
+
+
+
+
4||this.props.identity===undefined||power===false?"none":"block"}}>
+
提交
+
取消
+
+
+
+ )
+ }
+}
+
+
diff --git a/public/react/src/tpm/challengesnew/TPManswer2.js b/public/react/src/tpm/challengesnew/TPManswer2.js
new file mode 100644
index 000000000..6cbfcd081
--- /dev/null
+++ b/public/react/src/tpm/challengesnew/TPManswer2.js
@@ -0,0 +1,368 @@
+import React, {Component} from 'react';
+
+import {Input, InputNumber, Select, Radio, Checkbox, Popconfirm, message, Modal, Tooltip} from 'antd';
+
+import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
+
+// import "antd/dist/antd.css";
+
+import { getImageUrl, toPath, getUrl } from 'educoder';
+
+import axios from 'axios';
+
+import './css/TPMchallengesnew.css';
+
+import TPMMDEditor from './TPMMDEditor';
+
+
+let origin = getUrl();
+
+let path = getUrl("/editormd/lib/")
+
+const $ = window.$;
+
+let timeout;
+
+let currentValue;
+
+const Option = Select.Option;
+
+const RadioGroup = Radio.Group;
+
+// const testAnswers = [{
+// "id": 4337,
+// "name": "解题思路1",
+// "contents": "答案的解题思路1",
+// "level": 1,
+// "score": 25
+// },
+// {
+// "id": 4338,
+// "name": "解题思路2",
+// "contents": "答案的解题思路2",
+// "level": 2,
+// "score": 25
+// }]
+export default class TPManswer extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ choice_url: undefined,
+ practice_url: undefined,
+ go_back_url: undefined,
+ value: 1,
+ answer:"",
+ id:undefined,
+ checkpointId:undefined,
+ power: false,
+ prev_challenge: undefined,
+ next_challenge: undefined,
+ answers: [] //testAnswers
+ }
+ }
+
+ componentDidMount() {
+ let id = this.props.match.params.shixunId;
+ let checkpointId=this.props.match.params.checkpointId;
+
+ let newchoice_url= "/shixuns/"+id+"/challenges/newquestion";
+ let newpractice_url= "/shixuns/"+id+"/challenges/new";
+ let newgo_back_url="/shixuns/"+id+"/challenges";
+ this.setState({
+ shixunId:id,
+ checkpointId:checkpointId
+ })
+
+
+ let url = "/shixuns/" + id + "/challenges/" + checkpointId + "/edit.json?tab=2";
+ axios.get(url).then((response) => {
+ let newprev_challenge = response.data.prev_challenge;
+ let next_challenge = response.data.next_challenge;
+ if (newprev_challenge != undefined) {
+ if(newprev_challenge.st===0){
+ newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint";
+ }else{
+ newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion";
+ }
+ }
+ if (next_challenge != undefined) {
+
+ if(next_challenge.st===0){
+ next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint";
+ }else{
+ next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion";
+ }
+ }
+ this.setState({
+ answer:response.data.answer,
+ power: response.data.power,
+ choice_url: newchoice_url, // 导航中的新建选择题url
+ practice_url: newpractice_url, //string 导航中新建实践题url
+ go_back_url: newgo_back_url, //string 导航中的返回url
+ position: response.data.position, //int 关卡位置,导航栏中的第几关
+ prev_challenge: newprev_challenge,
+ next_challenge: next_challenge,
+ })
+
+ if(response.data.power===false){
+ this.props.showSnackbar("没有权限修改");
+ }
+ // if(response.data.answer===undefined||response.data.answer===null){
+ // this.answerMD("", "answerMD");
+ // }else{
+ // this.answerMD(response.data.answer, "answerMD");
+ // }
+
+ }).catch((error) => {
+ console.log(error)
+ });
+
+
+ let urlAnswer = `/shixuns/${id}/challenges/${checkpointId}/answer.json`;
+ axios.get(urlAnswer).then((response) => {
+ if (response.data.status === 401) {
+
+ } else if (response.data) {
+ this.setState({ answers: response.data })
+ }
+ })
+ }
+
+ challenge_answer_submit=()=> {
+ // `levelSection${index}`
+ // this.refs.md0
+ const { answers } = this.state;
+ const answersParams = answers.slice(0)
+ console.log(answersParams)
+ let isValidate = true;
+ let totalScore = 0;
+ answersParams.forEach( (item, index) => {
+ if (!isValidate) {
+ return;
+ }
+ const sectionId = `#levelSection${index}`;
+ const mdContnet = this.refs[`md${index}`].getValue().trim();;
+ item.contents = mdContnet;
+ item.name = item.name.trim()
+ totalScore += item.score;
+ delete item.id;
+ if (!item.name) {
+ this.props.showSnackbar("请先填写参考答案名称");
+ isValidate = false;
+ } else if (!mdContnet) {
+ this.props.showSnackbar("请先填写参考答案内容");
+ isValidate = false;
+ }
+ if (!isValidate) {
+ $("html, body").animate({ scrollTop: $(`${sectionId}`).offset().top - 100})
+ }
+ })
+ if (!isValidate) {
+ return;
+ }
+ if (answersParams.length != 0 && totalScore != 100) {
+ this.props.showSnackbar("请先保证占比和为100%");
+ return;
+ }
+ let id = this.props.match.params.shixunId;
+ let {checkpointId} = this.state;
+ let url = `/shixuns/${id}/challenges/${checkpointId}/crud_answer.json`;
+
+ axios.post(url,{
+ challenge_answer: answersParams
+ }
+ ).then((response) => {
+ if (response.data) {
+ if (response.data.message) {
+ this.props.showSnackbar(response.data.message);
+ }
+ if (response.data.status == 1) {
+ $("html").animate({ scrollTop: 0 })
+ }
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+ onNameChange = (e, index) => {
+ const newAnswer = Object.assign({}, this.state.answers[index])
+ newAnswer.name = e.target.value
+ const newAnswers = this.state.answers.slice(0)
+ newAnswers[index] = newAnswer
+ this.setState({ answers: newAnswers})
+ }
+ onScoreChange = (val, index) => {
+ const newAnswer = Object.assign({}, this.state.answers[index])
+ newAnswer.score = val
+ const newAnswers = this.state.answers.slice(0)
+ newAnswers[index] = newAnswer
+ this.setState({ answers: newAnswers})
+ }
+ answerOnChange = (val, index) => {
+ if (!this.state.answers[index]) {
+ // 1、2、3删除2会走到这里
+ return;
+ }
+ const newAnswer = Object.assign({}, this.state.answers[index])
+ newAnswer.contents = val
+ const newAnswers = this.state.answers.slice(0)
+ newAnswers[index] = newAnswer
+ this.setState({ answers: newAnswers})
+ }
+ addAnswer = () => {
+ const newAnswers = this.state.answers.slice(0)
+ newAnswers.push({
+ "name": `解题思路${newAnswers.length + 1}`,
+ "contents": "",
+ "score": 10
+ })
+ this.setState({ answers: newAnswers })
+ }
+
+ delanswers=(index)=>{
+ let {answers}=this.state;
+ let newanswers=answers;
+ newanswers.splice(index,1)
+ this.setState({
+ answers:newanswers
+ }, () => {
+ for(let i = index; i < newanswers.length; i ++) {
+ this.refs[`md${i}`].setValue(newanswers[i].contents)
+ }
+ })
+ }
+ render() {
+
+ let {
+ choice_url,
+ practice_url,
+ go_back_url,
+ position,
+ task_pass_default,
+ submit_url,
+ shixunId,
+ checkpointId,
+ power,
+ prev_challenge,
+ next_challenge,
+ answers,
+ } = this.state;
+ let tab1url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/editcheckpoint";
+ let tab2url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=2";
+ let tab3url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=3";
+ // console.log(this.props)
+ return (
+
+
+
+
+
+
+
第{position}关
+
返回
+
+ {prev_challenge === undefined ? "" :
+
上一关
+ }
+
+ {next_challenge === undefined ? "" :
+
下一关
+ }
+
+
+ 实践类型
+
+ 选择题类型
+
+
+
+
+
+
+ 本关任务
+
+
+
+ 评测设置
+
+
+
+ 参考答案
+
+
+
+
+
+
+
+ 可以将参考答案分级设置,让学员自行选择级别,每级查看后按照比例扣分值(学员已完成任务再查看,则不影响原因已获得的成绩)
+
+
+ 示例:级别1,扣减分值占比25%;级别2,扣减分值占比35%;级别3,扣减分值占比40%;则学员选择查看级别1的答案,将被扣减25%的分值;
+ 选择查看级别2的答案,将被扣减60%的分值;选择查看级别3的答案,将被扣减100%的分值。
+
+
+
+
+ {
+ answers.map((answer, index) => {
+ return
+
*
+
级别{index + 1}
+
+ this.delanswers(index)}>
+
+
+
+
+
+ 名称:
+ this.onNameChange(e, index)}>
+
+ 扣减分值占比:
+ this.onScoreChange(e, index)} >%
+
+
+ 参考答案:
+ this.answerOnChange(val, index)}>
+
+
+
+ })
+ }
+
+
4||this.props.identity===undefined||power===false?"none":"block"}}>
+
新增
+
+
+
+
+
+
+
4||this.props.identity===undefined||power===false?"none":"block"}}>
+
提交
+
取消
+
+
+
+ )
+ }
+}
+
+
diff --git a/public/react/src/tpm/challengesnew/TPMchallengesnew.js b/public/react/src/tpm/challengesnew/TPMchallengesnew.js
new file mode 100644
index 000000000..9da0b79f5
--- /dev/null
+++ b/public/react/src/tpm/challengesnew/TPMchallengesnew.js
@@ -0,0 +1,615 @@
+import React, {Component} from 'react';
+
+import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal} from 'antd';
+
+import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
+
+// import "antd/dist/antd.css";
+
+import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
+
+import axios from 'axios';
+
+import './css/TPMchallengesnew.css';
+
+import { getImageUrl, toPath } from 'educoder';
+
+import {getUrl} from 'educoder';
+
+let origin = getUrl();
+
+let path = getUrl("/editormd/lib/")
+
+const $ = window.$;
+
+let timeout;
+
+let currentValue;
+
+const Option = Select.Option;
+
+const RadioGroup = Radio.Group;
+
+export default class TPMchallengesnew extends Component {
+ constructor(props) {
+ super(props)
+ this.exercisememoMDRef=React.createRef();
+ this.state = {
+ choice_url: undefined,
+ practice_url: undefined,
+ go_back_url: undefined,
+ task_pass_default: undefined,
+ submit_url: undefined,
+ shixunCreatePracticeGroup: 1,
+ optionsums:[100,200],
+ activetype:0,
+ setopen: false,
+ shixunCreatePractice: undefined,
+ onshixunsmarkvalue: 100,
+ shixunsskillvalue: undefined,
+ shixunsskillvaluelist: [],
+ tab2url: "",
+ tab3url: "",
+ prev_challenge:undefined,
+ next_challenge:undefined,
+ power: false,
+ shixunCreatePracticetype: false,
+ shixunsskillvaluelisttype: false,
+ marktype:false,
+ editPracticesendtype:false,
+ CreatePracticesendtype:false,
+ exec_time:20,
+ shixunExec_timeType:false
+ }
+ }
+
+
+ componentDidMount() {
+ let id = this.props.match.params.shixunId;
+ let checkpointId=this.props.match.params.checkpointId;
+
+ let newchoice_url= "/shixuns/"+id+"/challenges/newquestion";
+ let newpractice_url= "/shixuns/"+id+"/challenges/new";
+ let newgo_back_url="/shixuns/"+id+"/challenges"
+ if(checkpointId===undefined){
+ //新建模式
+ let url = "/shixuns/" + id + "/challenges/new.json"
+ axios.get(url).then((response) => {
+ this.setState({
+ choice_url: newchoice_url,
+ practice_url: newpractice_url,
+ go_back_url: newgo_back_url,
+ position: response.data.position,
+ task_pass_default: response.data.task_pass_default,
+ submit_url: response.data.submit_url,
+ checkpointId:checkpointId,
+ exercisememoMDRefval:response.data.task_pass_default
+ })
+
+ this.exercisememoMDRef.current.setValue(response.data.task_pass_default||'')
+ }).catch((error) => {
+ console.log(error)
+ });
+ }else{
+ //编辑模式
+ let url="/shixuns/"+id+"/challenges/"+checkpointId+".json?tab=0";
+ axios.get(url).then((response) => {
+
+ let optionsum;
+ if(response.data.difficulty===1){
+ optionsum=[100,200];
+ }else if(response.data.difficulty===2){
+ optionsum=[300,400,500,600];
+ }else if(response.data.difficulty===3){
+ optionsum=[700,800,900,1000]
+ }
+ let newprev_challenge=response.data.prev_challenge;
+ let next_challenge=response.data.next_challenge;
+ if (newprev_challenge != undefined) {
+ if(newprev_challenge.st===0){
+ newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint";
+ }else{
+ newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion";
+ }
+ }
+ if (next_challenge != undefined) {
+ if(next_challenge.st===0){
+ next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint";
+ }else{
+ next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion";
+ }
+ }
+ this.setState({
+ power: response.data.power,
+ prev_challenge:newprev_challenge,
+ next_challenge:next_challenge,
+ choice_url: newchoice_url,
+ practice_url: newpractice_url,
+ go_back_url: newgo_back_url,
+ shixunCreatePractice:response.data.subject,
+ position:response.data.position,
+ shixunCreatePracticeGroup:response.data.difficulty,
+ optionsums:optionsum,
+ onshixunsmarkvalue:response.data.score,
+ shixunsskillvaluelist:response.data.tags,
+ checkpointId:checkpointId,
+ exec_time:response.data.exec_time,
+ tab2url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=2",
+ tab3url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=3",
+ exercisememoMDRefval:response.data.task_pass
+ })
+ if(response.data.power===false){
+ this.props.showSnackbar("你没有权限修改");
+ }
+
+ this.exercisememoMDRef.current.setValue(response.data.task_pass||'')
+ }).catch((error) => {
+ console.log(error)
+ });
+
+ }
+
+ }
+
+ onshixunCreatePracticeChange = (e) => {
+ let optionsum;
+ let onshixunsmark;
+ if(e.target.value===1){
+ optionsum=[100,200];
+ onshixunsmark=100;
+ }else if(e.target.value===2){
+ optionsum=[300,400,500,600];
+ onshixunsmark=300;
+ }else if(e.target.value===3){
+ optionsum=[700,800,900,1000]
+ onshixunsmark=700;
+ }
+ this.setState({
+ shixunCreatePracticeGroup: e.target.value,
+ optionsums:optionsum,
+ onshixunsmarkvalue:onshixunsmark
+ })
+ }
+
+ shixunCreatePractice = (e) => {
+ this.setState({
+ shixunCreatePractice: e.target.value
+ })
+ }
+
+ CreatePracticesend = () => {
+
+
+ this.setState({
+ CreatePracticesendtype:true
+ })
+
+ if(this.props.status===2){
+ this.props.showSnackbar("该实训已经发布不能新建")
+ this.setState({
+ CreatePracticesendtype:false
+ })
+ return
+ }
+ let {shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvaluelist,exec_time} = this.state;
+ if (shixunCreatePractice === undefined||shixunCreatePractice=="") {
+ this.setState({
+ shixunCreatePracticetype: true
+ })
+ this.props.showSnackbar("任务名称为空")
+ $('html').animate({
+ scrollTop: 10
+ }, 1000);
+
+ this.setState({
+ CreatePracticesendtype:false
+ })
+ return
+ }
+
+ if (shixunsskillvaluelist.length === 0) {
+ this.setState({
+ shixunsskillvaluelisttype: true,
+ CreatePracticesendtype:false
+ })
+ this.props.showSnackbar("技能标签为空")
+ return
+ }
+ if(exec_time===null||exec_time===undefined||exec_time===""){
+
+ this.setState({
+ shixunExec_timeType:false
+ })
+ return
+ }
+
+ const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim();
+ let id = this.props.match.params.shixunId;
+
+ let url = "/shixuns/" + id + "/challenges.json";
+
+ axios.post(url, {
+ identifier:id,
+ subject: shixunCreatePractice,
+ task_pass: exercise_editormdvalue,
+ difficulty: shixunCreatePracticeGroup,
+ score: onshixunsmarkvalue,
+ challenge_tag: shixunsskillvaluelist,
+ st: 0,
+ exec_time:exec_time
+ }).then((response) => {
+ if (response.data.status === 1) {
+ // $("html").animate({ scrollTop: 0 })
+
+ window.location.href=`/shixuns/${id}/challenges/${response.data.challenge_id}/editcheckpoint`;
+ // this.setState({
+ // setopen: true,
+ // CreatePracticesendtype:false,
+ // tab2url: "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=2",
+ // tab3url: "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=3",
+ // })
+
+ }
+ // this.props.showSnackbar(response.data.messages);
+ }).catch((error) => {
+ console.log(error)
+ });
+
+
+
+ }
+
+ onshixunsmark = (value) => {
+ this.setState({
+ onshixunsmarkvalue: value
+ })
+ }
+
+ shixunsskill = (e) => {
+ this.setState({
+ shixunsskillvalue: e.target.value
+ })
+ }
+
+ clickshixunsskill = () => {
+
+ let {shixunsskillvalue, shixunsskillvaluelist} = this.state;
+ if (shixunsskillvalue === "") {
+ return
+ } else if (shixunsskillvalue === undefined) {
+ return
+ }
+
+ if(shixunsskillvalue == "" || shixunsskillvalue == undefined || shixunsskillvalue == null || (shixunsskillvalue.length>0 && shixunsskillvalue.trim().length == 0)){
+ message.error("输入为空,不能保存!");
+ return
+ }
+
+ let list = shixunsskillvaluelist;
+ list.push(shixunsskillvalue);
+ this.setState({
+ shixunsskillvaluelist: list,
+ shixunsskillvalue: ""
+ })
+ }
+
+ delshixunsskilllist = (key) => {
+ let {shixunsskillvaluelist} = this.state;
+ let newshixunsskillvaluelist = shixunsskillvaluelist;
+ newshixunsskillvaluelist.splice(key, 1);
+ this.setState({
+ shixunsskillvaluelist: newshixunsskillvaluelist
+ })
+ }
+
+ editPracticesend=()=>{
+
+ this.setState({
+ editPracticesendtype:true
+ })
+
+ let {shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvaluelist,checkpointId,exec_time} = this.state;
+
+ const exercise_editormdvalue = this.exercisememoMDRef.current.getValue().trim();
+
+ let id = this.props.match.params.shixunId;
+
+ let url = "/shixuns/"+id+"/challenges/"+checkpointId+".json";
+
+ if (shixunCreatePractice === undefined||shixunCreatePractice=="") {
+ // this.setState({
+ // shixunCreatePracticetype: true
+ // })
+ this.props.showSnackbar("任务名称为空")
+ $('html').animate({
+ scrollTop: 10
+ }, 1000);
+ this.setState({
+ editPracticesendtype:false
+ })
+ return
+ }
+
+ if (shixunsskillvaluelist.length === 0) {
+ // this.setState({
+ // shixunsskillvaluelisttype: true
+ // })
+ this.props.showSnackbar("技能标签为空")
+ this.setState({
+ editPracticesendtype:false
+ })
+ return
+ }
+
+ if(exec_time===null||exec_time===undefined||exec_time===""){
+
+ this.setState({
+ shixunExec_timeType:false
+ })
+ return
+ }
+ axios.put(url, {
+ tab:0,
+ identifier:id,
+ id:checkpointId,
+ challenge:{
+ subject: shixunCreatePractice,
+ task_pass: exercise_editormdvalue,
+ difficulty: shixunCreatePracticeGroup,
+ score: onshixunsmarkvalue,
+ exec_time:exec_time
+ },
+ challenge_tag:shixunsskillvaluelist
+ }).then((response) => {
+ this.props.showSnackbar(response.data.messages);
+ if (response.data.status === 1) {
+ this.setState({
+ setopen: true,
+ editPracticesendtype:false,
+ tab2url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=2",
+ tab3url: "/shixuns/" + id + "/challenges/"+checkpointId+"/tab=3",
+ })
+ // window.location.href = "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=2"
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+
+
+ }
+
+ onshixunsmarks=()=> {
+ this.setState({
+ marktype:true
+ })
+ }
+
+ onshixunsmarkss=()=> {
+ this.setState({
+ marktype:false
+ })
+ }
+
+ setexec_time=(e)=>{
+ this.setState({
+ exec_time:e.target.value
+ })
+ }
+ render() {
+
+ let shixuntype = this.props.match.params.type;
+
+
+ let {marktype,
+ shixunCreatePracticetype, shixunsskillvaluelisttype,
+ choice_url, practice_url, go_back_url, position, task_pass_default, submit_url, setopen,checkpointId,prev_challenge,next_challenge,power,
+ shixunCreatePractice, shixunCreatePracticeGroup, onshixunsmarkvalue, shixunsskillvalue, shixunsskillvaluelist, tab2url, tab3url,optionsums,
+ CreatePracticesendtype,editPracticesendtype
+ } = this.state;
+
+ let options;
+ if(optionsums!=undefined){
+ options = optionsums.map((d, k) => {
+ return (
+
+ )
+ })
+ }
+
+ return (
+
+
+
+
+
+
+
+ 本关任务
+
+
+
+ {tab2url === "" ? 评测设置 : 评测设置}
+
+
+
+ {tab3url === "" ? 参考答案 : 参考答案}
+
+
+
+
+
+
+
+
+
+
+
+
难度系数
+
+
+
+ 简单
+ 中等
+ 困难
+
+
+
+
奖励经验值
+
+
*
+
+
+
+
+ 如果学员答题错误,则不能得到相应的经验值
+ 如果学员成功得到经验值,那么将同时获得等值的金币奖励,如:+10经验值、+10金币
+
+
+
必填项
+
+
+
+
+
+
技能标签
+
+
*
+
+
+ {/*
+ 添加*/}
+
学员答题正确将获得技能,否则不能获得技能
+
+
+ {
+ shixunsskillvaluelist===undefined?"":shixunsskillvaluelist.length === 0 ? "" : shixunsskillvaluelist.map((itme, key) => {
+ return (
+
{itme}
+ this.delshixunsskilllist(key)}>×
+
+ )
+ })
+ }
+
+
+
+
+
+ 必填项
+
+
+
+
+
服务配置
+
+
*
+
+
+
+
+
必填项
+
+
+
+
+
4||this.props.identity===undefined?"none":'block'}}
+ >
+ {checkpointId===undefined?
提交:
+
提交}
+
取消
+
+
+
+ )
+ }
+}
+
+
diff --git a/public/react/src/tpm/challengesnew/TPMevaluation.js b/public/react/src/tpm/challengesnew/TPMevaluation.js
new file mode 100644
index 000000000..f29e9311e
--- /dev/null
+++ b/public/react/src/tpm/challengesnew/TPMevaluation.js
@@ -0,0 +1,1213 @@
+import React, {Component} from 'react';
+
+import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Button,Icon,Tooltip} from 'antd';
+
+import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
+
+// import "antd/dist/antd.css";
+
+import axios from 'axios';
+
+import { getImageUrl, toPath } from 'educoder';
+
+import './css/TPMchallengesnew.css';
+
+import {getUrl} from 'educoder';
+
+let origin = getUrl();
+
+let path = getUrl("/editormd/lib/")
+
+const $ = window.$;
+
+let timeout;
+
+let currentValue;
+
+const Option = Select.Option;
+
+const RadioGroup = Radio.Group;
+
+const { TextArea } = Input;
+
+function create_editorMD(id, width, high, placeholder, imageUrl, callback) {
+ var editorName = window.editormd(id, {
+ width: width,
+ height: high,
+ path: path, // "/editormd/lib/"
+
+ syncScrolling: "single",
+ tex: true,
+ tocm: true,
+ emoji: true,
+ taskList: true,
+ codeFold: true,
+ searchReplace: true,
+ htmlDecode: "style,script,iframe",
+ sequenceDiagram: true,
+ autoFocus: false,
+ toolbarIcons: function () {
+ // Or return editormd.toolbarModes[name]; // full, simple, mini
+ // Using "||" set icons align right.
+ return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"]
+ },
+ toolbarCustomIcons: {
+ testIcon: "",
+ testIcon1: ""
+ },
+ //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。
+ saveHTMLToTextarea: true,
+ // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标
+ dialogMaskOpacity: 0.6,
+ placeholder: placeholder,
+ imageUpload: true,
+ imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"],
+ imageUploadURL: imageUrl,//url
+ onload: function () {
+ // this.previewing();
+ $("#" + id + " [type=\"latex\"]").bind("click", function () {
+ editorName.cm.replaceSelection("```latex");
+ editorName.cm.replaceSelection("\n");
+ editorName.cm.replaceSelection("\n");
+ editorName.cm.replaceSelection("```");
+ var __Cursor = editorName.cm.getDoc().getCursor();
+ editorName.cm.setCursor(__Cursor.line - 1, 0);
+ });
+
+ $("#" + id + " [type=\"inline\"]").bind("click", function () {
+ editorName.cm.replaceSelection("`$$$$`");
+ var __Cursor = editorName.cm.getDoc().getCursor();
+ editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3);
+ editorName.cm.focus();
+ });
+ $("[type=\"inline\"]").attr("title", "行内公式");
+ $("[type=\"latex\"]").attr("title", "多行公式");
+
+ window.md_elocalStorage(editorName, `exercise__${id}`, "Memochallengesnew");
+
+ callback && callback()
+ }
+ });
+ return editorName;
+}
+
+
+export default class TPMevaluation extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ choice_url: undefined,
+ practice_url: undefined,
+ go_back_url: undefined,
+ task_pass_default: undefined,
+ submit_url: undefined,
+ value: 1,
+ evaluationlist:[],
+ shixunId:undefined,
+ power:false,
+ shixunfilepath:undefined,
+ evaluationvisible:false,
+ trees:undefined,
+ path:"",
+ main:[],
+ saveshixunfilepath:undefined,
+ selectpath:undefined,
+ shixunfilepathplay:undefined,
+ shixunfileexpectpicturepath:undefined,
+ shixunfilestandardpicturepath:undefined,
+ shixunfilepicturepath:undefined,
+ pathoptionvalue:-1,
+ showrepositoryurltiptype: false,
+ prev_challenge: undefined,
+ next_challenge: undefined,
+ StudentTaskPapers:false,
+ StudentTaskDocs:false,
+ selectpatharr:[],
+ handpathopt:false,
+ scorevalue:false,
+ markvalue:true,
+ scoretype:undefined,
+ web_route:null
+ }
+ }
+
+
+ exerciseMD(initValue, id) {
+
+ this.contentChanged = false;
+ const placeholder = "";
+// amp;
+// 编辑时要传memoId
+ const imageUrl = `/api/attachments.json`;
+// 创建editorMd
+
+ const exercise_editormd = create_editorMD(id, '100%', 400, placeholder, imageUrl, () => {
+ setTimeout(() => {
+ exercise_editormd.resize()
+ exercise_editormd.cm && exercise_editormd.cm.refresh()
+ }, 500)
+
+ if (initValue != undefined) {
+ exercise_editormd.setValue(initValue)
+ }
+ exercise_editormd.cm.on("change", (_cm, changeObj) => {
+ console.log('....contentChanged')
+ this.contentChanged = true;
+ })
+ });
+ this.exercise_editormd = exercise_editormd;
+ window.exercise_editormd = exercise_editormd;
+
+ }
+
+ componentDidMount() {
+ let id = this.props.match.params.shixunId;
+ let checkpointId=this.props.match.params.checkpointId;
+ this.setState({
+ shixunId:id,
+ checkpointId:checkpointId
+ })
+ let newchoice_url= "/shixuns/"+id+"/challenges/newquestion";
+ let newpractice_url= "/shixuns/"+id+"/challenges/new";
+ let newgo_back_url="/shixuns/"+id+"/challenges";
+
+ let url = "/shixuns/" + id + "/challenges/" + checkpointId + "/edit.json?tab=1";
+ axios.get(url).then((response) => {
+ let newprev_challenge = response.data.prev_challenge;
+ let next_challenge = response.data.next_challenge;
+ if (newprev_challenge != undefined) {
+ if(newprev_challenge.st===0){
+ newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint";
+ }else{
+ newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion";
+ }
+ }
+ if (next_challenge != undefined) {
+
+ if(next_challenge.st===0){
+ next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint";
+ }else{
+ next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion";
+ }
+ }
+ let newevaluationlist=[]
+ if(response.data.test_sets.length===0){
+ let newlist=[
+ {hidden:0,input:"",output:"",score:50},
+ {hidden:0,input:"",output:"",score:50}
+ ]
+ newevaluationlist=newlist
+ }else{
+ newevaluationlist=response.data.test_sets
+ }
+
+ this.setState({
+ power: response.data.power,
+ evaluationlist:newevaluationlist,
+ shixunfilepath:response.data.path,
+ shixunfilepathplay:response.data.exec_path,
+ pathoptionvalue:response.data.show_type,
+ shixunfileexpectpicturepath:response.data.original_picture_path,
+ shixunfilestandardpicturepath:response.data.expect_picture_path,
+ shixunfilepicturepath:response.data.picture_path,
+ prev_challenge: newprev_challenge,
+ next_challenge: next_challenge,
+ choice_url: newchoice_url, // 导航中的新建选择题url
+ practice_url: newpractice_url, //string 导航中新建实践题url
+ go_back_url: newgo_back_url, //string 导航中的返回url
+ position: response.data.position, //int 关卡位置,导航栏中的第几关
+ scorevalue:response.data.test_set_score,
+ markvalue:response.data.test_set_average,
+ web_route:response.data.web_route,
+ has_web_route:response.data.has_web_route
+ })
+ this.evaluationoninputvalueonload();
+ if(response.data.power===false){
+ this.props.showSnackbar("你没有权限修改");
+ }
+ if(response.data.answer===undefined){
+ this.answerMD("", "answerMD");
+ }else{
+ this.answerMD(response.data.answer, "answerMD");
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ });
+
+ }
+
+
+ setevaluationlist=(newevaluationlist)=>{
+ this.setState({
+ evaluationlist:newevaluationlist
+ })
+ console.log(newevaluationlist)
+ }
+
+
+ addevaluationon=()=>{
+ let {evaluationlist,markvalue}=this.state;
+ let newevaluationlist=evaluationlist;
+ newevaluationlist.push({hidden:0,input:"",output:"",score:0});
+ newevaluationlist=this.oneditevaluationlist(newevaluationlist,markvalue);
+ this.setevaluationlist(newevaluationlist);
+ }
+
+ del_test_array=(key)=>{
+ let {evaluationlist,markvalue}=this.state;
+ let newevaluationlist=evaluationlist;
+ newevaluationlist.splice(key,1);
+ newevaluationlist=this.oneditevaluationlist(newevaluationlist,markvalue);
+ this.setevaluationlist(newevaluationlist);
+ }
+
+ getfilepath=(e,shixunfilepath,type)=>{
+ this.setState({
+ evaluationvisible: true,
+ selectpath:e.target.value,
+ selectpatharr:[],
+ pathtype:type
+ });
+ let id = this.props.match.params.shixunId;
+ let url ="/shixuns/"+id+"/repository.json";
+ axios.post(url,{
+ path: ""
+ }).then((response) => {
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else{
+ this.setState({
+ trees:response.data.trees,
+ saveshixunfilepath:shixunfilepath,
+ path:"",
+ main:[],
+ })
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ sendgetfilepath=(newpath,type,newpathtype)=>{
+ let id = this.props.match.params.shixunId;
+ let{path,main,pathtype}=this.state;
+ let ary=main;
+ let paths=path;
+
+ this.setState({
+ selectpatharr:[],
+ })
+ if(paths===""&&type==="tree"){
+ newpath=newpath+"/";
+ paths="";
+ if(main.length===0){
+ ary.push({val:"根目录/",path:""},{val:newpath,path:paths+newpath})
+ }else{
+ ary.push({val:newpath,path:paths+newpath})
+ }
+
+ }else if(paths!=""&&type==="tree"){
+ newpath=newpath+"/";
+ ary.push({val:newpath,path:paths+newpath})
+ }
+
+
+ let url ="/shixuns/"+id+"/repository.json";
+ if(type==="tree"){
+
+ axios.post(url,{
+ path: paths+newpath
+ }).then((response) => {
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else{
+ this.setState({
+ trees:response.data.trees,
+ path:paths+newpath,
+ main:ary,
+ // selectpath:""
+ })
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ if(pathtype===2){
+ this.setState({
+ selectpath: newpathtype,
+ })
+ }
+ }
+
+ goblakepath=(path,key)=>{
+ let {main,selectpath,pathtype} =this.state;
+ let newmain=[]
+ for(var i=0;i<=key;i++){
+ newmain.push(main[i])
+ }
+ let id = this.props.match.params.shixunId;
+ let url ="/shixuns/"+id+"/repository.json";
+ axios.post(url,{
+ path: path
+ }).then((response) => {
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else {
+ this.setState({
+ trees: response.data.trees,
+ path: path,
+ main: newmain,
+ // selectpath:selectpath
+ })
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+
+ if(pathtype===2){
+ let paths = path.substring(0,path.length-1);
+ console.log(paths)
+ this.setState({
+ selectpath: paths,
+ })
+ }
+
+
+ }
+
+
+
+
+
+ // delesavegetfilepath=(value)=>{
+ // let {selectpatharr} = this.state
+ // let newarr =selectpatharr;
+ // let newselectpath="";
+ // for(var i=0; i{
+ let {selectpath,saveshixunfilepath,pathtype} = this.state
+
+ if(pathtype===1){
+ let newselectpath;
+
+ if(saveshixunfilepath==="shixunfilepathplay"){
+ newselectpath=value
+ }else{
+ const type = selectpath.split(';');
+ let types=false;
+ for(var i=0; i1&&arrtype===false){
+ // for(var i=0; i{
+ let {saveshixunfilepath,selectpath}=this.state;
+ this.setState({
+ evaluationvisible: false,
+ [saveshixunfilepath]:selectpath
+ });
+ }
+ evaluationhideModal=()=>{
+ this.setState({
+ evaluationvisible: false,
+ });
+ }
+ handpathoptionvalue=(value)=>{
+ this.setState({
+ pathoptionvalue:value,
+ shixunfileexpectpicturepath:undefined,
+ shixunfilestandardpicturepath:undefined,
+ shixunfilepicturepath:undefined
+ })
+ }
+ showrepositoryurltip=(type)=>{
+ if(type===1){
+ this.setState({
+ showrepositoryurltiptype:true
+ })
+ }else{
+ this.setState({
+ showrepositoryurltiptype:false
+ })
+ }
+ }
+
+ evaluationonChange=(e,key)=>{
+ let {evaluationlist}=this.state;
+ let newevaluationlist=evaluationlist;
+ let newtype;
+ if(e===1){
+ newtype=0;
+ }else{
+ newtype=1;
+ }
+ // newevaluationlist[key].is_public=newtype;
+ // for(var i=0; i{
+ let {evaluationlist,scoretype}=this.state;
+
+ if(scoretype===key){
+ this.setState({
+ scoretype:undefined
+ })
+ }
+ let newevaluationlist=evaluationlist;
+ let sum =parseInt(e.target.value);
+ if(isNaN(sum)){
+ sum=0
+ }
+ newevaluationlist[key].score=sum;
+
+ this.setState({
+ evaluationlist:newevaluationlist,
+ markvalue:false
+ })
+ this.setevaluationlist(newevaluationlist);
+ }
+
+ // 修改测试集的匹配规则
+ changeEvaluationRule=(e,key)=>{
+ let {evaluationlist}=this.state;
+ let newevaluationlist=evaluationlist;
+ newevaluationlist[key].match_rule=e.target.value
+ this.setevaluationlist(newevaluationlist);
+ }
+
+ evaluationoninputvalue=(e,key,type)=>{
+ $.fn.autoHeight = function(){
+ function autoHeight(elem){
+ elem.style.height = 'auto';
+ elem.style.maxHeight = '140px';
+ elem.scrollTop = 0; //防抖动
+ elem.style.height = elem.scrollHeight + 'px';
+ }
+ this.each(function(){
+ autoHeight(this);
+ $(this).on('keyup', function(){
+ autoHeight(this);
+ });
+ });
+ }
+ $('textarea[autoHeight]').autoHeight();
+
+ let {evaluationlist}=this.state;
+ let newevaluationlist=evaluationlist;
+ if(type==="sr"){
+ newevaluationlist[key].input=e.target.value
+ }else if(type==="yq"){
+ // 统一转成\r\n
+ newevaluationlist[key].output= e.target.value ? e.target.value.replace(/\r?\n/g, "\r\n") : e.target.value
+ }
+ this.setevaluationlist(newevaluationlist);
+ }
+
+
+ evaluationoninputvalueonload=()=>{
+ $.fn.autoHeight = function(){
+ function autoHeight(elem){
+ elem.style.height = 'auto';
+ elem.style.maxHeight = '140px';
+ elem.scrollTop = 0; //防抖动
+ elem.style.height = elem.scrollHeight + 'px';
+ }
+ this.each(function(){
+ autoHeight(this);
+ $(this).on('keyup', function(){
+ autoHeight(this);
+ });
+ });
+ }
+ $('textarea[autoHeight]').autoHeight();
+ }
+ submitarbitrationevaluation=()=>{
+ let{evaluationlist,shixunfilepath,shixunfilepathplay,shixunfileexpectpicturepath,shixunfilestandardpicturepath,shixunfilepicturepath,pathoptionvalue,scorevalue,markvalue,web_route}=this.state;
+
+
+ let newscorevalue;
+ if(scorevalue===false){
+ newscorevalue=false
+ }else{
+ //判断占比
+ newscorevalue=true
+
+ let sum=0;
+ for(var i=0; i100){
+ this.props.showSnackbar("测试集的评分占比不能大于100");
+ this.setState({
+ scoretype:i
+ })
+ return
+ }
+ sum=sum+evaluationlist[i].score
+ }
+
+ if(sum>100||sum<100){
+ this.props.showSnackbar("测试集的评分占比之和必须等于100");
+ return
+ }
+
+
+ }
+ if(shixunfilepath===undefined||shixunfilepath===""||shixunfilepath===null){
+ this.props.showSnackbar("学员任务文件路径为空");
+ this.setState({
+ StudentTaskPapers:true
+ })
+ $('html').animate({
+ scrollTop: 120
+ }, 1000);
+ return
+ }
+
+ if(shixunfilepathplay===undefined||shixunfilepathplay===""||shixunfilepathplay===null){
+ this.props.showSnackbar("评测执行文件路径为空");
+ this.setState({
+ StudentTaskDocs:true
+ })
+ $('html').animate({
+ scrollTop: 130
+ }, 1000);
+ return
+ }
+
+ if(evaluationlist.length===0){
+ this.props.showSnackbar("测试集不能为空");
+ return
+ }
+ let id = this.props.match.params.shixunId;
+ let{checkpointId}=this.state;
+ let url = "/shixuns/"+id+"/challenges/"+checkpointId+".json";
+ let newchallenge={
+ path:shixunfilepath,
+ exec_path:shixunfilepathplay,
+ show_type:pathoptionvalue,
+ original_picture_path:pathoptionvalue===-1?undefined:shixunfileexpectpicturepath===undefined?null:shixunfileexpectpicturepath,
+ expect_picture_path:pathoptionvalue===-1?undefined:shixunfilestandardpicturepath===undefined?null:shixunfilestandardpicturepath,
+ picture_path:pathoptionvalue===-1?undefined:shixunfilepicturepath===undefined?null:shixunfilepicturepath,
+ test_set_score:newscorevalue,
+ test_set_average:markvalue,
+ web_route:web_route===null?undefined:web_route
+ }
+ axios.put(url,{
+ tab:1,
+ challenge:newchallenge,
+ test_set:evaluationlist
+ }
+ ).then((response) => {
+ this.props.showSnackbar(response.data.messages);
+ // if(response.data.status===1){
+ // window.location.href = "/shixuns/" + id + "/challenges/"+response.data.challenge_id+"/tab=3"
+ // }
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+ handpathoptionvalues=()=>{
+ this.setState({
+ handpathopt:true
+ })
+ }
+ handpathoptionvaluess=()=>{
+ this.setState({
+ handpathopt:false
+ })
+ }
+ saveselectpath=(e)=>{
+
+ this.setState({
+ selectpath:e.target.value
+ })
+
+ }
+ updatepath=(e,name,type)=>{
+ this.setState({
+ [name]:e.target.value,
+ pathtype:type
+ })
+ }
+
+
+ oneditevaluationlist=(newevaluationlist,markvalue)=>{
+
+ if(markvalue===true){
+ if(100%newevaluationlist.length===0){
+ let sum=100/newevaluationlist.length;
+ for(var i=0; i{
+
+ let {markvalue,evaluationlist}=this.state;
+ let newevaluationlist=evaluationlist;
+
+ if(e.target.value===true){
+ newevaluationlist=this.oneditevaluationlist(newevaluationlist,markvalue)
+ }
+
+ this.setState({
+ scorevalue: e.target.value,
+ evaluationlist:newevaluationlist
+ });
+
+ this.setevaluationlist(newevaluationlist);
+ }
+
+ //均匀比例
+ onChangemarkvalue=(e)=>{
+ let {evaluationlist}=this.state;
+
+ if(e.target.value===true){
+ let newevaluationlist=evaluationlist;
+ newevaluationlist=this.oneditevaluationlist(newevaluationlist,e.target.value);
+ this.setevaluationlist(newevaluationlist);
+ }
+
+ this.setState({
+ markvalue: e.target.value,
+ });
+
+ }
+
+ updatewebroute=(e)=>{
+ this.setState({
+ web_route:e.target.value
+ })
+ }
+ render() {
+
+ let {
+ choice_url,
+ practice_url,
+ go_back_url,
+ position,
+ evaluationlist,
+ shixunId,
+ checkpointId,
+ power,
+ shixunfileexpectpicturepath,
+ shixunfilestandardpicturepath,
+ shixunfilepicturepath,
+ shixunfilepath,
+ evaluationvisible,
+ trees,
+ path,
+ main,
+ selectpath,
+ shixunfilepathplay,
+ pathoptionvalue,
+ showrepositoryurltiptype,
+ prev_challenge,
+ next_challenge,
+ StudentTaskPapers,
+ StudentTaskDocs,
+ web_route,
+ scorevalue,
+ markvalue,
+ scoretype,
+ has_web_route
+ } = this.state;
+
+ let tab1url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/editcheckpoint";
+ let tab2url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=2";
+ let tab3url="/shixuns/" + shixunId + "/challenges/"+checkpointId+"/tab=3";
+ // console.log(this.props)
+ const radioStyle = {
+ display: 'block',
+ height: '30px',
+ lineHeight: '30px',
+ marginLeft: '20px',
+ };
+ return (
+
+
+
+
+
+
+
第{position}关
+
返回
+
+ {prev_challenge === undefined ? "" :
+
上一关
+ }
+
+ {next_challenge === undefined ? "" :
+
下一关
+ }
+
+
4||this.props.identity===undefined||this.props.status===2||this.props.status===1? "none":'block'}}
+ data-tip-down="新增代码编辑类型的任务">+ 实践类型
+
4||this.props.identity===undefined||this.props.status===2||this.props.status===1?"none":'block'}}
+ data-tip-down="新增选择题类型的任务">+ 选择题类型
+
+
+
+
+
+
+ 本关任务
+
+
+
+ 评测设置
+
+
+
+ 参考答案
+
+
+
+
+ 请先上传本关任务的所有代码文件、标准图片等所有必要的文件到
+ 版本库
+
+
+
+
+
+
学员任务文件
+
+
*
+
+
this.updatepath(e,"shixunfilepath",1)}
+ onClick={(e)=>this.getfilepath(e,"shixunfilepath",1)}
+ />
+
该文件将直接显示给学生,需要学生在其中填写代码
+
+
+ 必填项
+
+
+
+
+
+
+
+
+
+
+
评测执行文件
+
+
*
+
+
this.updatepath(e,"shixunfilepathplay",1)}
+ onClick={(e)=>this.getfilepath(e,"shixunfilepathplay",1)}
+ />
+
该文件由平台执行,用来测试平台学员代码是否正确
+
+
+ 必填项
+
+
+
+
+
+
+
+
+
效果展现方式
+
+
+
this.showrepositoryurltip(1)}>}/)
+
+
+
+
+ 图片:处理或输出图片类型的任务,请选填此项
+ 可以通过设置图片路径和学员答案文件路径,展示代码对应的图片效果
+ apk/exe:写可执行文件的任务,请选填此项
+ 可以通过设置学员答案文件路径,展示二维码以供扫码下载
+ txt:输出txt文档类型的任务,请选填此项
+ 可以通过学员答案文件路径设置,展示txt文件内容
+ html:web类型的任务,请选填此项
+ 可以通过Web路由设置,展示html效果预览页
+
+
this.showrepositoryurltip(2)}
+ >知道了
+
+
+
+
该选项用来配置学员评测本关任务时,查看效果页上需要展现的文件类型
+
+
+
+ {pathoptionvalue===4&&web_route!=null||pathoptionvalue===4&&has_web_route===true?
+
+
Web路由
+
+
+ this.updatewebroute(e)}
+ placeholder="网站类型实训,请填写Web路由地址。例:java/mypage"/>
+
+
+
+
:""}
+
+ {pathoptionvalue===1||pathoptionvalue===5||pathoptionvalue===6?
+
+
待处理文件路径
+
+
+
this.updatepath(e,"shixunfileexpectpicturepath",2)}
+ onClick={(e)=>this.getfilepath(e,"shixunfileexpectpicturepath",2)}
+ />
+
+ 该路径下的文件将在学员评测本关任务时,作为原始文件显示在查看效果页,供学员参考;任务为文件处理时请指定该路径,并注意与程序文件所在文件夹分开。
+
+
+
+
+
+
:""}
+
+
+ {pathoptionvalue===1||pathoptionvalue===5||pathoptionvalue===6?
+
+
标准答案文件路径
+
+
+
this.updatepath(e,"shixunfilestandardpicturepath",2)}
+ onClick={(e)=>this.getfilepath(e,"shixunfilestandardpicturepath",2)}
+ />
+
+ 该路径下的文件将在学员评测本关任务时,作为参考答案显示在查看效果页,供学员参考;任务输出结果为文件时请指定该路径,并注意与程序文件所在文件夹分开。
+
+
+
+
+
+
:""}
+
+
+ {pathoptionvalue===-1?"":
+
+
学员答案文件路径
+
+
+
this.updatepath(e,"shixunfilepicturepath",2)}
+ onClick={(e)=>this.getfilepath(e,"shixunfilepicturepath",2)}
+ placeholder="请在版本库中指定用来保存学员代码实际输出结果的路径。例:src/step1/outputfiles"/>
+
+ 学员评测本关任务时生成的文件将保存在该路径下,并作为实际输出显示在查看效果页,供学员确认;任务输出结果为文件时请指定该路径,并注意与程序文件所在文件夹分开。
+
+
+
+
+
+
}
+
+
+
+
+ {/*
测试集
*/}
+
测试集和系统评分规则
+
+ 得分规范:
+
+
+ 通过全部测试集
+ (学员评测,仅当所有测试集都正确时,才获得一次性奖励)
+
+
+ 通过部分测试集
+ (学员评测,当至少有一组测试集正确时,即可获得其对应比例的奖励)
+
+
+
+
+
+ 系统评分占比:
+
+ 均分比例
+ 自定义比例
+
+
+
+
+
+
+
+
+
+
+ {evaluationlist===undefined?"":evaluationlist.length===0?"":evaluationlist.map((item,key)=>{
+ return(
+
+
+ *
+ 组{key+1}
+
+ {/*checked={item.is_public===1?false:true}*/}
+
+ this.editpercentage(e,key)}
+ value={item.score} />
+ %
+
+
+ this.evaluationonChange(item.hidden,key)} checked={item.hidden===1?true:false}>隐藏
+
+
+
+ this.del_test_array(key)}>
+
+
+
+
+
+
+
+ 匹配规则:
+ this.changeEvaluationRule(e,key)}>
+ 完全匹配
+ 末尾匹配
+
+
+
+ )
+ })}
+
+
+
+
+
+
+ 新增测试集
+
+
+
温馨提示:建议公开测试集和隐藏测试集结合使用,降低作弊的几率;隐藏测试集,在“提交评测”时也将被自动检测
+
+
+
+
+
+
4||this.props.identity===undefined||power===false?"none":"block"}}>
+
提交
+
取消
+
+
+
+
+
+ )
+ }
+}
+
+
diff --git a/public/react/src/tpm/challengesnew/TPMquestion.js b/public/react/src/tpm/challengesnew/TPMquestion.js
new file mode 100644
index 000000000..b76e17b17
--- /dev/null
+++ b/public/react/src/tpm/challengesnew/TPMquestion.js
@@ -0,0 +1,1052 @@
+import React, {Component} from 'react';
+
+import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Tooltip,notification} from 'antd';
+
+import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
+
+// import "antd/dist/antd.css";
+
+import axios from 'axios';
+
+import { getImageUrl, toPath } from 'educoder';
+
+import './css/TPMchallengesnew.css';
+
+import {getUrl} from 'educoder';
+
+import TpmQuestionMain from './TpmQuestionMain';
+
+import TpmQuestionNew from './TpmQuestionNew';
+
+import TpmQuestionEdit from './TpmQuestionEdit';
+
+let origin = getUrl();
+
+let path = getUrl("/editormd/lib/")
+
+const $ = window.$;
+
+const Option = Select.Option;
+
+const RadioGroup = Radio.Group;
+
+var letterArr = [];
+for (var i = 65, j = 0; i < 91; i++, j++) {
+ letterArr[j] = String.fromCharCode(i);
+}
+
+
+export default class TPMquestion extends Component {
+ constructor(props) {
+ super(props)
+ this.contentMdRef = React.createRef();
+ this.newquestioMDMdRef = React.createRef();
+ this.newquestioMDMdCont=React.createRef();
+ this.neweditanswerRef=React.createRef();
+ this.editanswersRef=React.createRef();
+ this.state = {
+ choice_url: undefined,
+ practice_url: undefined,
+ go_back_url: undefined,
+ position: undefined,
+ task_pass_default: undefined,
+ submit_url: undefined,
+ questionsInputvalue:undefined,
+ questionaddsum:0,
+ questionaddarray:[],
+ questionaddtype:true,
+ activetype:"",
+ questionlists:[{str:"A",val:"",type:false},{str:"B",val:"",type:false},{str:"C",val:"",type:false},{str:"D",val:"",type:false}],
+ answeshixunsGroup: 1,
+ answeoptions:[10,20],
+ answeonshixunsmark:10,
+ shixunssanswerkillvalue:"",
+ shixunsskillanswerlist:[],
+ challenge_id:"",
+ challenge_choose_id:undefined,
+ questionlistss:[],
+ newcnttype:false,
+ newquestioMDvaluetype:false,
+ challenge_tagtype:false,
+ editquestionaddtype:false,
+ mancheckpointId:undefined,
+ power:false,
+ questionInputvaluetype:false,
+ questioMD:"",
+ standard_answer:"",
+ subject:"",
+ newquestioMDvaluetypes:false,
+ questionInputvaluetypes:false,
+ prev_challenge:undefined,
+ next_challenge:undefined,
+ newcnttypesum:1,
+ marktype:false,
+ answer:"",
+ sumittype:false
+ }
+ }
+
+
+ questionInputvalue=(e)=>{
+ this.setState({
+ questionsInputvalue: e.target.value
+ })
+ }
+
+ componentDidMount() {
+ if(this.props.status===2){
+
+ }
+ let id = this.props.match.params.shixunId;
+ let checkpointId=this.props.match.params.checkpointId;
+
+ this.setState({
+ mancheckpointId:id,
+ })
+
+ let newchoice_url= "/shixuns/"+id+"/challenges/newquestion";
+ let newpractice_url= "/shixuns/"+id+"/challenges/new";
+ let newgo_back_url="/shixuns/"+id+"/challenges";
+
+ if(this.props.match.params.choose_id===undefined){
+ if(checkpointId===undefined){
+ //新建模式
+ let nurl = "/shixuns/" + id + "/challenges/new.json"
+ axios.get(nurl).then((response) => {
+
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else {
+ this.setState({
+ choice_url: newchoice_url,
+ practice_url: newpractice_url,
+ go_back_url: newgo_back_url,
+ position: response.data.position,
+ task_pass_default: response.data.task_pass_default,
+ submit_url: response.data.submit_url,
+ power:true,
+ activetype:"first",
+
+ })
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+ this.setState({
+ contentMdRefval:""
+ })
+ } else {
+
+ this.setState({
+ contentMdRefval:response.data.task_pass_default
+ })
+ this.contentMdRef.current.setValue(response.data.task_pass_default || '')
+ }
+ this.shixunsautoHeight()
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ });
+
+ }else{
+ //编辑模式
+ let url = "/shixuns/"+ id +"/challenges/"+checkpointId+"/edit.json?st=1"
+ axios.get(url).then((response) => {
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else {
+ let newprev_challenge=response.data.prev_challenge;
+ let next_challenge=response.data.next_challenge;
+ if (newprev_challenge != undefined) {
+ if(newprev_challenge.st===0){
+ newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint";
+ }else{
+ newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion";
+ }
+ }
+ if (next_challenge != undefined) {
+ if(next_challenge.st===0){
+ next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint";
+ }else{
+ next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion";
+ }
+ }
+ this.setState({
+ questionaddtype:false,
+ newquestionaddtype:false,
+ activetype:"first",
+ prev_challenge:newprev_challenge,
+ next_challenge:next_challenge,
+ questionsInputvalue:response.data.subject,
+ questionaddarray:response.data.chooses,
+ challenge_id:response.data.id,
+ mancheckpointId:checkpointId,
+ position: response.data.position,
+ choice_url: newchoice_url,
+ practice_url: newpractice_url,
+ go_back_url: newgo_back_url,
+ power:response.data.power,
+ // questioMD:response.data.task_pass,
+ answer:response.data.answer
+
+ })
+
+ this.setState({
+ contentMdRefval:response.data.task_pass
+ })
+ // this.contentMdRef.current.setValue(response.data.task_pass || '')
+ if(response.data.chooses.length===0){
+ // 新建选择题时,没法切回 ‘本关任务’ tab
+ // this.questionadd()
+ }
+
+ this.shixunsautoHeight()
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ }else{
+ $('html').animate({
+ scrollTop:10
+ }, 500);
+
+ let{challenge_id} =this.state;
+
+ let id = this.props.match.params.shixunId;
+ let url = "/shixuns/"+ id +"/challenges/"+checkpointId+"/edit.json?st=1"
+ axios.get(url).then((response) => {
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else {
+ let newprev_challenge=response.data.prev_challenge;
+ let next_challenge=response.data.next_challenge;
+ if (newprev_challenge != undefined) {
+ if(newprev_challenge.st===0){
+ newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editcheckpoint";
+ }else{
+ newprev_challenge = "/shixuns/" + id + "/challenges/" + newprev_challenge.id + "/editquestion";
+ }
+ }
+ if (next_challenge != undefined) {
+ if(next_challenge.st===0){
+ next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editcheckpoint";
+ }else{
+ next_challenge = "/shixuns/" + id + "/challenges/" + next_challenge.id+ "/editquestion";
+ }
+ }
+ this.setState({
+ questionaddtype:false,
+ newquestionaddtype:false,
+ prev_challenge:newprev_challenge,
+ next_challenge:next_challenge,
+ questionsInputvalue:response.data.subject,
+ questionaddarray:response.data.chooses,
+ challenge_id:response.data.id,
+ mancheckpointId:checkpointId,
+ position: response.data.position,
+ choice_url: newchoice_url,
+ practice_url: newpractice_url,
+ go_back_url: newgo_back_url,
+ power:response.data.power,
+ // questioMD:response.data.task_pass,
+
+ })
+
+ this.setState({
+ contentMdRefval:response.data.task_pass
+ })
+ // this.contentMdRef.current.setValue(response.data.task_pass || '')
+ if(response.data.chooses.length===0){
+ this.questionadd()
+ }
+ this.shixunsautoHeight()
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ });
+
+ let zrl ='/shixuns/'+this.props.match.params.shixunId+'/challenges/'+this.props.match.params.checkpointId+'/edit_choose_question.json?choose_id='+this.props.match.params.choose_id;
+ axios.get(zrl).then((response) => {
+ if(response.status===200){
+ let choose_contents=response.data.choose_contents;
+ let newchoose_contentslist=[]
+ for(var i=0; i {
+ });
+
+ }
+ }
+
+ clickquestionsumit=()=>{
+ this.setState({
+ sumittype:true
+ })
+ let checkpointId=this.props.match.params.checkpointId;
+ if(this.props.status===2&&checkpointId===undefined){
+ this.props.showSnackbar("该实训已经发布不能新建")
+ this.setState({
+ sumittype:false
+ })
+ return
+ }
+ let {questionsInputvalue} =this.state;
+ // const exercise_editormdvalue = this.questio_editormd.getValue();
+ const exercise_editormdvalue = this.contentMdRef.current.getValue().trim();
+ let id = this.props.match.params.shixunId;
+
+ if(questionsInputvalue===undefined||questionsInputvalue===null||questionsInputvalue===""){
+ this.setState({
+ questionInputvaluetype:true
+ })
+ $('html').animate({
+ scrollTop: 10
+ }, 1000);
+ this.setState({
+ sumittype:false
+ })
+ return
+ }
+
+
+ if(exercise_editormdvalue===null ||exercise_editormdvalue===""){
+ this.setState({
+ questionInputvaluetypes:true
+ })
+ $('html').animate({
+ scrollTop: 500
+ }, 1000);
+ this.setState({
+ sumittype:false
+ })
+ return
+ }
+ if(checkpointId===undefined){
+
+ let url = "/shixuns/" + id + "/challenges.json";
+
+ axios.post(url, {
+ identifier:id,
+ subject: questionsInputvalue,
+ task_pass: exercise_editormdvalue,
+ st: 1
+ }).then((response) => {
+ this.props.showSnackbar(response.data.messages);
+ // if(response.data.status===1){
+ //
+ // this.setState({
+ // questionaddtype:false,
+ // challenge_id:response.data.challenge_id
+ // })
+ //
+ // this.questionadd()
+ // }
+ window.location.href = '/shixuns/'+id+'/challenges/'+response.data.challenge_id+'/editquestion';
+
+ }).catch((error) => {
+ console.log(error)
+ });
+ }else{
+ let url ="/shixuns/"+id+"/challenges/"+checkpointId+".json";
+ axios.put(url, {
+ tab:0,
+ subject: questionsInputvalue,
+ task_pass: exercise_editormdvalue,
+ }).then((response) => {
+ if(response.data.status===1){
+ this.setState({
+ questionaddtype:false,
+ challenge_id:response.data.challenge_id
+ })
+ }
+ $('html').animate({
+ scrollTop: 10
+ }, 200);
+ this.props.showSnackbar(response.data.messages);
+ window.location.href = '/shixuns/'+id+'/challenges/'+response.data.challenge_id+'/editquestion';
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ }
+
+ questionall=()=>{
+ // this.setState({
+ // activetype:"first",
+ // newquestionaddtype:false,
+ // editquestionaddtype:false,
+ // questionaddtype:false
+ // })
+
+ window.location.href = '/shixuns/'+this.props.match.params.shixunId+'/challenges/'+this.props.match.params.checkpointId+'/editquestion';
+ }
+ questionadd=()=>{
+
+ let{questionaddarray}=this.state;
+
+ let questionaddsums=questionaddarray.length;
+
+ if(questionaddsums-1>9){
+ this.props.showSnackbar("选择题目最大支持设置9道题")
+ return
+ }
+
+ let questionaddarrays=questionaddarray;
+
+ questionaddarrays.map((item,key)=>{
+ if(item.choose_id===0){
+ questionaddarrays.splice(key,1)
+ }
+ })
+
+ questionaddarrays.push({type:0,choose_id:0});
+ this.setState({
+ activetype:0,
+ questionaddarray:questionaddarrays,
+ questionaddtype:true,
+ editquestionaddtype:false,
+ newquestionaddtype:true,
+ questionlists:[{str:"A",val:"",type:false},{str:"B",val:"",type:false},{str:"C",val:"",type:false},{str:"D",val:"",type:false}],
+ answeshixunsGroup: 1,
+ answeoptions:[10,20],
+ answeonshixunsmark:10,
+ shixunssanswerkillvalue:"",
+ shixunsskillanswerlist:[],
+ contentMdRefval:"",
+ newquestioMDMdContval:"",
+ })
+
+
+ setTimeout(() => {
+ this.newquestioMDMdRef.current.setValue('')
+ }, 1000)
+ setTimeout(() => {
+ this.newquestioMDMdCont.current.setValue('')
+ }, 1500)
+ // this.shixunsautoHeight()
+ }
+
+ editquestionlists=(newquestionlists)=>{
+ let newlist=newquestionlists;
+ let list=[]
+ for(var i=0; i{
+ let{questionlists} = this.state;
+ let newquestionlists=questionlists;
+ let newli={str:letterArr[questionlists.length],val:"",type:false};
+ newquestionlists.push(newli);
+ this.editquestionlists(newquestionlists);
+ }
+
+
+ delquestionlists=(key)=>{
+ let{questionlists} = this.state;
+ let newquestionlists=questionlists;
+ newquestionlists.splice(key,1);
+ for(var i=0; i{
+ let{questionlists} = this.state;
+ let newquestionlists=questionlists;
+ if(newquestionlists[key].type===true){
+ newquestionlists[key].type=false;
+ }else if(newquestionlists[key].type===false){
+ newquestionlists[key].type=true;
+ }
+
+ this.editquestionlists(newquestionlists);
+ }
+
+ onshixunGroupanswe=(e)=> {
+ let optionsum;
+ let onshixunsmark;
+ if(e.target.value===1){
+ optionsum=[10,20];
+ onshixunsmark=10;
+ }else if(e.target.value===2){
+ optionsum=[30,40,50,60];
+ onshixunsmark=30;
+ }else if(e.target.value===3){
+ optionsum=[70,80,90,100]
+ onshixunsmark=70;
+ }
+ this.setState({
+ answeshixunsGroup: e.target.value,
+ answeoptions:optionsum,
+ answeonshixunsmark:onshixunsmark
+ })
+ }
+ shixunssanswerkill = (e) => {
+ this.setState({
+ shixunssanswerkillvalue: e.target.value
+ })
+
+ }
+ clickshixunsanswerskill = () => {
+
+ let {shixunssanswerkillvalue, shixunsskillanswerlist} = this.state;
+ if (shixunssanswerkillvalue === "") {
+ return
+ } else if (shixunssanswerkillvalue === undefined) {
+ return
+ }
+
+ if(shixunssanswerkillvalue == "" || shixunssanswerkillvalue == undefined || shixunssanswerkillvalue == null || (shixunssanswerkillvalue.length>0 && shixunssanswerkillvalue.trim().length == 0)){
+ message.error("输入为空,不能保存!");
+ return
+ }
+
+ let list = shixunsskillanswerlist;
+ list.push(shixunssanswerkillvalue);
+ this.setState({
+ shixunsskillanswerlist: list,
+ shixunssanswerkillvalue: ""
+ })
+ }
+ delshixunssnswerllist=(key)=>{
+ let {shixunsskillanswerlist} = this.state;
+ let newshixunsskillanswerlist = shixunsskillanswerlist;
+ newshixunsskillanswerlist.splice(key, 1);
+ this.setState({
+ shixunsskillanswerlist: newshixunsskillanswerlist
+ })
+ }
+ onInputoquestionption=(e,key)=>{
+
+ $.fn.autoHeight = function(){
+ function autoHeight(elem){
+ elem.style.height = 'auto';
+ elem.style.maxHeight = '140px';
+ elem.scrollTop = 0; //防抖动
+ elem.style.height = elem.scrollHeight + 'px';
+ }
+ this.each(function(){
+ autoHeight(this);
+ $(this).on('keyup', function(){
+ autoHeight(this);
+ });
+ });
+ }
+ $("#"+e.target.id).autoHeight();
+
+ let {questionlists}=this.state;
+ let newquestionlists=questionlists;
+ newquestionlists[key].val=e.target.value;
+ this.editquestionlists(newquestionlists);
+ }
+
+ onshixunsansweSelect=(value)=>{
+ this.setState({
+ answeonshixunsmark: value
+ })
+ }
+
+ answer_subit=(sumtype,challenge_choose_id)=>{
+ $('html').animate({
+ scrollTop:10
+ }, 500);
+
+ let {challenge_id,questionlists,shixunsskillanswerlist,answeonshixunsmark,answeshixunsGroup,questionaddarray} =this.state;
+ if(challenge_id===undefined){
+ message.error("关卡id为空");
+ return
+ }
+ let newquestionlists=questionlists;
+ let newlist="";
+ let newtype=[];
+ let newcnt=[];
+ let list=0;
+ for(var i=0; i {
+ // $('html').animate({
+ // scrollTop: 10
+ // }, 200);
+ $('html').animate({
+ scrollTop: 10
+ }, 200);
+
+ notification.open({
+ message: '提示',
+ description:
+ '修改成功,请点击右侧加号继续添加',
+ });
+
+ this.setState({
+ questionaddtype:false,
+ newquestioMDvaluetype:false,
+ newquestioMDvaluetypes:false,
+ })
+ // setTimeout(window.location.href="/shixuns/"+this.props.match.params.shixunId+"/challenges/"+this.props.match.params.checkpointId+"/editquestion"+"/"+response.data.challenge_choose_id,1000)
+ // this.gochooseid()
+ }).catch((error) => {
+ console.log(error)
+ });
+ }else{
+
+ let newquestioMDvalue = this.newquestioMDMdRef.current.getValue().trim();
+ if(newquestioMDvalue===""||newquestioMDvalue==="请输入选择题的题干内容"){
+ this.setState({
+ newquestioMDvaluetype:true,
+ })
+ $('html').animate({
+ scrollTop:100
+ }, 200);
+ message.error("题干为空");
+ return
+ }
+ let newnewanswerMDvalue = this.newquestioMDMdCont.current.getValue().trim();
+
+ if(newnewanswerMDvalue===""||newnewanswerMDvalue===" "){
+ newnewanswerMDvalue=undefined
+ }
+ url="/shixuns/" + id + "/challenges/" + challenge_id + "/create_choose_question.json";
+ axios.post(url, {
+ challenge_choose: {subject: newquestioMDvalue, answer: newnewanswerMDvalue, standard_answer:newlist , score: answeonshixunsmark, difficult: answeshixunsGroup},
+ challenge_tag: shixunsskillanswerlist,
+ question: {cnt: newcnt},
+ choice: {answer: newtype}
+ }).then((response) => {
+
+ let questionaddsums=questionaddarray.length;
+ let questionaddarrays=questionaddarray;
+ questionaddarrays[questionaddsums-1].choose_id=response.data.challenge_choose_id;
+ if(newlist.length===1){
+ questionaddarrays[questionaddsums-1].type=1;
+ }else if(newlist.length>1){
+ questionaddarrays[questionaddsums-1].type=2;
+ }
+ this.setState({
+ challenge_choose_id:response.data.challenge_choose_id,
+ questionaddtype:false,
+ editquestionaddtype:false,
+ newquestioMDvaluetype:false,
+ newquestioMDvaluetypes:false,
+ questionaddarray:questionaddarrays
+ })
+ $('html').animate({
+ scrollTop: 10
+ }, 200);
+
+ notification.open({
+ message: '提示',
+ description:
+ '新建成功,请点击右侧加号继续添加',
+ });
+ window.location.href=`/shixuns/${id}/challenges/${checkpointId}/editquestion/${response.data.challenge_choose_id}`;
+
+ // this.getanswer_subitlist()
+ // this.gochooseid("/shixuns/"+this.props.match.params.shixunId+"/challenges/"+this.props.match.params.checkpointId+"/editquestion"+"/"+response.data.challenge_choose_id)
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+
+ }
+
+ questionlist=(key,challenge_choose_id,type)=>{
+ $('html').animate({
+ scrollTop:10
+ }, 500);
+
+ let{challenge_id} =this.state;
+
+ if(challenge_choose_id===""||type===0){
+
+
+ // this.neweditanswerRef.current.setValue('')
+ // this.editanswersRef.current.setValue('')
+ this.setState({
+ activetype:challenge_choose_id,
+ editquestionaddtype:true,
+ questionaddtype:true,
+ newquestionaddtype:false,
+ questionlists:[{str:"A",val:"",type:false},{str:"B",val:"",type:false},{str:"C",val:"",type:false},{str:"D",val:"",type:false}],
+ answeshixunsGroup: 1,
+ answeoptions:[10,20],
+ answeonshixunsmark:10,
+ shixunssanswerkillvalue:"",
+ shixunsskillanswerlist:[],
+ neweditanswerRefval:'',
+ editanswersRefval:''
+ })
+ this.newquestioMDMdRef.current.setValue('')
+ this.newquestioMDMdCont.current.setValue('')
+ }else{
+ let id = this.props.match.params.shixunId;
+ let url ='/shixuns/'+id+'/challenges/'+challenge_id+'/edit_choose_question.json?choose_id='+challenge_choose_id;
+ axios.get(url).then((response) => {
+ if(response.status===200){
+ let choose_contents=response.data.choose_contents;
+ let newchoose_contentslist=[]
+ for(var i=0; i {
+ });
+
+ }
+
+ }
+
+ shixunsautoHeight=()=>{
+ $.fn.autoHeight = function(){
+ function autoHeight(elem){
+ elem.style.height = 'auto';
+ elem.style.maxHeight = '140px';
+ elem.scrollTop = 0; //防抖动
+ if(elem.scrollHeight===0){
+ elem.style.height = 62 + 'px';
+ }else{
+
+ elem.style.height = elem.scrollHeight + 'px';
+ }
+
+ }
+ this.each(function(){
+ autoHeight(this);
+ $(this).on('keyup', function(){
+ autoHeight(this);
+ });
+ });
+ }
+ $('textarea[autoHeight]').autoHeight();
+ }
+
+ gochooseid=(url)=>{
+ window.location.href =url
+ // window.location.Reload(url)
+ // this.props.history.replace( url );
+ // this.props.history.push( url );
+ // 返回
+ // this.props.history.goBack();
+ }
+
+ render() {
+
+ let {choice_url,
+ practice_url,
+ go_back_url,
+ position,
+ answeoptions,
+ questionaddarray,
+ questionaddtype,
+ activetype,
+ newquestionaddtype,
+ editquestionaddtype,
+ challenge_choose_id,
+ prev_challenge,
+ next_challenge,
+ answer,
+
+ } = this.state;
+
+ let options;
+
+
+ options = answeoptions.map((d, k) => {
+ return (
+
+ )
+ })
+
+ return (
+
+
+
+
+
+
+ {/*x选择题首页*/}
+ {activetype==="first"?
this.questionInputvalue(e)}
+ clickquestionsumit={(e)=>this.clickquestionsumit(e)}
+
+ />:""}
+
+ {/*新建*/}
+
+ {newquestionaddtype===true?
+ this.selquestionlists(key)}
+ onInputoquestionption={(e,key)=>this.onInputoquestionption(e,key)}
+ delquestionlists={(key)=>this.delquestionlists(key)}
+ addquestionlists={(e)=>this.addquestionlists(e)}
+ onshixunGroupanswe={(e)=>this.onshixunGroupanswe(e)}
+ onshixunsansweSelect={(e)=>this.onshixunsansweSelect(e)}
+ shixunssanswerkill={(e)=>this.shixunssanswerkill(e)}
+ clickshixunsanswerskill={(e)=>this.clickshixunsanswerskill(e)}
+ delshixunssnswerllist={(key)=>this.delshixunssnswerllist(key)}
+ answer_subit={()=>this.answer_subit()}
+ />:""}
+
+
+ {/*修改*/}
+ {editquestionaddtype===true?
+ this.selquestionlists(key)}
+ onInputoquestionption={(e,key)=>this.onInputoquestionption(e,key)}
+ delquestionlists={(key)=>this.delquestionlists(key)}
+ addquestionlists={(e)=>this.addquestionlists(e)}
+ onshixunGroupanswe={(e)=>this.onshixunGroupanswe(e)}
+ onshixunsansweSelect={(e)=>this.onshixunsansweSelect(e)}
+ shixunssanswerkill={(e)=>this.shixunssanswerkill(e)}
+ clickshixunsanswerskill={(e)=>this.clickshixunsanswerskill(e)}
+ delshixunssnswerllist={(key)=>this.delshixunssnswerllist(key)}
+ answer_subit={()=>this.answer_subit("edit",challenge_choose_id)}
+ />
+ :""}
+
+
+
+ )
+ }
+}
+
diff --git a/public/react/src/tpm/challengesnew/TpmQuestionEdit.js b/public/react/src/tpm/challengesnew/TpmQuestionEdit.js
new file mode 100644
index 000000000..d0e6f98bd
--- /dev/null
+++ b/public/react/src/tpm/challengesnew/TpmQuestionEdit.js
@@ -0,0 +1,229 @@
+import React, {Component} from 'react';
+
+import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Tooltip} from 'antd';
+
+import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
+
+import axios from 'axios';
+
+import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
+
+const Option = Select.Option;
+
+const RadioGroup = Radio.Group;
+
+export default class TpmQuestionEdit extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+
+ }
+ }
+
+ componentDidMount() {
+
+ }
+ delecbtns=()=>{
+ let url=`/shixuns/${this.props.match.params.shixunId}/challenges/${this.props.match.params.checkpointId}/destroy_challenge_choose.json`;
+ axios.delete((url), { data: {
+ choose_id:this.props.match.params.choose_id
+ }})
+ .then((result)=>{
+ if(result.data.status===1){
+ window.location.href=`/shixuns/${this.props.match.params.shixunId}/challenges/${this.props.match.params.checkpointId}/editquestion`;
+ }
+ })
+ }
+
+ render() {
+
+ return (
+
+
+
+
+
题干
+
+
*
+
+
+
+
+
+
+ 必填项
+
+
+
+
+
+
+
+
+
+
+
+
+
+
难度系数
+
+
+ this.props.onshixunGroupanswe(e)}>
+ 简单
+ 中等
+ 困难
+
+
+
+
奖励经验值
+
+
*
+
+
+
+ 如果学员答题错误,则不能得到相应的经验值
+ 如果学员成功得到经验值,那么将同时获得等值的金币奖励,如:+10经验值、+10金币
+
+
+
必填项
+
+
+
+
+
技能标签
+
+
*
+
+
this.props.shixunssanswerkill(e)}
+ value={this.props.shixunssanswerkillvalue}
+ onPressEnter={(e)=>this.props.clickshixunsanswerskill(e)}
+ onBlur={(e)=>this.props.clickshixunsanswerskill(e)}
+ />
+ {/*
+ 添加*/}
+
学员答题正确将获得技能,否则不能获得技能
+
+ 必填项
+
+
+
+
+ {
+ this.props.shixunsskillanswerlist.length === 0 ? "" : this.props.shixunsskillanswerlist.map((itme, key) => {
+ return (
+
{itme}
+ this.props.delshixunssnswerllist(key)}>×
+
+ )
+ })
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+}
+
+
+
diff --git a/public/react/src/tpm/challengesnew/TpmQuestionMain.js b/public/react/src/tpm/challengesnew/TpmQuestionMain.js
new file mode 100644
index 000000000..614842ab8
--- /dev/null
+++ b/public/react/src/tpm/challengesnew/TpmQuestionMain.js
@@ -0,0 +1,84 @@
+import React, {Component} from 'react';
+
+import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
+import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
+
+
+export default class TpmQuestionMain extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+
+ }
+ }
+
+ componentDidMount() {
+
+ }
+
+
+ render() {
+ return (
+
+
+
+
+
+
+
+
4 || this.props.identity === undefined || this.props.power === false ? "none" : "block"}}>
+
提交
+
取消
+
+
+
+
+
+ )
+ }
+ }
+
+
+
diff --git a/public/react/src/tpm/challengesnew/TpmQuestionNew.js b/public/react/src/tpm/challengesnew/TpmQuestionNew.js
new file mode 100644
index 000000000..861c4f879
--- /dev/null
+++ b/public/react/src/tpm/challengesnew/TpmQuestionNew.js
@@ -0,0 +1,219 @@
+import React, {Component} from 'react';
+
+import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal,Tooltip} from 'antd';
+
+import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
+
+import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
+
+const Option = Select.Option;
+
+const RadioGroup = Radio.Group;
+
+export default class TpmQuestionNew extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+
+ }
+ }
+
+ componentDidMount() {
+
+ }
+
+
+ render() {
+ // console.log( this.props.questionlists)
+ return (
+
+
+
+
+
题干
+
+
*
+
+
+
+
+
+
+ 必填项
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
难度系数
+
+
+ this.props.onshixunGroupanswe(e)}
+ >
+ 简单
+ 中等
+ 困难
+
+
+
+
奖励经验值
+
+
*
+
+
+
+
+ 如果学员答题错误,则不能得到相应的经验值
+ 如果学员成功得到经验值,那么将同时获得等值的金币奖励,如:+10经验值、+10金币
+
+
+
必填项
+
+
+
+
+
技能标签
+
+
*
+
+
this.props.shixunssanswerkill(e)}
+ value={this.props.shixunssanswerkillvalue}
+ onPressEnter={(e)=>this.props.clickshixunsanswerskill(e)}
+ onBlur={(e)=>this.props.clickshixunsanswerskill(e)}
+ />
+ {/*
+ 添加*/}
+
学员答题正确将获得技能,否则不能获得技能
+
+ 必填项
+
+
+
+
+ {
+ this.props.shixunsskillanswerlist.length === 0 ? "" : this.props.shixunsskillanswerlist.map((itme, key) => {
+ return (
+
{itme}
+ this.props.delshixunssnswerllist(key)}>×
+
+ )
+ })
+ }
+
+
+
+
+
+
+
+
+
+
+
4||this.props.identity===undefined||this.props.power===false?"none":"block"}}>
+
提交
+
取消
+
+
+
+
+ )
+ }
+}
+
+
+
diff --git a/public/react/src/tpm/challengesnew/css/TPMchallengesnew.css b/public/react/src/tpm/challengesnew/css/TPMchallengesnew.css
new file mode 100644
index 000000000..37a65ef97
--- /dev/null
+++ b/public/react/src/tpm/challengesnew/css/TPMchallengesnew.css
@@ -0,0 +1,269 @@
+.CodeMirror-scroll {
+ overflow: auto !important;
+ margin-bottom: -30px;
+ margin-right: -30px;
+ padding-bottom: 30px;
+ height: 100%;
+ outline: none;
+ position: relative;
+}
+a.white-btn.orange-btn:hover {
+ border: 1px solid #F06200;
+ color: #FFF !important;
+}
+.flex1 a.white-btn.orange-btn:hover {
+ border: 1px solid #F06200;
+ color: #FFF !important;
+}
+
+/*.challenge_nav li a{*/
+ /*color:#000 !important;*/
+/*}*/
+
+.questionli{
+ width: 95%;
+ margin-left: 37px;
+}
+#directory_file{
+ height:200px;
+ overflow-y:auto;
+ background:#f5f5f5;
+ padding:10px;
+}
+.directory_filepath{
+ width:120px;
+ text-align:left;
+}
+
+a{
+ text-decoration: none;
+ color: #05101a;
+}
+.repository_url_tippostion{
+ position: absolute;
+ left: 22%;
+ width: 500px;
+ top: 100%;
+}
+
+.top-black-trangleft {
+ display: block;
+ border-width: 8px;
+ position: absolute;
+ top: -16px;
+ /* right: 4px; */
+ border-style: dashed solid dashed dashed;
+ border-color: transparent transparent rgba(5,16,26,0.6) transparent;
+ font-size: 0;
+ line-height: 0;
+}
+
+#exercisememoMD .CodeMirror {
+ margin-top: 31px !important;
+ height: 370px !important;
+ /*width: 579px !important;*/
+}
+
+#exercisememoMD .editormd-preview {
+ top: 40px !important;
+ height: 370px !important;
+ width: 578px !important;
+}
+#exercisememoMD{
+ /*height: 700px !important;*/
+}
+#questioMD{
+ /*width: 95% !important;*/
+ height: 417px !important;
+ margin-left: 0% !important;
+}
+
+
+#questioMD .CodeMirror {
+ /*width: 550.5px !important;*/
+ margin-top: 31px !important;
+ height: 374px !important;
+}
+
+#questioMD .editormd-preview {
+ top: 40px !important;
+ height: 375px !important;
+ width: 550px !important;
+}
+
+#newquestioMD .CodeMirror {
+ /*width: 549px !important;*/
+ margin-top: 31px !important;
+ height: 364px !important;
+}
+
+#newquestioMD .editormd-preview {
+ top: 40px !important;
+ height: 364px !important;
+ width: 578px !important;
+}
+
+#challenge_choose_answer .CodeMirror {
+ margin-top: 31px !important;
+ height: 364px !important;
+ /*width: 578px !important;*/
+}
+
+
+#challenge_choose_answer .editormd-preview {
+ top: 40px !important;
+ height: 364px !important;
+ width: 578px !important;
+}
+
+#neweditanswer .CodeMirror {
+ margin-top: 31px !important;
+ height: 364px !important;
+ /*width: 549.5px !important;*/
+}
+
+#neweditanswer .editormd-preview {
+ top: 40px !important;
+ height: 364px !important;
+ width: 551px !important;
+}
+
+#repository_url_tip {
+ top: 30px !important;
+ left: 249px !important;
+ width: 292px !important;
+}
+
+#editanswers .CodeMirror{
+ /*width: 548px !important;*/
+ height: 358px !important;
+ margin-top: 30px !important;
+}
+#editanswers .editormd-preview{
+ width: 578px !important;
+ height: 358px !important;
+
+}
+#newquestioMDs .CodeMirror{
+ /*width: 510px !important;*/
+ height: 358px !important;
+ margin-top: 30px !important;
+}
+
+#newquestioMDs .editormd-preview{
+ width: 578px !important;
+ height: 358px !important;
+}
+
+.choose_names{
+ width: 80px;
+ margin-left: 20px;
+}
+
+#answerMD .CodeMirror{
+ /*width: 569px !important;*/
+ height: 600px !important;
+ margin-top: 30px !important;
+}
+
+#answerMD .editormd-preview{
+ width: 578px !important;
+ height: 600px !important;
+}
+
+#answerMD {
+ height: 600px !important;
+}
+
+.textareavalue{
+ width: 100%;
+ padding: 5px;
+
+ box-sizing: border-box;
+}
+.greyInput{
+ width: 107%;
+}
+.greyInpus{
+ width: 100%;
+}
+
+.pdr20{
+ padding-right:20px;
+}
+
+.winput-240-40s {
+ background-color: #F5F5F5;
+}
+
+
+.winput-240-40s:focus{
+ background-color: #fff;
+}
+.input-100-45{
+ background-color: #F5F5F5;
+}
+.input-100-45:focus{
+ background-color: #fff;
+ }
+
+.wind100{
+ width:100% !important;
+}
+
+.color-bule-tip {
+ color: #5485f7 !important;
+}
+.martopf4{
+ margin-top:-4px;
+}
+
+.headdfgf{
+ display: block;
+ width: 100px;
+ height: 30px;
+ line-height: 30px;
+ float: left;
+}
+
+.color979797{
+ color: #979797 !important;
+}
+
+.border-left{
+ width: 0;
+ height: 0;
+ border-bottom: 6px solid transparent;
+ border-right: 6px solid #cccbcb;
+ border-top: 6px solid transparent;
+ position: absolute;
+ left: 30px;
+ top: 12px;
+}
+.border-left span{
+ display: block;
+ width: 0;
+ height: 0;
+ border-bottom: 6px solid transparent;
+ border-right: 6px solid #fff;
+ border-top: 6px solid transparent;
+ position: absolute;
+ left: 1px;
+ top: -6px;
+ z-index: 10;
+}
+.fillTip{
+ position: absolute;
+ left: 36px;
+ top: 2px;
+ width: 125px;
+ font-size: 12px;
+ display: block;
+ padding: 5px;
+ border: 1px solid #eaeaea;
+ border-radius: 5px;
+ box-sizing: border-box;
+ height: 32px;
+ line-height: 20px;
+ font-family: "微软雅黑","宋体";
+}
\ No newline at end of file
diff --git a/public/react/src/tpm/challengesnew/editorMD.js b/public/react/src/tpm/challengesnew/editorMD.js
new file mode 100644
index 000000000..50f15b601
--- /dev/null
+++ b/public/react/src/tpm/challengesnew/editorMD.js
@@ -0,0 +1,122 @@
+import React, {Component} from 'react';
+
+import {getUrl} from 'educoder';
+
+let path = getUrl("/editormd/lib/");
+
+const $ = window.$;
+
+function create_editorMD(id, width, high, placeholder, imageUrl, callback) {
+ var editorName = window.editormd(id, {
+ width: width,
+ height: high,
+ path: path, // "/editormd/lib/"
+
+ syncScrolling: "single",
+ tex: true,
+ tocm: true,
+ emoji: true,
+ taskList: true,
+ codeFold: true,
+ searchReplace: true,
+ htmlDecode: "style,script,iframe",
+ sequenceDiagram: true,
+ autoFocus: false,
+ toolbarIcons: function () {
+ // Or return editormd.toolbarModes[name]; // full, simple, mini
+ // Using "||" set icons align right.
+ return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"]
+ },
+ toolbarCustomIcons: {
+ testIcon: "",
+ testIcon1: ""
+ },
+ //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。
+ saveHTMLToTextarea: true,
+ // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标
+ dialogMaskOpacity: 0.6,
+ placeholder: placeholder,
+ imageUpload: true,
+ imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"],
+ imageUploadURL: imageUrl,//url
+ onload: function () {
+ // this.previewing();
+ $("#" + id + " [type=\"latex\"]").bind("click", function () {
+ editorName.cm.replaceSelection("```latex");
+ editorName.cm.replaceSelection("\n");
+ editorName.cm.replaceSelection("\n");
+ editorName.cm.replaceSelection("```");
+ var __Cursor = editorName.cm.getDoc().getCursor();
+ editorName.cm.setCursor(__Cursor.line - 1, 0);
+ });
+
+ $("#" + id + " [type=\"inline\"]").bind("click", function () {
+ editorName.cm.replaceSelection("`$$$$`");
+ var __Cursor = editorName.cm.getDoc().getCursor();
+ editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3);
+ editorName.cm.focus();
+ });
+ $("[type=\"inline\"]").attr("title", "行内公式");
+ $("[type=\"latex\"]").attr("title", "多行公式");
+
+ window.md_elocalStorage(editorName, `MemoQuestion_${id}`, `${id}Question`);
+
+ callback && callback()
+ }
+ });
+ return editorName;
+}
+
+
+export default class TPMeditorMD extends Component {
+ constructor(props) {
+ super(props)
+
+ }
+ componentDidMount() {
+
+
+ }
+
+ questioMD=(initValue, id)=> {
+
+ this.contentChanged = false;
+ const placeholder = "";
+// amp;
+// 编辑时要传memoId
+ // const imageUrl = `/upload_with_markdown?container_id=&container_type=Memo`;
+ const imageUrl = `/api/attachments.json`;
+// 创建editorMd
+
+ let questio_editormd = create_editorMD(id, '100%', 400, placeholder, imageUrl, () => {
+ setTimeout(() => {
+ questio_editormd.resize()
+ questio_editormd.cm && questio_editormd.cm.refresh()
+ }, 500)
+
+ if (initValue != undefined) {
+ questio_editormd.setValue(initValue)
+ }
+ questio_editormd.cm.on("change", (_cm, changeObj) => {
+ console.log('....contentChanged')
+ this.contentChanged = true;
+ })
+ });
+ this.questio_editormd = questio_editormd;
+ window.questio_editormd = questio_editormd;
+
+ }
+
+ componentWillReceiveProps(newProps) {
+ this.questioMD(newProps.value,newProps.id)
+ }
+ render() {
+ return (
+
+ )
+ }
+}
diff --git a/public/react/src/tpm/component/TPMNav.js b/public/react/src/tpm/component/TPMNav.js
new file mode 100644
index 000000000..ff8f57aa5
--- /dev/null
+++ b/public/react/src/tpm/component/TPMNav.js
@@ -0,0 +1,57 @@
+import React, { Component } from 'react';
+
+import { BrowserRouter as Router, Route, Link } from "react-router-dom";
+
+class TPMNav extends Component {
+
+ render() {
+ const { user, match, shixun, secret_repository } = this.props;
+ let isAdminOrCreator = false;
+ if (user) {
+ isAdminOrCreator = user.admin || user.manager
+ }
+ const shixunId = match.params.shixunId;
+ // const challengesPath = `/shixuns/${shixunId}/challenges`;
+ // console.log(this.props.propaedeutics)
+ const challengesPath = `/shixuns/${shixunId}/challenges`;
+ // console.log(match.path)
+ return (
+
+
任务
+
+ {
+ this.props.propaedeutics===undefined?"":this.props.propaedeutics===false?"":
背景知识
+ }
+
+ { this.props.identity >4||this.props.identity===undefined ?"":
版本库}
+ {this.props.identity >4||this.props.identity===undefined ?"": secret_repository &&
私密版本库}
+
+
合作者
+
+
评论
+
+
排行榜
+
+ {this.props.identity >2||this.props.identity===undefined?"":
审核情况}
+
+
4||this.props.identity===undefined ? "none" : 'block'}}
+ >配置
+
+ );
+ }
+}
+
+export default TPMNav;
diff --git a/public/react/src/tpm/component/TPMRightSection.js b/public/react/src/tpm/component/TPMRightSection.js
new file mode 100644
index 000000000..4306fc6e3
--- /dev/null
+++ b/public/react/src/tpm/component/TPMRightSection.js
@@ -0,0 +1,205 @@
+import React, { Component } from 'react';
+
+import { BrowserRouter as Router, Route, Link } from "react-router-dom";
+
+import axios from 'axios';
+
+import { getImageUrl,} from "educoder";
+
+import './TPMright.css';
+
+import {Icon,Tooltip} from 'antd';
+
+// import "antd/dist/antd.css";
+
+class TPMRightSection extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+
+ TPMRightSection:false,
+ clickNewsubscripttype:false
+ }
+ }
+
+ // componentDidMount() {
+ // let id=this.props.match.params.shixunId;
+ //
+ // let shixunsDetailsURL=`/shixuns/`+id+`/show_right.json`;
+ //
+ // axios.get(shixunsDetailsURL).then((response)=> {
+ // if(response.status===200){
+ // this.setState({
+ // TPMRightSectionData: response.data
+ // });
+ // }
+ // }).catch((error)=>{
+ // console.log(error)
+ // });
+ // }
+
+ // shouldComponentUpdate(nextProps, nextState) {
+ // return nextProps.TPMRightSectionData !== this.state.TPMRightSectionData
+ // }
+ clickNewsubscript=(val)=>{
+ if(val===0){
+ this.setState({
+ TPMRightSection:true,
+ clickNewsubscripttype:true
+ })
+ }else{
+ this.setState({
+ TPMRightSection:false,
+ clickNewsubscripttype:false
+ })
+ }
+
+ }
+ render() {
+ let {TPMRightSection,clickNewsubscripttype}=this.state;
+ let {TPMRightSectionData}=this.props
+
+ return (
+
+ {
+ TPMRightSectionData===undefined?"":
+
+
+
创建者
+
+
+
+
+
+
+
{TPMRightSectionData===undefined?"":TPMRightSectionData.creator===undefined?"":TPMRightSectionData.creator.name}
+
+
发布 {TPMRightSectionData.user_shixuns_count}
+ {/*
粉丝 {TPMRightSectionData.fans_count}*/}
+ {/*
取消关注 */}
+
+
+
+
+
+ {
+ TPMRightSectionData === undefined ? "" :TPMRightSectionData.tags===undefined?"": TPMRightSectionData.tags.length === 0 ? "" :
+
+
技能标签 {TPMRightSectionData.tags.length}
+
+
+ { TPMRightSectionData.tags.map((item,key)=>{
+ return(
+ {item.tag_name}
+ )})
+ }
+
+
+
+
+
15&&clickNewsubscripttype===false?"newsubscript mb9 color-grey-9":"newsubscript mb9 color-grey-9 none"}
+
+ data-tip-down="显示全部"
+ onClick={()=>this.clickNewsubscript(0)}>...
+
+
+
+
this.clickNewsubscript(1)}>
+
+
+
+
+
+ }
+
+
+
+
所属课程
+
+ {
+ TPMRightSectionData===undefined?"":TPMRightSectionData.paths===undefined?"":TPMRightSectionData.paths.map((i,k)=>{
+
+ return(
+
+
+
+
+
+
+
+
+
{i.name}
+
+
+
+ {i.stages_count}
+
+
+ {/**/}
+ {/*{i.score_count}*/}
+ {/**/}
+
+
+ {i.members_count}
+
+
+
+
+
+
+
+ )
+ })
+ }
+
+
+
+ {TPMRightSectionData === undefined?"":TPMRightSectionData.paths===undefined?"":TPMRightSectionData.paths.length === 0 ? "" :
+ this.props.user&&this.props.user.main_site===true?
+
推荐实训
+
+ {
+ TPMRightSectionData===undefined?"":TPMRightSectionData.recommands===undefined?"":TPMRightSectionData.recommands.map((item,key)=>{
+ return(
+
+ )
+ })
+ }
+
+
:""
+ }
+
+ }
+
+ )
+
+
+ }
+}
+
+export default TPMRightSection;
diff --git a/public/react/src/tpm/component/TPMright.css b/public/react/src/tpm/component/TPMright.css
new file mode 100644
index 000000000..c664d75c4
--- /dev/null
+++ b/public/react/src/tpm/component/TPMright.css
@@ -0,0 +1,79 @@
+/*bæ–°æ ‡ç¾*/
+.newedu-filter-btn{
+ display: block;
+ float: left;
+ padding: 0 9px;
+ /*height: 28px;*/
+ line-height: 28px;
+ border-radius: 14px;
+ background-color: #F5F5F5;
+ color: #666;
+ margin-right: 10px;
+ margin-bottom: 9px;
+}
+.newedbox{
+ /*flex-wrap: wrap;*/
+ /*display: -webkit-flex; !* Safari *!*/
+ /*display: flex;*/
+ width: 360px;
+ position:relative;
+ overflow: hidden;
+}
+.newsubscript{
+ position: absolute;
+ right: 23px;
+ bottom: 16px;
+ cursor: pointer;
+}
+.newsubscript:hover{
+ color:deepskyblue;
+}
+.edu-filter-btn29BD8B{
+ display: block;
+ float: left;
+ padding: 0 9px;
+ height: 28px;
+ line-height: 28px;
+ border-radius: 14px;
+ background-color: #29BD8B;
+ color: #FFF;
+ margin-right: 10px;
+ margin-bottom: 9px;
+}
+.relative{
+ position:relative;
+}
+.newedboxheight{
+ max-height: 177px;
+ overflow-y: hidden;
+}
+.newminheight{
+ /*max-height: 670px;*/
+ max-height: 300px;
+ overflow-y: auto;
+}
+
+.delSubentry{
+ font-size:7px;
+ font-family:MicrosoftYaHei;
+ font-weight:400;
+ color:rgba(76,172,255,1);
+ line-height:9px;
+ cursor: pointer;
+}
+.operationalter .delSubentry{
+ font-size:15px !important;
+ line-height: 25px;
+}
+/*临时的tpiå…³é—æŒ‰é’®æ ·å¼*/
+.headerRight a {
+ color: #1a3f5f;
+}
+/*实è®åšæˆå¼¹çª—aæ ‡ç¾æ ·å¼è°ƒæ•´*/
+.-task-list-title a:link, .-task-list-title a:visited {color: #bcc6cd;}
+.-task-list-title a:hover{
+ color: #459be5;
+}
+.headerLeft .-header-right{
+ height: 32px;
+}
\ No newline at end of file
diff --git a/public/react/src/tpm/component/modal/RepositoryChooseModal.js b/public/react/src/tpm/component/modal/RepositoryChooseModal.js
new file mode 100644
index 000000000..4b72ae2bd
--- /dev/null
+++ b/public/react/src/tpm/component/modal/RepositoryChooseModal.js
@@ -0,0 +1,153 @@
+// import React, { useState, useEffect, memo } from 'react';
+// import axios from 'axios'
+// import { Modal, Input } from 'antd';
+
+// function RepositoryChooseModal(props) {
+// const [trees, setTrees] = useState([])
+// const [path, setPath] = useState('')
+// const [pathArray, setPathArray] = useState([{val: "根目录/", path: ""}])
+// const [modalVisible, setModalVisible] = useState(true)
+
+// useEffect(() => {
+// repository('')
+// }, [])
+// function onOk() {
+
+// }
+// function onCancel() {
+
+// }
+// /**
+// 点nav 会传入key
+// 点item 会传入 newPath
+
+// item => name, type type tree/leaf
+// */
+// const repository=(item, key, newPath)=>{
+// let newPathArray = [] //
+// //
+// if (key) {
+// for(var i=0; i<=key; i++){
+// newPathArray.push(pathArray[i])
+// }
+// } else if (item) {
+// newPathArray = pathArray.slice(0)
+// newPathArray.push({val: item.name, path: pathArray[pathArray.length - 1] + "/" + item.name})
+// }
+
+// const path = item || key ? newPathArray[newPathArray.length - 1] : ''
+
+// let id = props.match.params.shixunId;
+// let url ="/shixuns/"+id+"/repository.json";
+// axios.post(url,{
+// path: path
+// }).then((response) => {
+// if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+// }else{
+// setTrees(response.data.trees)
+// setPath(path)
+// pathArray(newPathArray)
+// }
+
+// }).catch((error) => {
+// console.log(error)
+// });
+// }
+// const savegetfilepath=(value)=>{
+// const state = {}
+// let {selectpath,saveshixunfilepath,pathtype} = state
+
+// if(pathtype===1){
+// let newselectpath;
+
+// if(saveshixunfilepath==="shixunfilepathplay"){
+// newselectpath=value
+// }else{
+// const type = selectpath.split(';');
+// let types=false;
+// for(var i=0; i{
+
+// }
+// function sendgetfilepath() {
+
+// }
+// return (
+//
+//
+//
+//
+// {/*文件导航*/}
+// {
+// pathArray.length===0?"":pathArray.map((item,key)=>{
+// return(
+// goblakepath(item.path,key,item)}>{item.val}
+// )
+// })
+// }
+// {/*文件*/}
+// {trees === undefined || trees === null ? "" : trees.map((item, key) => {
+// return(
+// -
+//
+//
+
+// )
+// })}
+
+//
+//
+//
+// saveselectpath(e)}
+// value={path}/>
+//
+
+//
onOk()}>确定
+//
onCancel()}>取消
+//
+//
+//
+// )
+
+// }
+
+// export default RepositoryChooseModal
\ No newline at end of file
diff --git a/public/react/src/tpm/newshixuns/Newshixuns.js b/public/react/src/tpm/newshixuns/Newshixuns.js
new file mode 100644
index 000000000..1eaee9ad6
--- /dev/null
+++ b/public/react/src/tpm/newshixuns/Newshixuns.js
@@ -0,0 +1,1356 @@
+import React, {Component} from 'react';
+
+import {TPMIndexHOC} from '../TPMIndexHOC';
+
+import {SnackbarHOC,appendFileSizeToUploadFileAll, getUploadActionUrl} from 'educoder';
+
+import {Input, Select, Radio, Checkbox, Modal, Icon, DatePicker,Upload,Button,message,Form,notification,Tooltip} from 'antd';
+
+// import "antd/dist/antd.css";
+
+import locale from 'antd/lib/date-picker/locale/zh_CN';
+
+import axios from 'axios';
+
+import './css/Newshixuns.css';
+
+import {getUrl} from 'educoder'
+
+import moment from 'moment';
+
+let path = getUrl("/editormd/lib/")
+
+const $ = window.$;
+
+let timeout;
+
+let currentValue;
+
+const Option = Select.Option;
+
+const RadioGroup = Radio.Group;
+const confirm = Modal.confirm;
+
+
+// 处理整点 半点
+// 取传入时间往后的第一个半点
+export function handleDateStrings(dateString) {
+ if (!dateString) return dateString;
+ const ar = dateString.split(':')
+ if (ar[1] == '00' || ar[1] == '30') {
+ return dateString
+ }
+ const miniute = parseInt(ar[1]);
+ if (miniute < 30 || miniute == 60) {
+ return [ar[0], '30'].join(':')
+ }
+ if (miniute < 60) {
+ // 加一个小时
+ const tempStr = [ar[0], '00'].join(':');
+ const format = "YYYY-MM-DD HH:mm";
+ const _moment = moment(tempStr, format)
+ _moment.add(1, 'hours')
+ return _moment.format(format)
+ }
+
+ return dateString
+}
+
+
+
+// 恢复数据
+function md_rec_data(k, mdu, id, editor) {
+ if (window.sessionStorage.getItem(k + mdu) !== null) {
+ editor.setValue(window.sessionStorage.getItem(k + mdu));
+ md_clear_data(k, mdu, id);
+ }
+}
+
+// 保存数据
+function md_add_data(k, mdu, d) {
+ window.sessionStorage.setItem(k + mdu, d);
+}
+
+// 清空保存的数据
+function md_clear_data(k, mdu, id) {
+ window.sessionStorage.removeItem(k + mdu);
+ var id1 = "#e_tip_" + id;
+ var id2 = "#e_tips_" + id;
+ if (k == 'content') {
+ $(id2).html("");
+ } else {
+ $(id1).html("");
+ }
+}
+
+function md_elocalStorage(editor, mdu, id) {
+ if (window.sessionStorage) {
+ var oc = window.sessionStorage.getItem('content' + mdu);
+ if (oc !== null) {
+ $("#e_tips_" + id).data('editor', editor);
+ var h = '您上次有已保存的数据,是否恢复 ? / 不恢复';
+ $("#e_tips_" + id).html(h);
+ }
+ setInterval(function () {
+ var d = new Date();
+ var h = d.getHours();
+ var m = d.getMinutes();
+ var s = d.getSeconds();
+ h = h < 10 ? '0' + h : h;
+ m = m < 10 ? '0' + m : m;
+ s = s < 10 ? '0' + s : s;
+ if (editor.getValue().trim() != "") {
+ md_add_data("content", mdu, editor.getValue());
+ var id1 = "#e_tip_" + id;
+ var id2 = "#e_tips_" + id;
+
+ $(id1).html(" 数据已于 " + h + ':' + m + ':' + s + " 保存 ");
+ $(id2).html("");
+ }
+ }, 10000);
+
+ } else {
+ $("#e_tip_" + id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!');
+ }
+}
+
+
+function create_editorMD(id, width, high, placeholder, imageUrl, callback) {
+ var editorName = window.editormd(id, {
+ width: width,
+ height: high,
+ path: path, // "/editormd/lib/"
+
+ syncScrolling: "single",
+ tex: true,
+ tocm: true,
+ emoji: true,
+ taskList: true,
+ codeFold: true,
+ searchReplace: true,
+ htmlDecode: "style,script,iframe",
+ sequenceDiagram: true,
+ autoFocus: false,
+ toolbarIcons: function () {
+ // Or return editormd.toolbarModes[name]; // full, simple, mini
+ // Using "||" set icons align right.
+ return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"]
+ },
+ toolbarCustomIcons: {
+ testIcon: "",
+ testIcon1: ""
+ },
+ //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。
+ saveHTMLToTextarea: true,
+ // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标
+ dialogMaskOpacity: 0.6,
+ placeholder: placeholder,
+ imageUpload: true,
+ imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"],
+ imageUploadURL: imageUrl,//url
+ onload: function () {
+ // this.previewing();
+ $("#" + id + " [type=\"latex\"]").bind("click", function () {
+ editorName.cm.replaceSelection("```latex");
+ editorName.cm.replaceSelection("\n");
+ editorName.cm.replaceSelection("\n");
+ editorName.cm.replaceSelection("```");
+ var __Cursor = editorName.cm.getDoc().getCursor();
+ editorName.cm.setCursor(__Cursor.line - 1, 0);
+ });
+
+ $("#" + id + " [type=\"inline\"]").bind("click", function () {
+ editorName.cm.replaceSelection("`$$$$`");
+ var __Cursor = editorName.cm.getDoc().getCursor();
+ editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3);
+ editorName.cm.focus();
+ });
+ $("[type=\"inline\"]").attr("title", "行内公式");
+ $("[type=\"latex\"]").attr("title", "多行公式");
+
+ md_elocalStorage(editorName, `memoNew_${id}`, "memoNew");
+
+ callback && callback()
+ }
+ });
+ return editorName;
+}
+
+function range(start, end) {
+ const result = [];
+ for (let i = start; i < end; i++) {
+ result.push(i);
+ }
+ return result;
+}
+function disabledDateTime() {
+ return {
+ // disabledHours: () => range(0, 24).splice(4, 20),
+ disabledMinutes: () => range(1, 30).concat(range(31, 60)),
+ // disabledSeconds: () => [0, 60],
+ };
+}
+
+function disabledDate(current) {
+ return current && current < moment().endOf('day').subtract(1, 'days');
+}
+class Newshixuns extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ fileList: [],
+ newshixunlist: undefined,
+ departmentslist: undefined,
+ name: "",
+ main_type: "",
+ small_type: "",
+ trainee: "",
+ webssh: 0,
+ use_scope: 0,
+ can_copy: "",
+ scope_partment: undefined,
+ vnc: "",
+ scopetype: false,
+ postapplyvisible: false,
+ sendsure_applyvalue: undefined,
+ postapplytitle: false,
+ shixun_nametype: false,
+ main_types: false,
+ trainee_types: false,
+ SelectTheCommandtype: false,
+ opers: false,
+ operss: false,
+ TimePickervalue: "",
+ opensmail: false,
+ onSearchvalue: "",
+ scope_partmenttype: false,
+ languagewrite: undefined,
+ systemenvironment:undefined,
+ testcoderunmode:undefined,
+ file:undefined,
+ deleteisnot:true,
+ languagewritetype:false,
+ systemenvironmenttype:false,
+ testcoderunmodetype:false,
+ attachmentidstype:false,
+ datalisttype:false,
+ bottonloading:false
+ }
+ }
+
+ initMD(initValue) {
+ this.contentChanged = false;
+ const placeholder = "";
+ // amp;
+ // 编辑时要传memoId
+ const imageUrl = `/api/attachments.json`;
+ // 创建editorMd
+
+ const taskpass_editormd = create_editorMD("memoMD", '100%', 400, placeholder, imageUrl, () => {
+ setTimeout(() => {
+ taskpass_editormd.resize()
+ taskpass_editormd.cm && taskpass_editormd.cm.refresh()
+ }, 500)
+
+ if (initValue) {
+ taskpass_editormd.setValue(initValue)
+ }
+ taskpass_editormd.cm.on("change", (_cm, changeObj) => {
+ // console.log('....contentChanged')
+ this.contentChanged = true;
+ })
+ });
+ this.taskpass_editormd = taskpass_editormd;
+ window.taskpass_editormd = taskpass_editormd;
+
+ }
+
+ componentDidMount() {
+ let newshixunUrl = `/shixuns/new.json`;
+ axios.get(newshixunUrl).then((response) => {
+ if (response.status === 200) {
+ if (response.data.message===undefined) {
+ this.setState({
+ newshixunlist: response.data
+ });
+ this.initMD(response.data.sample[0][1]);
+ }
+
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+
+ let departmentsUrl = `/shixuns/departments.json`;
+ axios.get(departmentsUrl).then((response) => {
+ if (response.status === 200) {
+ if (response.data.message===undefined) {
+ this.setState({
+ departmentslist: response.data.shools_name
+ });
+ }
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ setlanguagewrite = (e)=>{
+ this.setState({
+ languagewrite: e.target.value
+ })
+ }
+
+ setsystemenvironment = (e) => {
+ this.setState({
+ systemenvironment: e.target.value
+ })
+ }
+ settestcoderunmode = (e) => {
+ this.setState({
+ testcoderunmode: e.target.value
+ })
+
+ }
+ shixunname = (e) => {
+ this.setState({
+ name: e.target.value,
+ shixun_nametype: false
+ });
+ }
+
+ bigClass = (value) => {
+ this.setState({
+ main_type: value
+ })
+ }
+
+ littleClass = (value) => {
+ this.setState({
+ small_type: value
+ })
+ }
+
+ Selectthestudent = (value) => {
+ this.setState({
+ trainee: value
+ })
+ }
+
+ SelectTheCommand = (e) => {
+ this.setState({
+ webssh: e.target.value,
+ });
+
+ if (e.target.value === 2) {
+ this.setState({
+ SelectTheCommandtype: true,
+ multi_webssh: false
+ });
+ } else {
+ this.setState({
+ SelectTheCommandtype: false,
+ multi_webssh: false
+ });
+ }
+ }
+
+ Selectpublic = (e) => {
+ this.setState({
+ scopetype: false,
+ use_scope: e.target.value,
+ });
+ if (e.target.value === 1) {
+ this.setState({
+ scopetype: true
+ });
+ }
+
+ }
+
+ Teacherscopy = (e) => {
+ let sum = ""
+ if (e.target.checked === false) {
+ sum = 0
+ } else if (e.target.checked === true) {
+ sum = 1
+ }
+ this.setState({
+ can_copy: sum,
+ });
+ }
+
+ TeachersUbuntu = (e) => {
+ let sum = ""
+ if (e.target.checked === false) {
+ sum = 0
+ } else if (e.target.checked === true) {
+ sum = 1
+ }
+ this.setState({
+ vnc: sum,
+ });
+ }
+
+ adduse_scopeinput = () => {
+ let {scope_partment} = this.state;
+ let array = scope_partment;
+ let newarray = ""
+ array.push(newarray)
+ this.setState({
+ scope_partment: array,
+ });
+ }
+
+ shixunScopeInput = (e, id) => {
+ let types=false
+ let {scope_partment} = this.state;
+ let datalist = scope_partment;
+ if (datalist === undefined) {
+ datalist = []
+ }
+
+ datalist.map((item,key)=>{
+ if(e===item){
+ types=true
+ this.setState({
+ datalisttype:true
+ })
+ return
+ }
+ })
+
+ if(types===false){
+ datalist.push(e)
+ this.setState({
+ scope_partment: datalist,
+ onSearchvalue: ""
+ });
+ }
+
+
+ }
+
+ deleteScopeInput = (key) => {
+ let {scope_partment} = this.state;
+ let datalist = scope_partment;
+ datalist.splice(key, 1);
+ this.setState({
+ scope_partment: datalist
+ });
+ }
+
+ //提交数据
+ submit_new_shixun = () => {
+ const mdVal = this.taskpass_editormd.getValue();
+ let {can_copy, main_type, name, scope_partment, small_type, trainee, use_scope, vnc, webssh, multi_webssh, TimePickervalue} = this.state;
+ let Url = `/shixuns.json`
+ if (name === "") {
+ this.setState({
+ shixun_nametype: true
+ })
+ this.props.showSnackbar("实训名称为空");
+ $('html').animate({
+ scrollTop: 10
+ }, 1000);
+ return
+ }
+ if (main_type === "") {
+ this.setState({
+ main_types: true
+ })
+ $('html').animate({
+ scrollTop: 700
+ }, 1000);
+ this.props.showSnackbar("请选择技术平台大类别");
+
+ return
+ }
+
+ if (use_scope === 1) {
+ if (scope_partment === undefined || scope_partment.length === 0) {
+ this.setState({
+ scope_partmenttype: true
+ })
+ $('html').animate({
+ scrollTop: 900
+ }, 1000);
+ this.props.showSnackbar("公开程度,指定单位为空");
+ return
+ }
+ }
+ if (trainee === "") {
+ this.setState({
+ trainee_types: true
+ })
+ // $('html').animate({
+ // scrollTop: 700
+ // }, 1000);
+ this.props.showSnackbar("请选择发布信息");
+ return
+ }
+ let newmulti_webssh = multi_webssh;
+ if (newmulti_webssh === true) {
+ newmulti_webssh = 1
+ } else {
+ newmulti_webssh = ""
+ }
+ this.setState({
+ bottonloading:true
+ })
+ axios.post(Url, {
+ name: name,
+ can_copy: can_copy,
+ description: mdVal,
+ main_type: main_type,
+ scope_partment: scope_partment,
+ small_type: small_type,
+ trainee: trainee,
+ use_scope: use_scope,
+ vnc: vnc,
+ webssh: webssh,
+ multi_webssh: newmulti_webssh,
+ task_pass: 1,
+ opening_time: TimePickervalue
+ }
+ ).then((response) => {
+ if (response.status === 200) {
+ window.location.href = "/shixuns/" + response.data.shixun_identifier + "/challenges";
+ // window.open("/shixuns/"+response.data.shixun_identifier+"/challenges");
+ }else{
+ this.setState({
+ bottonloading:false
+ })
+ }
+ }).catch((error) => {
+ console.log(error)
+ this.setState({
+ bottonloading:false
+ })
+ })
+ }
+
+
+ shixunsfetch = (value, callback) => {
+ if (timeout) {
+ clearTimeout(timeout);
+ timeout = null;
+ }
+ currentValue = value;
+
+ function fake() {
+ let departmentsUrl = `/shixuns/departments.json?q=` + currentValue;
+ axios.get(departmentsUrl).then((response) => {
+ if (response.data.message===undefined) {
+ callback(response.data.shools_name);
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ timeout = setTimeout(fake, 300);
+ }
+
+ shixunHandleSearch = (value) => {
+
+ this.shixunsfetch(value, departmentslist => this.setState({departmentslist}));
+
+ this.setState({
+ onSearchvalue: ""
+ })
+ }
+
+ post_apply = () => {
+ this.setState({
+ postapplyvisible: true
+ })
+ }
+ sendsure_apply = () => {
+ let {languagewrite,systemenvironment,testcoderunmode} = this.state;
+ // console.log("点击确定")
+ // console.log("languagewrite"+languagewrite);
+ // console.log("systemenvironment"+systemenvironment);
+ // console.log("testcoderunmode"+testcoderunmode);
+
+ // let attachment_ids = undefined
+ // if (this.state.fileList) {
+ // attachment_ids = this.state.fileList.map(item => {
+ // return item.response ? item.response.id : item.id
+ // })
+ // }
+ if(languagewrite === undefined || languagewrite === "" ){
+ // this.props.showNotification(`请填写该镜像是基于什么语言`);
+ this.setState({
+ languagewritetype:true
+ })
+ return
+ }
+ if(systemenvironment === undefined || systemenvironment === ""){
+ // this.props.showNotification(`请填写该镜像是基于什么语言系统环境`);
+ this.setState({
+ systemenvironmenttype:true
+ })
+ return;
+
+ }
+ if(testcoderunmode === undefined || testcoderunmode === "") {
+ // this.props.showNotification(`请填写该镜像中测试代码运行方式`);
+ this.setState({
+ testcoderunmodetype:true
+ })
+ return;
+ }
+ var attachment_ids=undefined;
+ if (this.state.fileList) {
+ attachment_ids = this.state.fileList.map(item => {
+ return item.response ? item.response.id : item.id
+ })
+ }
+
+ if( attachment_ids === undefined || attachment_ids.length===0){
+
+ // notification.open(
+ // {
+ // message: '提示',
+ // description:
+ // '请上传附件!',
+ //
+ // }
+ // )
+ this.setState({
+ attachmentidstype:true
+ })
+ return;
+ }
+ // console.log("attachment_ids"+attachment_ids);
+
+ // alert(languagewrite +" "+systemenvironment +" "+testcoderunmode + " "+attachment_ids);
+
+ var data={
+ language:languagewrite,
+ runtime:systemenvironment,
+ run_method:testcoderunmode,
+ attachment_id:attachment_ids[0],
+ }
+ var url =`/shixuns/apply_shixun_mirror.json`;
+ axios.post(url,data
+ ).then((response) => {
+
+ try {
+ if (response.data) {
+ // const { id } = response.data;
+ // if (id) {
+ if(this.state.file !== undefined){
+ console.log("549");
+ // this.deleteAttachment(this.state.file);
+ this.setState({
+ file:undefined,
+ deleteisnot:true,
+ languagewrite:"",
+ systemenvironment:"",
+ testcoderunmode:"",
+ fileList:[]
+ })
+ }else {
+ this.setState({
+ file:undefined,
+ deleteisnot:true,
+ languagewrite:"",
+ systemenvironment:"",
+ testcoderunmode:"",
+ fileList:[]
+ })
+ }
+ // this.props.showNotification('提交成功!');
+ notification.open(
+ {
+ message: '提示',
+ description:
+ '提交成功!',
+
+ }
+ )
+ this.sendhideModaly()
+ // this.props.history.push(`/courses/${cid}/graduation_topics`);
+ // }
+ }
+ }catch (e) {
+
+ }
+
+ })
+
+ }
+ sendhideModaly = () => {
+ this.setState({
+ postapplyvisible: false,
+ })
+ if(this.state.file !== undefined){
+ console.log("580");
+ // this.deleteAttachment(this.state.file);
+ this.setState({
+ file:undefined,
+ deleteisnot:true,
+ languagewrite:"",
+ systemenvironment:"",
+ testcoderunmode:"",
+ fileList:[]
+ })
+ }else {
+ this.setState({
+ file:undefined,
+ deleteisnot:true,
+ languagewrite:"",
+ systemenvironment:"",
+ testcoderunmode:"",
+ fileList:[]
+ })
+ }
+ }
+ sendsure_applyvalues = (e) => {
+ this.setState({
+ sendsure_applyvalue: e.target.value
+ })
+ }
+ yeshidemodel = () => {
+ this.setState({
+ postapplytitle: false
+ })
+ }
+
+ SelectTheCommandonChange = (e) => {
+ this.setState({
+ multi_webssh: e.target.checked
+ })
+ }
+
+
+ bigopen = (e) => {
+ this.setState({
+ opers: true
+ })
+
+ }
+
+ bigopens = (e) => {
+ this.setState({
+ opers: false,
+ operss: false,
+ opensmail: false
+ })
+
+ }
+
+ bigopensmal = (e) => {
+ this.setState({
+ opensmail: true
+ })
+
+ }
+
+ sbigopen = (e) => {
+ this.setState({
+ operss: true
+ })
+
+ }
+
+ // sbigopens=()=>{
+ // this.setState({
+ // operss:false
+ // })
+ // }
+
+ onChangeTimePicker = (value, dateString) => {
+ this.setState({
+ TimePickervalue: dateString=== ""?"":moment(handleDateStrings(dateString))
+ })
+ }
+
+ // 附件相关 START
+ handleChange = (info) => {
+ if(info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
+ let {fileList} = this.state;
+
+ if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
+ console.log("handleChange1");
+ // if(fileList.length===0){
+ let fileLists = info.fileList;
+ this.setState({
+ // fileList:appendFileSizeToUploadFileAll(fileList),
+ fileList: fileLists,
+ deleteisnot: false
+ });
+ // }
+ }
+ }
+ }
+ onAttachmentRemove = (file) => {
+ if(!file.percent || file.percent == 100){
+ confirm({
+ title: '确定要删除这个附件吗?',
+ okText: '确定',
+ cancelText: '取消',
+ // content: 'Some descriptions',
+ onOk: () => {
+ console.log("665")
+ this.deleteAttachment(file)
+ },
+ onCancel() {
+ console.log('Cancel');
+ },
+ });
+ return false;
+ }
+
+ }
+ deleteAttachment = (file) => {
+ console.log(file);
+ let id=file.response ==undefined ? file.id : file.response.id
+ const url = `/attachments/${id}.json`
+ axios.delete(url, {
+ })
+ .then((response) => {
+ if (response.data) {
+ const { status } = response.data;
+ if (status == 0) {
+ // console.log('--- success')
+
+ this.setState((state) => {
+
+ const index = state.fileList.indexOf(file);
+ const newFileList = state.fileList.slice();
+ newFileList.splice(index, 1);
+ return {
+ fileList: newFileList,
+ deleteisnot:true
+ };
+ });
+ }
+ }
+ })
+ .catch(function (error) {
+ console.log(error);
+ });
+ }
+
+
+ handleSubmit=()=>{
+ // console.log(this.state.languagewrite)
+ // console.log(this.state.systemenvironment)
+ // console.log(this.state.testcoderunmode)
+ var attachment_ids;
+ if (this.state.fileList) {
+ attachment_ids = this.state.fileList.map(item => {
+ return item.response ? item.response.id : item.id
+ })
+ }
+ // console.log(attachment_ids);
+ // var data={
+ // language:"",
+ // runtime:"",
+ // run_method:"",
+ // attachment_id:"",
+ // }
+ // axios.post(url,data
+ // ).then((response) => {
+ // if (response.data) {
+ // // const { id } = response.data;
+ // // if (id) {
+ // this.props.showNotification('提交成功!');
+ // // this.props.history.push(`/courses/${cid}/graduation_topics`);
+ // // }
+ // }
+ // })
+
+
+
+ }
+ render() {
+ const { getFieldDecorator } = this.props.form;
+ let {testcoderunmode ,systemenvironment,languagewrite,deleteisnot, fileList,TimePickervalue, scope_partmenttype, opensmail, newshixunlist, name, scope_partment, departmentslist, postapplyvisible, sendsure_applyvalue, postapplytitle, shixun_nametype, main_types, trainee_types, SelectTheCommandtype, opers, datalisttype, onSearchvalue} = this.state;
+ let options
+ if (departmentslist != undefined) {
+ options = this.state.departmentslist.map((d, k) => {
+ return (
+
+ )
+ })
+ }
+ const uploadProps = {
+ width: 600,
+ fileList,
+ multiple: true,
+ // https://github.com/ant-design/ant-design/issues/15505
+ // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
+ // showUploadList: false,
+ action: `${getUploadActionUrl()}`,
+ onChange: this.handleChange,
+ onRemove: this.onAttachmentRemove,
+ beforeUpload: (file, fileList) => {
+
+ if (this.state.fileList.length >= 1) {
+ return false
+ }
+ // console.log('beforeUpload', file.name);
+ const isLt150M = file.size / 1024 / 1024 < 50;
+ if (!isLt150M) {
+ // this.props.showNotification(`文件大小必须小于50MB`);
+ notification.open(
+ {
+ message: '提示',
+ description:
+ '文件大小必须小于50MB',
+
+ }
+ )
+ }
+ if(this.state.file !== undefined){
+ console.log("763")
+ this.setState({
+ file:file
+ })
+ }else {
+ this.setState({
+ file:file
+ })
+ }
+
+ console.log("handleChange2");
+ return isLt150M;
+ },
+ }
+ // const uploadProps = {
+ // width: 600,
+ // fileList,
+ // multiple: true,
+ // // https://github.com/ant-design/ant-design/issues/15505
+ // // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
+ // // showUploadList: false,
+ // action: `${getUrl()}/api/attachments.json`,
+ // onChange: this.handleChange,
+ // onRemove: this.onAttachmentRemove,
+ // beforeUpload: (file) => {
+ // // console.log('beforeUpload', file.name);
+ // const isLt50M = file.size / 1024 / 1024 < 50;
+ // if (!isLt50M) {
+ // this.props.showNotification('文件大小必须小于150MB!');
+ // }
+ // return isLt50M;
+ // },
+ // };
+
+ return (
+
+
+
+
+
+
+
+ 创建实训
+ {this.props.user&&this.props.user.main_site===true?实训制作指南:""}
+
+
+
+
+
+
+
+
+
+
+
技术平台
+
+
*
+
+
+
+ 列表中没有?
+ 申请新建
+
+
+
+ {/**/}
+
+
+
+
+
+
+
新建申请已提交,请等待管理员的审核
+
我们将在1-2个工作日内与您联系
+
+
+
+
+
+
+
+
+
+
请在配置页面完成后续的评测脚本设置操作
+
+ 必填项
+
+
+
+
+
+
+
命令行
+
+
+ 无命令行窗口 (选中则不给学员的实践任务提供命令窗口)
+ 命令行练习窗口 (选中则给学员提供用于练习操作的命令行窗口)
+ 命令行评测窗口 (选中则给学员提供用于关卡评测的命令行窗口)
+
+ 多个命令行窗口(选中则允许学员同时开启多个命令行窗口)
+
+
+
+
+
+
+
+
公开程度
+
+
+ 对所有公开 (选中则所有已被试用授权的用户可以学习)
+ 对指定单位公开 (选中则下方指定单位的已被试用授权的用户可以学习)
+
+
+
+
+
+
+
+
+ {
+ scope_partment === undefined ? "" : scope_partment.map((item, key) => {
+ return (
+
{item}
+ this.deleteScopeInput(key)}>×
+
+ )
+ })
+ }
+
+ {/*{*/}
+ {/*scope_partment===undefined?"":scope_partment.map((item,key)=>{*/}
+ {/*return(*/}
+ {/*
*/}
+ {/*this.deleteScopeInput(key)} style={{ color: 'rgba(0,0,0,.25)' }} />}*/}
+ {/*value={item}*/}
+ {/*/>*/}
+ {/*
*/}
+
+ {/*)*/}
+ {/*})*/}
+ {/*}*/}
+
+
+
+
+ 请选择需要公开的单位
+
+
+
+
+
+
+
+
+
发布信息
+
+
+
*面向学员:
+
+
+
+
实训难易度定位,不限定用户群体
+
+ 必填项
+
+
+
+
+ 复制:
+
+
+
+
+ 开启时间:
+
+
+
+
+
+
+ {/*
*/}
+ {/*
VNC图形化
*/}
+ {/*
*/}
+ {/**/}
+ {/**/}
+ {/**/}
+ {/*
*/}
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+const NewshixunsNew = Form.create({ name: 'newshixunsnew' })(Newshixuns);
+export default SnackbarHOC()(TPMIndexHOC(NewshixunsNew));
+
+
+
+
+
+
diff --git a/public/react/src/tpm/newshixuns/TPMNewshixuns/TPMNewshixuns.js b/public/react/src/tpm/newshixuns/TPMNewshixuns/TPMNewshixuns.js
new file mode 100644
index 000000000..8b102651f
--- /dev/null
+++ b/public/react/src/tpm/newshixuns/TPMNewshixuns/TPMNewshixuns.js
@@ -0,0 +1,19 @@
+import React, { Component } from 'react';
+
+import axios from 'axios';
+
+export default class TPMNewshixuns extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+
+ }
+ }
+ render() {
+ return (
+
+ );
+ }
+}
+
+
diff --git a/public/react/src/tpm/newshixuns/css/Newshixuns.css b/public/react/src/tpm/newshixuns/css/Newshixuns.css
new file mode 100644
index 000000000..e241dcf0d
--- /dev/null
+++ b/public/react/src/tpm/newshixuns/css/Newshixuns.css
@@ -0,0 +1,397 @@
+/* BASICS */
+
+.CodeMirror {
+ /* Set height, width, borders, and global font properties here */
+ font-family: monospace;
+ height: 300px;
+ color: black;
+ direction: ltr;
+}
+
+/* PADDING */
+
+.CodeMirror-lines {
+ padding: 4px 0; /* Vertical padding around content */
+}
+.CodeMirror pre {
+ padding: 0 4px; /* Horizontal padding of content */
+}
+
+.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+ background-color: white; /* The little square between H and V scrollbars */
+}
+
+/* GUTTER */
+
+.CodeMirror-gutters {
+ border-right: 1px solid #ddd;
+ background-color: #f7f7f7;
+ white-space: nowrap;
+}
+.CodeMirror-linenumbers {}
+.CodeMirror-linenumber {
+ padding: 0 3px 0 5px;
+ min-width: 20px;
+ text-align: right;
+ color: #999;
+ white-space: nowrap;
+}
+
+.CodeMirror-guttermarker { color: black; }
+.CodeMirror-guttermarker-subtle { color: #999; }
+
+/* CURSOR */
+
+.CodeMirror-cursor {
+ border-left: 1px solid black;
+ border-right: none;
+ width: 0;
+}
+/* Shown when moving in bi-directional text */
+.CodeMirror div.CodeMirror-secondarycursor {
+ border-left: 1px solid silver;
+}
+.cm-fat-cursor .CodeMirror-cursor {
+ width: auto;
+ border: 0 !important;
+ background: #7e7;
+}
+.cm-fat-cursor div.CodeMirror-cursors {
+ z-index: 1;
+}
+.cm-fat-cursor-mark {
+ background-color: rgba(20, 255, 20, 0.5);
+ -webkit-animation: blink 1.06s steps(1) infinite;
+ animation: blink 1.06s steps(1) infinite;
+}
+.cm-animate-fat-cursor {
+ width: auto;
+ border: 0;
+ -webkit-animation: blink 1.06s steps(1) infinite;
+ animation: blink 1.06s steps(1) infinite;
+ background-color: #7e7;
+}
+@-webkit-keyframes blink {
+ 0% {}
+ 50% { background-color: transparent; }
+ 100% {}
+}
+@keyframes blink {
+ 0% {}
+ 50% { background-color: transparent; }
+ 100% {}
+}
+
+/* Can style cursor different in overwrite (non-insert) mode */
+.CodeMirror-overwrite .CodeMirror-cursor {}
+
+.cm-tab { display: inline-block; text-decoration: inherit; }
+
+.CodeMirror-rulers {
+ position: absolute;
+ left: 0; right: 0; top: -50px; bottom: -20px;
+ overflow: hidden;
+}
+.CodeMirror-ruler {
+ border-left: 1px solid #ccc;
+ top: 0; bottom: 0;
+ position: absolute;
+}
+
+/* DEFAULT THEME */
+
+.cm-s-default .cm-header {color: blue;}
+.cm-s-default .cm-quote {color: #090;}
+.cm-negative {color: #d44;}
+.cm-positive {color: #292;}
+.cm-header, .cm-strong {font-weight: bold;}
+.cm-em {font-style: italic;}
+.cm-link {text-decoration: underline;}
+.cm-strikethrough {text-decoration: line-through;}
+
+.cm-s-default .cm-keyword {color: #708;}
+.cm-s-default .cm-atom {color: #219;}
+.cm-s-default .cm-number {color: #164;}
+.cm-s-default .cm-def {color: #00f;}
+.cm-s-default .cm-variable,
+.cm-s-default .cm-punctuation,
+.cm-s-default .cm-property,
+.cm-s-default .cm-operator {}
+.cm-s-default .cm-variable-2 {color: #05a;}
+.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
+.cm-s-default .cm-comment {color: #a50;}
+.cm-s-default .cm-string {color: #a11;}
+.cm-s-default .cm-string-2 {color: #f50;}
+.cm-s-default .cm-meta {color: #555;}
+.cm-s-default .cm-qualifier {color: #555;}
+.cm-s-default .cm-builtin {color: #30a;}
+.cm-s-default .cm-bracket {color: #997;}
+.cm-s-default .cm-tag {color: #170;}
+.cm-s-default .cm-attribute {color: #00c;}
+.cm-s-default .cm-hr {color: #999;}
+.cm-s-default .cm-link {color: #00c;}
+
+.cm-s-default .cm-error {color: #f00;}
+.cm-invalidchar {color: #f00;}
+
+.CodeMirror-composing { border-bottom: 2px solid; }
+
+/* Default styles for common addons */
+
+div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
+.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
+.CodeMirror-activeline-background {background: #e8f2ff;}
+
+/* STOP */
+
+/* The rest of this file contains styles related to the mechanics of
+ the editor. You probably shouldn't touch them. */
+
+.CodeMirror {
+ position: relative;
+ overflow: hidden;
+ background: white;
+}
+
+.CodeMirror-scroll {
+ overflow: scroll !important; /* Things will break if this is overridden */
+ /* 30px is the magic margin used to hide the element's real scrollbars */
+ /* See overflow: hidden in .CodeMirror */
+ margin-bottom: -30px; margin-right: -30px;
+ padding-bottom: 30px;
+ height: 100%;
+ outline: none; /* Prevent dragging from highlighting the element */
+ position: relative;
+}
+.CodeMirror-sizer {
+ position: relative;
+ border-right: 30px solid transparent;
+}
+
+/* The fake, visible scrollbars. Used to force redraw during scrolling
+ before actual scrolling happens, thus preventing shaking and
+ flickering artifacts. */
+.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+ position: absolute;
+ z-index: 6;
+ display: none;
+}
+.CodeMirror-vscrollbar {
+ right: 0; top: 0;
+ overflow-x: hidden;
+ overflow-y: scroll;
+}
+.CodeMirror-hscrollbar {
+ bottom: 0; left: 0;
+ overflow-y: hidden;
+ overflow-x: scroll;
+}
+.CodeMirror-scrollbar-filler {
+ right: 0; bottom: 0;
+}
+.CodeMirror-gutter-filler {
+ left: 0; bottom: 0;
+}
+
+.CodeMirror-gutters {
+ position: absolute; left: 0; top: 0;
+ min-height: 100%;
+ z-index: 3;
+}
+.CodeMirror-gutter {
+ white-space: normal;
+ height: 100%;
+ display: inline-block;
+ vertical-align: top;
+ margin-bottom: -30px;
+}
+.CodeMirror-gutter-wrapper {
+ position: absolute;
+ z-index: 4;
+ background: none !important;
+ border: none !important;
+}
+.CodeMirror-gutter-background {
+ position: absolute;
+ top: 0; bottom: 0;
+ z-index: 4;
+}
+.CodeMirror-gutter-elt {
+ position: absolute;
+ cursor: default;
+ z-index: 4;
+}
+.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
+.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
+.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
+
+.CodeMirror-lines {
+ cursor: text;
+ min-height: 1px; /* prevents collapsing before first draw */
+}
+.CodeMirror pre {
+ /* Reset some styles that the rest of the page might have set */ border-radius: 0;
+ border-width: 0;
+ background: transparent;
+ font-family: inherit;
+ font-size: inherit;
+ margin: 0;
+ white-space: pre;
+ word-wrap: normal;
+ line-height: inherit;
+ color: inherit;
+ z-index: 2;
+ position: relative;
+ overflow: visible;
+ -webkit-tap-highlight-color: transparent;
+ -webkit-font-variant-ligatures: contextual;
+ font-variant-ligatures: contextual;
+}
+.CodeMirror-wrap pre {
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ word-break: normal;
+}
+
+.CodeMirror-linebackground {
+ position: absolute;
+ left: 0; right: 0; top: 0; bottom: 0;
+ z-index: 0;
+}
+
+.CodeMirror-linewidget {
+ position: relative;
+ z-index: 2;
+ padding: 0.1px; /* Force widget margins to stay inside of the container */
+}
+
+.CodeMirror-widget {}
+
+.CodeMirror-rtl pre { direction: rtl; }
+
+.CodeMirror-code {
+ outline: none;
+}
+
+/* Force content-box sizing for the elements where we expect it */
+.CodeMirror-scroll,
+.CodeMirror-sizer,
+.CodeMirror-gutter,
+.CodeMirror-gutters,
+.CodeMirror-linenumber {
+ -webkit-box-sizing: content-box;
+ box-sizing: content-box;
+}
+
+.CodeMirror-measure {
+ position: absolute;
+ width: 100%;
+ height: 0;
+ overflow: hidden;
+ visibility: hidden;
+}
+
+.CodeMirror-cursor {
+ position: absolute;
+ pointer-events: none;
+}
+.CodeMirror-measure pre { position: static; }
+
+div.CodeMirror-cursors {
+ visibility: hidden;
+ position: relative;
+ z-index: 3;
+}
+div.CodeMirror-dragcursors {
+ visibility: visible;
+}
+
+.CodeMirror-focused div.CodeMirror-cursors {
+ visibility: visible;
+}
+
+.CodeMirror-selected { background: #d9d9d9; }
+.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
+.CodeMirror-crosshair { cursor: crosshair; }
+.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
+.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
+.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
+
+.cm-searching {
+ background-color: #ffa;
+ background-color: rgba(255, 255, 0, .4);
+}
+
+/* Used to force a border model for a node */
+.cm-force-border { padding-right: .1px; }
+
+@media print {
+ /* Hide the cursor when printing */
+ .CodeMirror div.CodeMirror-cursors {
+ visibility: hidden;
+ }
+}
+
+/* See issue #2901 */
+.cm-tab-wrap-hack:after { content: ''; }
+
+/* Help users use markselection to safely style text background */
+span.CodeMirror-selectedtext { background: none; }
+
+
+
+
+.radioStyle{
+ display: block;
+ height: 30px;
+ }
+a.white-btn.use_scope-btn:hover{
+
+}
+.shixunScopeInput{
+ width:218px;
+ height:33px;
+ display:block;
+ margin-bottom:15px;
+}
+
+#memoMD .CodeMirror {
+ /*width: 576px !important;*/
+ margin-top: 31px !important;
+ height: 364px !important;
+}
+
+#memoMD .editormd-preview {
+ width: 578px !important;
+ top: 40px !important;
+ height: 364px !important;
+}
+
+.ml36{
+ margin-left: 26px;
+}
+#person-unit a.white-btn.use_scope-btn:hover {
+ border: 1px solid #F06200;
+ color:#FFF !important;
+}
+
+.shixunspanred{
+ margin-left: 142px;
+ margin-top: 5px;
+ margin-bottom: 5px;
+}
+
+.ml82{
+ margin-left: 82px;
+}
+
+.ant-btn-primary.active, .ant-btn-primary:active {
+ color: #fff;
+ background-color: #096dd9;
+ border-color: #096dd9;
+}
+
+.ant-btn:hover, .ant-btn:focus, .ant-btn:active, .ant-btn.active{
+ background-color: #4CACFF;
+}
\ No newline at end of file
diff --git a/public/react/src/tpm/roundedRectangle.png b/public/react/src/tpm/roundedRectangle.png
new file mode 100755
index 0000000000000000000000000000000000000000..0d2d0b0dcdb359def884705254f050d1fbdcb3fb
GIT binary patch
literal 720
zcmV;>0x$iEP)7i5*ItXH}O~epQUU@HhV58rh1Hvd($Uc{~fs`t{WtAox?*xd!!y}DOtA`$57
zLY|)^QYobCBD`;Yr82JGz!@)1cQ*z
z!_W{i5J0S~ToGY^e4O2hiAqE@{{u?X1RqfE4-ODpTgdr&7#@aj7_q*NY;5GXwUtBQ
z)G&Bv+iaUAztw#}LwrviVMS9fBDu5#jsq<%2+KkNMRPMOEFk;(5Xq#LCpS7u{q!_n
z+Sa7-)NP@?@QOwQd_d*ESt3Dxb(Ok-0n!^A)P_QYdwMt+
z8{=?tQX5pj$F_~*0sU2^QcweFQGi+Ct@c34W?2xAmvR`1P_Qgc;&FaC4ld9%I7mZ#
zJF-|Lv$Mm=+FGRw1Ca<1EsLXgT(?8HHi}*!O8BITCRi+uwpRke7flH{;0QPd&VX94
z+LUwUb4nTYu8gYXGp@gT|J(vBK7jYWaaXz^;VbamyT1m!5Rkpir19Uq4!94r0-u4`
zq7+=!)^$KNiDG)P`&*_;$V)&8_kcG7rmJNCikZJnpcOq`ZNy>#0000 {
+ let id = this.props.match.params.shixunId;
+ let ChallengesURL = `/shixuns/` + id + `/challenges.json`;
+
+ axios.get(ChallengesURL).then((response) => {
+ if (response.status === 200) {
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else{
+ configShareForCustom(this.props.shixunsDetails.name, response.data.description)
+ this.setState({
+ ChallengesDataList: response.data,
+ sumidtype: false,
+ });
+ }
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ componentDidMount() {
+ setTimeout(this.ChallengesList(), 1000);
+ }
+
+ updatamakedown = (id) => {
+ setTimeout(() => {
+ var shixunDescr = window.editormd.markdownToHTML(id, {
+ htmlDecode: "style,script,iframe",
+ taskList: true,
+ tex: true,
+ flowChart: true,
+ sequenceDiagram: true
+ });
+ $("#" + id + " p:first").addClass("ReactMarkdown");
+ }, 200)
+ }
+
+ // 关卡的上移下移操作
+ operations = (sumid, type) => {
+ this.setState({
+ operationstrue:true
+ })
+ let { ChallengesDataList } = this.state;
+ let operationUrl;
+ if (type === "up") {
+ operationUrl = "/shixuns/" + ChallengesDataList.shixun_identifier + "/challenges/" + sumid + "/index_up.json";
+ } else if (type === "down") {
+ operationUrl = "/shixuns/" + ChallengesDataList.shixun_identifier + "/challenges/" + sumid + "/index_down.json";
+ }
+ if (this.state.operate) {
+
+ this.setState({
+ operate: false
+ });
+ axios.get(operationUrl).then((response) => {
+ if (response.status === 200) {
+ this.setState({
+ operate: true,
+ operationstrue:false
+ });
+ this.ChallengesList();
+
+ }
+ }).catch((error) => {
+ console.log(error);
+ this.setState({
+ operate: true,
+ operationstrue:false
+ });
+ this.ChallengesList()
+ })
+ }
+ }
+ delOperations = (sumid) => {
+ this.setState({
+ sumid: sumid,
+ sumidtype: true
+ })
+ }
+
+ clonedelOperationss = () => {
+ this.setState({
+ sumidtype: false
+ })
+ }
+ delOperationss = () => {
+ let { ChallengesDataList, sumid } = this.state;
+ let operationUrl = "/shixuns/" + ChallengesDataList.shixun_identifier + "/challenges/" + sumid+".json"
+
+ if (this.state.operate) {
+ this.setState({
+ operate: false,
+ sumidtype: false
+ })
+ axios.delete(operationUrl, {
+ withCredentials: true
+ }).then((response) => {
+ if (response.status === 200) {
+ this.setState({
+ operate: true,
+ sumidtype: false
+ });
+ this.ChallengesList();
+ }
+ this.ChallengesList()
+ }).catch((error) => {
+ console.log(error);
+ this.setState({
+ operate: true,
+ sumidtype: false
+ });
+ this.ChallengesList()
+ })
+ }
+ }
+
+ startgameid=(id)=>{
+
+ let url = "/shixuns/" + id + "/shixun_exec.json";
+ axios.get(url).then((response) => {
+
+ if (response.data.status === -2) {
+ this.setState({
+ shixunsreplace:true,
+ hidestartshixunsreplacevalue:response.data.message+".json"
+ })
+ } else if (response.data.status === -1) {
+ console.log(response)
+ }else if(response.data.status===-3){
+ this.setState({
+ shixunsmessage:response.data.message,
+ startshixunCombattype:true,
+ })
+ } else {
+ window.location.href = "/tasks/" + response.data.game_identifier;
+ // window.location.href = path
+ // let path="/tasks/"+response.data.game_identifier;
+ // this.props.history.push(path);
+ }
+ }).catch((error) => {
+
+ });
+
+
+ }
+
+ hidestartshixunsreplace=(url)=>{
+ this.setState({
+ isSpin:true,
+ })
+ axios.get(url).then((response) => {
+ if(response.status===200){
+ // let path="/shixuns/"+response.data.shixun_identifier+"/challenges";
+ // this.props.history.push(path);
+ message.success('重置成功,正在进入实训!');
+ this.startgameid(response.data.shixun_identifier);
+ this.setState({
+ shixunsreplace:false,
+ isSpin:false,
+ })
+
+ // message.success('重置成功,正在进入实训!');
+ // this.startshixunCombat();
+ }}
+ ).catch((error) => {
+
+ });
+
+ }
+
+ //编辑实训题目选择题
+ EditTraining=(type, ids, path)=>{
+ let { ChallengesDataList } = this.state;
+ window.location.href = "/shixuns/" + ChallengesDataList.shixun_identifier + "/challenges/" + ids + path;
+ }
+
+ //开始实战按钮
+ startshixunCombat = (type, ids, id) => {
+
+ if(this.props.checkIfLogin()===false){
+ this.props.showLoginDialog()
+ return
+ }
+
+ if(this.props.checkIfProfileCompleted()===false){
+ this.setState({
+ AccountProfiletype:true
+ })
+ return
+ }
+
+ // if(this.props.checkIfProfessionalCertification()===false){
+ // this.setState({
+ // AccountProfiletype:true
+ // })
+ // return
+ // }
+
+
+ let { ChallengesDataList } = this.state;
+ // let id = this.props.match.params.shixunId;
+ this.setState({
+ startbtns: true
+ })
+ let url = "/shixuns/" + ChallengesDataList.shixun_identifier + "/shixun_exec.json?challenge_id="+id;
+ axios.get(url).then((response) => {
+
+ if (response.data.status === -2) {
+ this.setState({
+ startbtns:false,
+ shixunsreplace:true,
+ hidestartshixunsreplacevalue:response.data.message+".json"
+ })
+ } else if (response.data.status === -1) {
+ this.setState({
+ startbtns: false
+ })
+ console.log(response)
+ }else if(response.data.status===-3){
+ this.setState({
+ shixunsmessage:response.data.message,
+ startshixunCombattype:true,
+ startbtns:false
+ })
+ } else {
+ window.location.href = "/tasks/" + response.data.game_identifier;
+ // window.location.href = path
+ // let path="/tasks/"+response.data.game_identifier;
+ // this.props.history.push(path);
+ }
+ }).catch((error) => {
+
+ });
+
+
+ // if(path===null){
+ // }else{
+ // if (type > 4 || type === false) {
+ // window.location.href = path;
+ // } else {
+ //
+ // }
+ // }
+
+
+ }
+ hidestartshixunCombattype=()=>{
+ this.setState({
+ startshixunCombattype:false
+ })
+ }
+
+ hideAccountProfile=()=>{
+ this.setState({
+ AccountProfiletype:false
+ })
+ }
+
+ render() {
+ let { ChallengesDataList, startbtns, sumidtype ,startshixunCombattype,shixunsreplace,shixunsmessage,hidestartshixunsreplacevalue,operationstrue,AccountProfiletype} = this.state;
+ let { loadingContent } = this.props;
+ if (ChallengesDataList != undefined) {
+ this.updatamakedown("ReactMarkdown")
+ }
+ let id = this.props.match.params.shixunId;
+ const antIcon = ;
+ return (
+
+ {AccountProfiletype===true?this.hideAccountProfile()}
+ {...this.props}
+ {...this.state}
+ />:""}
+
+ {loadingContent ?
+ :
+
+
+
+ {this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status=== 0 ?
+
+
+
+ 实践任务
+
+
+ : ""
+ }
+ {this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status=== 0 ?
+
+
+
+ 选择题任务
+
+ : ""
+ }
+
+
+ 简介
+
+
+
+
+
+
+
+
+
+
+ {ChallengesDataList === undefined ? "" :ChallengesDataList&&ChallengesDataList.description===null?"":
+
+ }
+
+
+ {/*
+
+ */}
+
+
+
+ 全部任务
+ {this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status=== 0 ?
+
+
+
+ 实践任务
+
+
+ : ""
+ }
+ {this.props.identity < 5 && ChallengesDataList&&ChallengesDataList.shixun_status=== 0 ?
+
+
+
+ 选择题任务
+
+ : ""
+ }
+
+
+
+ {ChallengesDataList === undefined ?
+
+
})
+
暂时还没有相关数据哦!
+
+
: ChallengesDataList.challenge_list === undefined ?
+
+
+
})
+
暂时还没有相关数据哦!
+
+
+ : ChallengesDataList.challenge_list.length === 0 ?
+
+
+
})
+
暂时还没有相关数据哦!
+
+
+ : ChallengesDataList.challenge_list.map((item, key) => {
+
+ let newstatus = 2;
+ if(ChallengesDataList.challenge_list[key - 1]!=undefined){
+ newstatus=ChallengesDataList.challenge_list[key - 1].status;
+ }
+ return (
+
+ )
+ })}
+
+
+
+
+
+
+
+
+
目前该实训项目尚在内测中,将于{shixunsmessage}之后开放,谢谢!
+
+
+ {/**/}
+ {/*知道了*/}
+ {/*
*/}
+
+
+
+
+
+
+
+
+
+ }
+
+
+ )
+ }
+}
+
+export default Challenges;
+ // {
+ // ChallengesDataList.allow_skip === false ? item.status === 1 && newstatus === 2 ?
+ //
+ // this.startshixunCombat(false,undefined, item.challenge_id)}
+ // style={{marginTop: '-2px'}}>直接挑战
+ //
+ //
+ // : item.status === 1 && newstatus === 1 ?
+ //
+ // this.startshixunCombat(false,undefined, item.challenge_id)}
+ // style={{marginTop: '-2px'}}>直接挑战
+ // : "" : ""
+ //
+ // }
\ No newline at end of file
diff --git a/public/react/src/tpm/shixunchild/Collaborators/Collaborators.css b/public/react/src/tpm/shixunchild/Collaborators/Collaborators.css
new file mode 100644
index 000000000..31917086f
--- /dev/null
+++ b/public/react/src/tpm/shixunchild/Collaborators/Collaborators.css
@@ -0,0 +1,9 @@
+.height40 {
+ height: 30px;
+ line-height: 30px;
+}
+
+.line27{
+ line-height: 27px;
+ vertical-align: 1px;
+}
\ No newline at end of file
diff --git a/public/react/src/tpm/shixunchild/Collaborators/Collaborators.js b/public/react/src/tpm/shixunchild/Collaborators/Collaborators.js
new file mode 100644
index 000000000..d67599bf1
--- /dev/null
+++ b/public/react/src/tpm/shixunchild/Collaborators/Collaborators.js
@@ -0,0 +1,658 @@
+import React, { Component } from 'react';
+
+import { Redirect } from 'react-router';
+
+import {Modal, Button, Radio, Input, Checkbox,message,Spin, Icon} from 'antd';
+
+import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
+
+import PropTypes from 'prop-types';
+
+import classNames from 'classnames';
+
+import { CircularProgress } from 'material-ui/Progress';
+
+import { getImageUrl, toPath } from 'educoder'
+
+import axios from 'axios';
+
+import NoneData from "../../../courses/coursesPublic/NoneData";
+
+import './Collaborators.css';
+
+
+const $ = window.$;
+
+const RadioGroup = Radio.Group;
+
+const Search = Input.Search;
+
+class Collaborators extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ collaboratorList: [],
+ Collaboratorsvisible: false,
+ Collaboratorsvisibleadmin: false,
+ value: 1,
+ page: 1,
+ Searchadmin: undefined,
+ allChangechecked: false,
+ Collaboratorslist: [],
+ Collaboratorslisttype: false,
+ collaborators_deletetype: false,
+ collaborators_deletevalue: null,
+ onSearchcalue:"",
+ collaboratorListsum:10,
+ collaboratorListsumtype:true,
+ user_name:undefined,
+ school_name:undefined,
+ spinnings:false,
+ useristrue:false
+ }
+ }
+ componentDidMount() {
+ let id=this.props.match.params.shixunId;
+
+ let collaborators=`/shixuns/`+id+`/collaborators.json`;
+ axios.get(collaborators).then((response)=> {
+ if(response.status===200){
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else{
+ this.setState({
+ collaboratorList: response.data
+ });
+ }
+
+ }
+ }).catch((error)=>{
+ console.log(error)
+ });
+ }
+
+ updatacomponentDiddata = () => {
+ let id = this.props.match.params.shixunId;
+
+ let collaborators = `/shixuns/` + id + `/collaborators.json`;
+ axios.get(collaborators).then((response) => {
+ if (response.status === 200) {
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else{
+ this.setState({
+ collaboratorList: response.data
+ });
+ }
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+ CollaboratorsshowModal = (type) => {
+
+ if (type === "cooperation") {
+ this.setState({
+ Collaboratorsvisibleadmin: false,
+ Collaboratorslist:[],
+ Searchadmin:[]
+ });
+ } else if (type === "admin") {
+ this.setState({
+ Collaboratorsvisible: false,
+ Collaboratorslist:[],
+ Searchadmin:[]
+ });
+ } else if (type === "collaborators_deletetype") {
+ this.setState({
+ collaborators_deletetype: false,
+ });
+ }
+ }
+
+ showCollaboratorsvisible = (type) => {
+
+ this.setState({
+ Collaboratorslist: [],
+ Searchadmin:undefined,
+ onSearchcalue:""
+ })
+ let admintype = this.props.identity;
+ if (admintype>4) {
+ this.props.showSnackbar("您没有权限");
+ return
+ }
+ if (type === "cooperation") {
+ this.setState({
+ Collaboratorsvisibleadmin: true,
+ });
+ } else if ("admin") {
+ let id = this.props.match.params.shixunId;
+ let url = "/shixuns/" + id + "/change_manager.json";
+ axios.get(url).then((response) => {
+ if (response.status === 200) {
+ // this.setState({
+ // Collaboratorsvisible: true
+ // })
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else{
+ this.setState({
+ Collaboratorsvisible: true,
+ Collaboratorslist: response.data
+ })
+ }
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+
+ }
+ }
+
+ onChange = (e) => {
+ this.setState({
+ value: e.target.value,
+ });
+ }
+ onSearchadmins=(e)=>{
+ this.setState({
+ onSearchcalue:e.target.value
+ })
+ }
+ onSearchadmin = (value) => {
+
+ let {collaboratorList,user_name,school_name} = this.state;
+ this.setState({
+ // Searchadmin: undefined,
+ spinnings:true,
+ })
+ // if (value === "") {
+ // this.setState({
+ // Searchadmin: [],
+ // collaboratorList: collaboratorList
+ // })
+ // } else {
+ //
+ // }
+ let id = this.props.match.params.shixunId;
+ let url = "/shixuns/" + id + "/add_collaborators.json";
+ axios.get(url,{params:{
+ user_name:user_name ,
+ school_name:school_name,
+ }}).then((response) => {
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+ this.setState({
+ spinnings:false
+ })
+ }else{
+ let newlist = response.data.users;
+ for (var i = 0; i < newlist.length; i++) {
+ newlist[i].checked = false
+ }
+ this.setState({
+ Searchadmin: newlist,
+ collaboratorList: collaboratorList,
+ spinnings:false
+ })
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ selectChangenickname = (e, key) => {
+
+ let {Searchadmin} = this.state;
+ let newlist = Searchadmin;
+ for (var i = 0; i < newlist.length; i++) {
+ newlist[key].checked = e.target.checked
+ }
+
+ let arrlist = [];
+ let alltype = false;
+ for (var z = 0; z < newlist.length; z++) {
+ if (newlist[z].checked === true) {
+ arrlist.push(newlist[z])
+ }
+ }
+
+ if (Searchadmin.length === arrlist.length) {
+ alltype = true
+ } else {
+ alltype = false
+ }
+
+ if(newlist.length===0){
+ this.setState({
+ Searchadmin: newlist,
+ allChangechecked: alltype,
+ })
+ }else{
+ this.setState({
+ Searchadmin: newlist,
+ allChangechecked: alltype,
+ useristrue:false
+ })
+ }
+
+
+ }
+ allChange = (e) => {
+
+ let {Searchadmin} = this.state;
+ let newlist = Searchadmin;
+ for (var i = 0; i < newlist.length; i++) {
+ newlist[i].checked = e.target.checked
+ }
+ this.setState({
+ Searchadmin: newlist,
+ allChangechecked: e.target.checked
+ })
+ }
+ submit_add_collaborators_form = () => {
+
+ let id = this.props.match.params.shixunId;
+ let {Searchadmin,collaboratorList} = this.state;
+ let newlist = Searchadmin;
+ let user_ids = []
+ if (newlist.length === 0) {
+ this.setState({
+ Collaboratorslisttype: true
+ })
+ return
+ }
+ for (var i = 0; i < newlist.length; i++) {
+ if (newlist[i].checked === true) {
+ user_ids.push(newlist[i].user_id)
+ }
+ }
+
+ for(var i=0; i {
+ this.updatacomponentDiddata();
+ this.props.showSnackbar(response.data.message);
+ this.setState({
+ Collaboratorsvisibleadmin: false,
+ Collaboratorslist:[],
+ Searchadmin:[]
+ })
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+ addadminredio = (e) => {
+ this.setState({
+ addadminrediovalue: e
+ })
+
+ }
+ submit_addadminredio = () => {
+
+ let {addadminrediovalue} = this.state;
+
+ let id = this.props.match.params.shixunId;
+
+ let url = "/shixuns/" + id + "/change_manager.json";
+ if(addadminrediovalue===undefined){
+ this.setState({
+ Collaboratorsvisible: false,
+ Collaboratorslist:[],
+ Searchadmin:[]
+ });
+ this.props.showSnackbar("所选人员为空,没有更换成功");
+ this.CollaboratorsshowModal("admin")
+ return
+ }
+
+
+ axios.post(url, {
+ user_id: addadminrediovalue
+ }).then((response) => {
+ this.setState({
+ Collaboratorsvisible: false,
+ Collaboratorslist:[],
+ Searchadmin:[]
+ });
+ this.updatacomponentDiddata();
+ this.props.showSnackbar(response.data.message);
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ collaborators_delete = (value) => {
+ this.setState({
+ collaborators_deletetype: true,
+ collaborators_deletevalue: value
+ })
+
+ }
+ collaborators_deletes = () => {
+ let {collaborators_deletevalue} = this.state;
+ if (collaborators_deletevalue === null) {
+ return
+ }
+ let id = this.props.match.params.shixunId;
+ let url = "/shixuns/" + id + "/collaborators_delete.json?user_id=" + collaborators_deletevalue;
+ axios.delete(url).then((response) => {
+ if (this.props.current_user.user_id == collaborators_deletevalue) {
+ this.props.history.push('/shixuns')
+ return;
+ }
+ this.props.showSnackbar(response.data.message);
+ this.updatacomponentDiddata();
+ this.setState({
+ collaborators_deletetype: false
+ })
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ loadMore=()=>{
+ let {collaboratorList}=this.state;
+ this.setState({
+ collaboratorListsum:collaboratorList.length,
+ collaboratorListsumtype:false
+ })
+ }
+
+
+ contentViewScrolledit=(e)=>{
+
+ //滑动到底判断
+ let newscrollTop=parseInt(e.currentTarget.scrollTop);
+ let allclientHeight=e.currentTarget.clientHeight+newscrollTop;
+
+ if(e.currentTarget.scrollHeight-allclientHeight===0||e.currentTarget.scrollHeight-allclientHeight===1||e.currentTarget.scrollHeight-allclientHeight===-1){
+ let {page,collaboratorList,user_name,school_name,Searchadmin} = this.state;
+ let newpage=page+1;
+ let newSearchadmin=Searchadmin
+ let id = this.props.match.params.shixunId;
+ let url = "/shixuns/" + id + "/add_collaborators.json";
+ axios.get(url,{params:{
+ user_name:user_name ,
+ school_name:school_name,
+ page:newpage
+ }}).then((response) => {
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else{
+ let newlist = response.data.users;
+ for (var i = 0; i < newlist.length; i++) {
+ newlist[i].checked = false
+ newSearchadmin.push(newlist[i])
+ }
+
+ this.setState({
+ Searchadmin: newSearchadmin,
+ collaboratorList: collaboratorList,
+ page:newpage
+ })
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ });
+
+ }
+
+ }
+
+ render() {
+ let {
+ collaboratorList,
+ Collaboratorsvisible,
+ Collaboratorsvisibleadmin,
+ Searchadmin,
+ allChangechecked,
+ Collaboratorslist,
+ Collaboratorslisttype,
+ collaborators_deletetype,
+ onSearchcalue,
+ collaboratorListsum,
+ collaboratorListsumtype,
+ user_name,
+ school_name,
+ useristrue
+ } = this.state;
+ let {loadingContent} = this.props;
+ const radioStyle = {
+ display: 'block',
+ height: '30px',
+ lineHeight: '30px',
+ };
+
+ const antIcon = ;
+
+ console.log(Searchadmin)
+ return (
+
+
+ this.showCollaboratorsvisible("cooperation")}
+ className="edu-default-btn edu-greenback-btn fr mr20 height40"
+ data-remote="true">
+ + 添加合作者
+
+ this.showCollaboratorsvisible("admin")}
+ style={{display:this.props.identity===1?"block":"none"}}
+ data-remote="true"
+ className="edu-default-btn edu-greenback-btn fr mr20 height40">更换管理员
+
+
+
+
+
+ 选择的成员将会成为新的管理员
您将不再拥有管理员的权限,但您仍是合作团队的一员
+
+
+
+
+
+ -
+
+
+ {
+ Collaboratorslist.length === 0 ? "" : Collaboratorslist.map((item, key) => {
+ return (
+ this.addadminredio(item.user_id)}>{item.name}
+ )
+ })
+ }
+
+
+
+
+
+
+
+
+
+
+ {Collaboratorsvisibleadmin===true?
+ {/* this.onSearchadmin(value)}*/}
+ {/*onInput={this.onSearchadmins}*/}
+ {/*style={{width: '100%'}}*/}
+ {/*/>*/}
+ 姓名或手机号:
+
+ {this.setState({user_name: e.target.value})}}
+ style={{ width: '215px'}}
+ >
+ 单位:
+ {this.setState({school_name: e.target.value})}}
+ style={{ width: '215px'}}
+ >
+
+
+ this.onSearchadmin()}
+ style={{ height: '30px', lineHeight: '30px', width: '70px'}}
+ >搜索
+
+ 姓名
+ 职业
+ 单位
+
+
+
+
+
+ {Searchadmin === undefined ? -
+ 请试试搜索一下
+
:Searchadmin.length === 0 ?: Searchadmin.map((item, key) => {
+ return (
+ -
+ this.selectChangenickname(e, key)}
+ id={item.user_id}>
+ {item.nickname}
+ {item.identify}
+ {item.school_name}
+
+ )
+ })
+
+ }
+
+
+
+
+
+
+
+ 全选
+
+ 请至少选择一个用户
+
+
+
+
+
+ {useristrue===true?请先选择用户:""}
+
+ :""}
+
+
+ {
+ collaboratorList===undefined?"":collaboratorList.map((item,key)=>{
+ if(key
+
+
+
+
+ {item.user.name}
+
+ {item.user.shixun_manager === true ? "(管理员)" : ""}
+
+
+
{item.user.identity}{item.user.school_name}
+
+
+ 发布 {item.user.user_shixuns_count}
+ {/*粉丝 */}
+ {/*{item.user.fans_count}*/}
+ {/**/}
+
+
+ {/*
{item.user.brief_introduction}
*/}
+
+
+
+
+ {item.user.shixun_manager === true ? "" : this.collaborators_delete(item.user.user_id)}>删除}
+ {/*取消关注*/}
+
+
+ )
+ }
+ })
+ }
+
+
+
+
+
+
+
+ 10&&collaboratorListsumtype===true?"":"none"}
+ style={{textAlign:'center',borderTop:'1px solid #eee'}}>
+
加载更多
+
+
+
+
+ );
+ }
+}
+
+export default Collaborators;
diff --git a/public/react/src/tpm/shixunchild/Propaedeutics/Propaedeu_tics.js b/public/react/src/tpm/shixunchild/Propaedeutics/Propaedeu_tics.js
new file mode 100644
index 000000000..f40e9fa63
--- /dev/null
+++ b/public/react/src/tpm/shixunchild/Propaedeutics/Propaedeu_tics.js
@@ -0,0 +1,114 @@
+import React, { Component } from 'react';
+
+import { Redirect } from 'react-router';
+
+import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
+
+import PropTypes from 'prop-types';
+
+import classNames from 'classnames';
+
+import { getImageUrl, toPath } from 'educoder';
+
+import { Tooltip } from 'antd';
+
+import axios from 'axios';
+
+import { CircularProgress } from 'material-ui/Progress';
+
+const $ = window.$;
+
+class Propaedeutics extends Component {
+ constructor(props) {
+ super(props)
+ this.state={
+ PropaedeuticsListcontent:undefined,
+ shixunId:undefined
+ }
+ }
+
+ componentDidMount() {
+ let id = this.props.match.params.shixunId;
+ this.setState({
+ shixunId:id
+ })
+ let url="/shixuns/"+id+"/propaedeutics.json";
+ axios.get(url).then((response) => {
+
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else{
+ if(response.data.content!=null){
+ this.setState({
+ PropaedeuticsListcontent:response.data.content
+ })
+ }else{
+ this.setState({
+ PropaedeuticsListcontent:""
+ })
+ }
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+
+ }
+
+ updatamakedown=(id)=>{
+ setTimeout(()=>{
+ var shixunDescr = window.editormd.markdownToHTML(id, {
+ htmlDecode: "style,script,iframe",
+ taskList: true,
+ tex: true,
+ flowChart: true,
+ sequenceDiagram: true
+ });
+ $("#"+id+" p:first").addClass("ReactMarkdown");
+ $('#collaborators_list_info').show()
+ }, 200)
+ }
+ render() {
+ let {loadingContent} = this.props;
+ let {PropaedeuticsListcontent,shixunId}=this.state
+
+ if(PropaedeuticsListcontent!=undefined){
+ this.updatamakedown("ReactMarkdown")
+ }
+
+ return (
+
+
+
+
+
+
+
+ {
+ loadingContent ?
+ :
+
+ {PropaedeuticsListcontent===undefined?"":
+
+
+ {PropaedeuticsListcontent === undefined ||PropaedeuticsListcontent === ""?
+
+
+
+
}/)
+
暂时还没有相关数据哦!
+
+
+
+ :
}
+
+
+ }
+
+ }
+
+ );
+ }
+}
+
+export default Propaedeutics;
diff --git a/public/react/src/tpm/shixunchild/Ranking_list/Ranking_list.js b/public/react/src/tpm/shixunchild/Ranking_list/Ranking_list.js
new file mode 100644
index 000000000..0e5d0498b
--- /dev/null
+++ b/public/react/src/tpm/shixunchild/Ranking_list/Ranking_list.js
@@ -0,0 +1,145 @@
+import React, { Component } from 'react';
+
+import { Redirect } from 'react-router';
+
+import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
+
+import PropTypes from 'prop-types';
+
+import classNames from 'classnames';
+
+import { getImageUrl, toPath } from 'educoder';
+
+import { CircularProgress } from 'material-ui/Progress';
+
+import axios from 'axios';
+
+const $ = window.$;
+
+class Ranking_list extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ Ranking_listData:[]
+ }
+ }
+
+ Ranking_listList = (id) => {
+ let Ranking_listURL = `/shixuns/` + id + `/ranking_list.json`;
+ axios.get(Ranking_listURL).then((response) => {
+ if (response.status === 200) {
+ if (response.data.status === 403||response.data.status === 401||response.data.status === 500) {
+
+ }else{
+ this.setState({
+ Ranking_listData: response.data
+ });
+ }
+ }
+
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ componentDidMount() {
+ let id = this.props.match.params.shixunId;
+ setTimeout(this.Ranking_listList(id), 1000);
+ }
+ checkAddZone=(num)=>{
+ return num<10 ? '0' + num.toString() : num
+ }
+ dateTimeFormatter=(t)=> {
+ if (!t) return ''
+ t = new Date(t).getTime()
+ t = new Date(t)
+ var year = t.getFullYear()
+ var month = (t.getMonth() + 1)
+ month = this.checkAddZone(month)
+
+ var date = t.getDate()
+ date = this.checkAddZone(date)
+
+ var hour = t.getHours()
+ hour = this.checkAddZone(hour)
+
+ var min = t.getMinutes()
+ min = this.checkAddZone(min)
+
+ return year + '-' + month + '-' + date + ' ' + hour + ':' + min
+ }
+
+ formatSeconds=(value)=> {
+ var theTime = parseInt(value);// 秒
+ var theTime1 = 0;// 分
+ var theTime2 = 0;// 小时
+ if(theTime > 60) {
+ theTime1 = parseInt(theTime/60);
+ theTime = parseInt(theTime%60);
+ if(theTime1 > 60) {
+ theTime2 = parseInt(theTime1/60);
+ theTime1 = parseInt(theTime1%60);
+ }
+ }
+ var result = ""+parseInt(theTime)+"秒";
+ if(theTime1 > 0) {
+ result = ""+parseInt(theTime1)+"分"+result;
+ }
+ if(theTime2 > 0) {
+ result = ""+parseInt(theTime2)+"小时"+result;
+ }
+ return result;
+ }
+
+ render() {
+ let { Ranking_listData } = this.state;
+ let { loadingContent } = this.props;
+
+ // console.log(Ranking_listData)
+ return (
+
+ { loadingContent ?
+ :
+
+
+ {Ranking_listData===undefined||Ranking_listData.length===0?
+
+
})
+
我们在等你,不轻言放弃
+
+ :Ranking_listData.map((item,key)=>{
+ var keys=key+1
+ return(
+
+
+
+ 2?"block":"none"}}
+ >{key+1}
+
+
+
+
+ {item.users.name}
+
+
+
{this.dateTimeFormatter(item.time)}通关
+ {/*
*/}
+ {/*/!*{item.accuracy} %准确率*!/*/}
+ {/**/}
+
{this.formatSeconds(item.use_time)}
+
+{item.gold}金币
+
+ )
+ })}
+
+ }
+
+
+ );
+ }
+}
+
+export default Ranking_list;
diff --git a/public/react/src/tpm/shixunchild/Repository/Repository.js b/public/react/src/tpm/shixunchild/Repository/Repository.js
new file mode 100644
index 000000000..c477422e8
--- /dev/null
+++ b/public/react/src/tpm/shixunchild/Repository/Repository.js
@@ -0,0 +1,266 @@
+import React, { Component } from 'react';
+
+import { Redirect } from 'react-router';
+
+import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
+
+import PropTypes from 'prop-types';
+
+import classNames from 'classnames';
+
+import axios from 'axios';
+
+import { trace, trace_collapse ,getImageUrl, toPath} from "educoder";
+
+import RepositoryDirectories from './RepositoryDirectories'
+
+import { ActionBtn , NoneData } from 'educoder'
+import RepositoryCombinePath from './RepositoryCombinePath'
+const $ = window.$;
+
+// 点击按钮复制功能
+function jsCopy(){
+ var e = document.getElementById("copy_rep_content");
+ e.select();
+ document.execCommand("Copy");
+}
+/**
+ 提交记录
+ 使用指南
+ */
+class Repository extends Component {
+ constructor(props) {
+ super(props);
+ this.state={
+
+ }
+ }
+ componentDidMount() {
+ }
+ onRepoFileClick = (item) => {
+
+ this.props.fetchRepo(item)
+
+ }
+ render() {
+ let { match, author, git_url, lastest_commit,repositoryLoading, commits,trees,pathArray , TPMRightSectionData } = this.props;
+
+ if (!author) {
+ author = {}
+ }
+ let userauthority=false;
+ if(this.props.author!=undefined){
+ userauthority=this.props.author.login===""||this.props.author.user_id===""||this.props.author.login===null||this.props.author.user_id===null;
+ }
+ return (
+
+ {/* jfinalshop/WebRoot */}
+ {/* */}
+
+ { repositoryLoading ? :
+
+
+
+
+
+
+ {/*
*/}
+
+
Git使用指南
+ {
+ this.props.current_user && (this.props.current_user.admin ==true || (TPMRightSectionData && TPMRightSectionData.creator && TPMRightSectionData.creator.login == this.props.current_user.login)) ?
+ !this.props.secret_repository_tab &&
+
+添加文件
+ :""
+ }
+
+
+
+
+
+
+ {this.props.secret_repository_tab &&
+
+ }
+
+
+
+
+
+ {/* 用户、最近提交时间 */}
+ {
+ trees === undefined || trees === null ||trees.length===0?
:
+
+ {commits===undefined?"":commits===null||commits.length===0?"":
}
+
+
+
+ }
+
+ {/* 当前分支的文件 */}
+
+
+
+ }
+
+
+ );
+ }
+}
+/*
+ 提交记录
+
+ { RepositoryList===undefined?"":RepositoryList.commits.map((item,key)=>{
+ // {"email":"李暾","title":"2\n","id":"80cb6fc55a14bdd64a9c99913f416966238ed3de","time":"49年前"}
+ return(
+
+
{item.email}
+
{item.title}
+
{item.id}
+
{item.time}
+
+ )
+ }) }
+
+
+
+
+
+
+
+ 1-1.py
+
+
+
+
+
+*/
+
+export default Repository;
diff --git a/public/react/src/tpm/shixunchild/Repository/RepositoryAddFile.js b/public/react/src/tpm/shixunchild/Repository/RepositoryAddFile.js
new file mode 100644
index 000000000..9ca535bb4
--- /dev/null
+++ b/public/react/src/tpm/shixunchild/Repository/RepositoryAddFile.js
@@ -0,0 +1,198 @@
+import React, { Component } from 'react';
+import { ActionBtn } from 'educoder'
+
+import { Form , Modal , Input , Breadcrumb , Button } from 'antd'
+
+import { Link } from 'react-router-dom'
+
+import axios from 'axios'
+
+/**
+ ---------------------------- START
+ */
+function getModeByMirrorName(mirror_name) {
+ let mode = 'javascript'
+ if (mirror_name && mirror_name.length) {
+ for (let i = 0; i < mirror_name.length; i++) {
+ let modeVal = mirrorNameModeMap[mirror_name[i]];
+ if (modeVal) {
+ mode = modeVal;
+ break;
+ }
+ }
+ }
+ return mode;
+}
+const _extraKeys = {"Alt-/": "autocomplete"};
+function createCMOptions(mirror_name) {
+ let mode = getModeByMirrorName(mirror_name)
+
+ let cmOptions = {
+ lineNumbers: true,
+ mode: mode,
+ theme: "railscasts",
+ indentUnit:4,
+ matchBrackets: true,
+ autoRefresh: true,
+ smartIndent: true,//智能换行
+ extraKeys: _extraKeys,
+ autofocus: true,
+ styleActiveLine: true,
+ lint: true,
+ gutters: ["CodeMirror-linenumbers", "breakpoints", "CodeMirror-lint-markers"]
+ };
+ return cmOptions;
+}
+
+const mirrorNameModeMap = {
+ 'JFinal': 'text/x-java',
+ 'Java': 'text/x-java',
+ 'Kotlin': 'text/x-kotlin',
+ 'C/C++' : 'text/x-c++src',
+ 'MachineLearning': {
+ name: "python",
+ version: 3,
+ singleLineStringErrors: false
+ },
+ 'Python2.7': {
+ name: "python",
+ version: 3,
+ singleLineStringErrors: false
+ },
+ 'Python3.6': {
+ name: "python",
+ version: 3,
+ singleLineStringErrors: false
+ },
+}
+/**
+ ---------------------------- END
+*/
+
+class RepositoryAddFile extends Component {
+ constructor(props) {
+ super(props);
+ }
+
+ componentDidMount(){
+ let cmOptions = createCMOptions(this.props.mirror_name)
+ const extend_editor = window.CodeMirror.fromTextArea(window.$('#codemirror-file-edit')[0]
+ , cmOptions);
+
+ // tpi没setValue也可以
+ extend_editor.setValue('')
+ extend_editor.refresh();
+
+ // 拖拽也需要用 : window.editor_CodeMirror.refresh()
+ window.editor_tempCodeMirror = extend_editor;
+ this.extend_editor = extend_editor;
+ }
+
+ checkPath= (rule, value, callback) =>{
+ if(!value){
+ callback('文件名不能为空');
+ }else if (value == "/" || value.indexOf('.') == -1 ) {
+ callback('请输入正确的文件路径,如:src/HelloWorld.java');
+ }else{
+ callback();
+ }
+ }
+
+ handleSubmit = () =>{
+ this.props.form.validateFieldsAndScroll((err, values) => {
+ if(!err){
+ let shixunId = this.props.match.params.shixunId;
+ let url = `/shixuns/${shixunId}/add_file.json`
+ axios.post(url,{
+ path:values.path,
+ message:values.message,
+ content:this.extend_editor.getValue()
+ }).then((result)=>{
+ if(result){
+ this.props.history.push(`${result.data.url}`)
+ }
+ }).catch((error)=>{
+ console.log(error);
+ })
+ }
+ })
+ }
+ render(){
+ const {getFieldDecorator} = this.props.form;
+ let { shixunId } = this.props.match.params;
+ return(
+
+
+
+
+ 实训项目
+ 版本库
+ 添加新文件
+
+
+
+ {getFieldDecorator('path', {
+ rules: [
+ {
+ validator:this.checkPath
+ }]
+ })(
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+ {getFieldDecorator('message', {
+ rules: [{required: true, message: "请输入提交信息"}],
+ })(
+
+ )}
+
+
+
+
+ 取消
+
+
+
+
+ )
+ }
+}
+const WrappedRepositoryAddFile = Form.create({name: 'taskRepositoryAddFile'})(RepositoryAddFile);
+// RouteHOC()
+export default (WrappedRepositoryAddFile);
\ No newline at end of file
diff --git a/public/react/src/tpm/shixunchild/Repository/RepositoryCodeEditor.js b/public/react/src/tpm/shixunchild/Repository/RepositoryCodeEditor.js
new file mode 100644
index 000000000..51f6e35f2
--- /dev/null
+++ b/public/react/src/tpm/shixunchild/Repository/RepositoryCodeEditor.js
@@ -0,0 +1,185 @@
+import React, { Component } from 'react';
+
+import { Redirect } from 'react-router';
+
+import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
+
+import PropTypes from 'prop-types';
+
+import classNames from 'classnames';
+
+import axios from 'axios';
+
+import RepositoryDirectories from './RepositoryDirectories'
+
+import { trace_collapse } from 'educoder'
+
+import Popconfirm from 'antd/lib/popconfirm';
+import 'antd/lib/popconfirm/style/css';
+
+import { message } from 'antd';
+
+require('codemirror/lib/codemirror.css');
+
+const $ = window.$;
+
+
+/**
+ ---------------------------- START
+ */
+function getModeByMirrorName(mirror_name) {
+ let mode = 'javascript'
+ if (mirror_name && mirror_name.length) {
+ for (let i = 0; i < mirror_name.length; i++) {
+ let modeVal = mirrorNameModeMap[mirror_name[i]];
+ if (modeVal) {
+ mode = modeVal;
+ break;
+ }
+ }
+ }
+ return mode;
+}
+const _extraKeys = {"Alt-/": "autocomplete"};
+function createCMOptions(mirror_name) {
+ let mode = getModeByMirrorName(mirror_name)
+
+ let cmOptions = {
+ lineNumbers: true,
+ mode: mode,
+ theme: "railscasts",
+ indentUnit:4,
+ matchBrackets: true,
+ autoRefresh: true,
+ smartIndent: true,//智能换行
+ extraKeys: _extraKeys,
+ autofocus: true,
+ styleActiveLine: true,
+ lint: true,
+ gutters: ["CodeMirror-linenumbers", "breakpoints", "CodeMirror-lint-markers"]
+ };
+ return cmOptions;
+}
+
+const mirrorNameModeMap = {
+ 'JFinal': 'text/x-java',
+ 'Java': 'text/x-java',
+ 'Kotlin': 'text/x-kotlin',
+ 'C/C++' : 'text/x-c++src',
+ 'MachineLearning': {
+ name: "python",
+ version: 3,
+ singleLineStringErrors: false
+ },
+ 'Python2.7': {
+ name: "python",
+ version: 3,
+ singleLineStringErrors: false
+ },
+ 'Python3.6': {
+ name: "python",
+ version: 3,
+ singleLineStringErrors: false
+ },
+}
+/**
+ ---------------------------- END
+ */
+
+class RepositoryCodeEditor extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ codeSaving: false
+ }
+ }
+ componentDidUpdate = (prevProps, prevState) => {
+
+ if (this.props.fileContent && this.props.fileContent != prevProps.fileContent) {
+ // window.setTimeout(() => {
+ this.extend_editor.setValue(this.props.fileContent)
+ // }, 2000)
+ }
+ }
+ componentDidMount(){
+ let cmOptions = createCMOptions(this.props.mirror_name)
+ const extend_editor = window.CodeMirror.fromTextArea(window.$('#codemirror-file-edit')[0]
+ , cmOptions);
+
+ // tpi没setValue也可以
+ extend_editor.setValue('')
+ extend_editor.refresh();
+
+ // 拖拽也需要用 : window.editor_CodeMirror.refresh()
+ window.editor_tempCodeMirror = extend_editor;
+ this.extend_editor = extend_editor;
+ }
+
+ saveCode = () => {
+ const { shixunId, pathArray } = this.props;
+ const url = `/shixuns/${shixunId}/update_file.json`
+ const path = pathArray.join('/')
+ this.setState({ codeSaving: true })
+ axios.post(url, {
+ secret_repository: this.props.secret_repository_tab,
+ content: this.extend_editor.getValue(),
+ // type: forTest === true ? 1 : 0,
+ path: path
+ }
+ ).then((response) => {
+ if (response.data.content) {
+ message.success('保存成功');
+ this.setState({ codeSaving: false })
+ }
+ })
+ }
+ render() {
+ const { fileContent, match, saveCode } = this.props;
+ const { codeSaving } = this.state;
+ return (
+
+
+
+
+
+
+
+
+
+ { codeSaving ?
+
保存中...
+ :
this.saveCode(this.extend_editor.getValue())}
+ okText="确定" cancelText="取消">
+ {/* onClick={this.saveCode}
+ onClick={() => saveCode(this.extend_editor.getValue())}
+ */}
+ 保存
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+export default RepositoryCodeEditor;
diff --git a/public/react/src/tpm/shixunchild/Repository/RepositoryCombinePath.js b/public/react/src/tpm/shixunchild/Repository/RepositoryCombinePath.js
new file mode 100644
index 000000000..aba008e20
--- /dev/null
+++ b/public/react/src/tpm/shixunchild/Repository/RepositoryCombinePath.js
@@ -0,0 +1,82 @@
+import React, { Component } from 'react';
+
+import { Redirect } from 'react-router';
+
+import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
+
+import PropTypes from 'prop-types';
+
+import classNames from 'classnames';
+
+import axios from 'axios';
+
+import { trace_collapse, WordsBtn } from 'educoder'
+
+import { message, Input } from 'antd';
+
+
+const $ = window.$;
+
+
+class RepositoryCombinePath extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ value: this.props.secret_dir_path || '',
+ isEdit: false,
+ }
+ }
+
+ onSave = () => {
+ const { shixunId, pathArray } = this.props;
+ const url = `/shixuns/${shixunId}/set_secret_dir.json`
+
+ this.setState({ codeSaving: true })
+ axios.post(url, {
+ secret_dir_path: this.state.value
+ }
+ ).then((response) => {
+ if (response.data) {
+ message.success('保存成功');
+ this.setState({isEdit: false})
+ }
+ })
+ }
+ onChange = (e) => {
+ const { value } = e.target;
+ this.setState({ value })
+ }
+ onEdit = () => {
+ this.setState({isEdit: true}, () => {
+ window.$('.combinePathEditRow input')[0].focus()
+ });
+ }
+ render() {
+ const { fileContent, match, saveCode } = this.props;
+ const { isEdit, value } = this.state;
+ return (
+
+
+
+ 第一版本库合并路径:
+
+ {!isEdit && 修改}
+ {isEdit && 保存}
+
+
+
+ );
+ }
+}
+export default RepositoryCombinePath;
diff --git a/public/react/src/tpm/shixunchild/Repository/RepositoryDirectories.js b/public/react/src/tpm/shixunchild/Repository/RepositoryDirectories.js
new file mode 100644
index 000000000..7c6eca37a
--- /dev/null
+++ b/public/react/src/tpm/shixunchild/Repository/RepositoryDirectories.js
@@ -0,0 +1,66 @@
+import React, { Component } from 'react';
+
+import { Redirect } from 'react-router';
+
+import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
+
+import PropTypes from 'prop-types';
+
+import classNames from 'classnames';
+
+import axios from 'axios';
+
+import { trace_collapse } from 'educoder'
+const $ = window.$;
+
+
+class RepositoryDirectories extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+
+ }
+ }
+ componentDidMount() {
+ }
+ render() {
+ const { match, pathArray, fetchRepo
+ } = this.props;
+ let { RepositoryList } = this.state;
+ return (
+
+
+ { pathArray.length !== 0 &&
+ }
+
+
+
+ );
+ }
+}
+export default RepositoryDirectories;
diff --git a/public/react/src/tpm/shixunchild/Repository/TPMRepositoryCommits.js b/public/react/src/tpm/shixunchild/Repository/TPMRepositoryCommits.js
new file mode 100644
index 000000000..663c5fcf3
--- /dev/null
+++ b/public/react/src/tpm/shixunchild/Repository/TPMRepositoryCommits.js
@@ -0,0 +1,145 @@
+import React, { Component } from 'react';
+
+import { Redirect } from 'react-router';
+
+import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
+
+import PropTypes from 'prop-types';
+
+import classNames from 'classnames';
+
+import axios from 'axios';
+
+import TPMNav from '../../component/TPMNav'
+import TPMRightSection from '../../component/TPMRightSection'
+import { CircularProgress } from 'material-ui/Progress';
+
+import { trace_collapse } from 'educoder'
+const $ = window.$;
+
+// 点击按钮复制功能
+function jsCopy(){
+ var e = document.getElementById("copy_rep_content");
+ e.select();
+ document.execCommand("Copy");
+}
+class TPMRepositoryCommits extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ RepositoryList: undefined,
+ }
+ }
+ componentDidMount() {
+ let id = this.props.match.params.shixunId;
+
+ let collaborators=`/shixuns/`+id+`/commits.json`;
+ axios.post(collaborators, {
+ secret_repository: this.props.secret_repository_tab
+ }).then((response)=> {
+
+ if(response.status===200){
+ this.setState({
+ RepositoryList: response.data
+ });
+ }
+ trace_collapse('repo commits res', response.data)
+
+ }).catch((error)=>{
+ console.log(error)
+ });
+
+ }
+ render() {
+ const { loadingContent, creator, shixun, myshixun, recommend_shixuns, current_user, watched,
+ aboutFocus, user, match
+ } = this.props;
+ let { RepositoryList } = this.state;
+ return (
+
+
+
+ {/* 可能会影响到其他页面的样式,需要测试、协商 */}
+
+
+ { loadingContent ?
+
+ :
+
+
+
+
+ 提交记录
+
+ {/* 35 */}
+
+ 返回
+
+
+
+
+
+
+ { RepositoryList === undefined ? "" : RepositoryList.commits.map( (item, key)=>{
+ return (
+ -
+ {item.email}
+
+ {item.title}
+
+ {item.time}
+
+
+ )
+ })
+ }
+
+
+
+ }
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+/**
+ { RepositoryList === undefined ? "" : RepositoryList.commits.map( (item, key)=>{
+ // {"email":"李暾","title":"2\n","id":"80cb6fc55a14bdd64a9c99913f416966238ed3de","time":"49年前"}
+ return (
+
+
{item.email}
+
{item.title}
+
{item.id}
+
{item.time}
+
+ )
+ })
+ */
+export default TPMRepositoryCommits;
diff --git a/public/react/src/tpm/shixunchild/ShixunDiscuss/ShixunDiscuss.js b/public/react/src/tpm/shixunchild/ShixunDiscuss/ShixunDiscuss.js
new file mode 100644
index 000000000..4e9470f89
--- /dev/null
+++ b/public/react/src/tpm/shixunchild/ShixunDiscuss/ShixunDiscuss.js
@@ -0,0 +1,170 @@
+import React, { Component } from 'react';
+
+import { Redirect } from 'react-router';
+
+import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
+
+import PropTypes from 'prop-types';
+
+import classNames from 'classnames';
+
+import { getImageUrl, toPath } from 'educoder'
+
+import axios from 'axios';
+
+const $ = window.$;
+
+class ShixunDiscuss extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ TPMRightSectionData: undefined
+ }
+ }
+ getshixunsDetailsList = (id) => {
+ let shixunsDetailsURL = `/shixuns/` + id + `/discusses.json`;
+ axios.get(shixunsDetailsURL).then((response) => {
+ if (response.status === 200) {
+ this.setState({
+ TPMRightSectionData: response.data
+ });
+ }
+ }).catch((error) => {
+ console.log(error)
+ });
+ }
+
+ componentDidMount() {
+ let id = this.props.match.params.shixunId;
+ setTimeout(this.getshixunsDetailsList(id), 1000);
+ }
+ render() {
+ let { TPMRightSectionData } = this.state;
+
+ return (
+
+
+
+
+
+ {
+ TPMRightSectionData===undefined?"":TPMRightSectionData.map((item,key)=>{
+ return(
+
+
+
+
+
+
+
+
+
+
+
+ {
+ item.replies.map((i,k)=>{
+ return(
+
+
+ )
+ })
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+ )
+ })
+ }
+
+
+
+
+ )
+ }
+ }
+
+ export default ShixunDiscuss;
diff --git a/public/react/src/tpm/shixunchild/Shixunfork_list.js b/public/react/src/tpm/shixunchild/Shixunfork_list.js
new file mode 100644
index 000000000..f813441f1
--- /dev/null
+++ b/public/react/src/tpm/shixunchild/Shixunfork_list.js
@@ -0,0 +1,69 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import { BrowserRouter as Router, Route, Link} from "react-router-dom";
+
+import { Switch } from 'antd';
+
+import PropTypes from 'prop-types';
+
+import classNames from 'classnames'
+
+import { TPMIndexHOC } from '../TPMIndexHOC'
+
+import { SnackbarHOC } from 'educoder'
+
+import ShixunCard from '.././shixuns/ShixunCard';
+
+import { Pagination,Row,Col,Rate } from 'antd';
+
+ import './shixunchildCss/Shixunfork_list.css';
+
+import 'antd/lib/rate/style/index.css';
+
+const $ = window.$;
+
+class Shixunforklist extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+
+ }
+ }
+
+ handleChange = (value) => {
+ console.log('Page: ', value);
+ // this.setState({ value });
+ }
+ //JSX
+ render() {
+ const { match, history } = this.props
+
+ return (
+
+
+
+
+ Fork实训列表
+ 返回
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+export default SnackbarHOC() (TPMIndexHOC ( Shixunforklist ));
diff --git a/public/react/src/tpm/shixunchild/shixunchildCss/Challenges.css b/public/react/src/tpm/shixunchild/shixunchildCss/Challenges.css
new file mode 100644
index 000000000..493a95301
--- /dev/null
+++ b/public/react/src/tpm/shixunchild/shixunchildCss/Challenges.css
@@ -0,0 +1,28 @@
+.editormd-html-preview, .editormd-preview-container {
+ width: 95% !important;
+}
+.Finish_button{
+ height: 30px;
+ line-height: 30px;
+ margin-top: -8px;
+}
+.startbtnModal .ant-modal-content{
+ background: transparent;
+ box-shadow: 0 4px 12px transparent;
+}
+
+.startbtnModal .ant-modal-content .ant-modal-body .ant-spin-spinning{
+ margin-left: 45%;
+}
+
+.color05101a{
+ color:#05101a;
+}
+
+.mtf3{
+ margin-top: -3px;
+}
+.addshixuns{
+ height: 27px;
+ line-height: 25px;
+}
\ No newline at end of file
diff --git a/public/react/src/tpm/shixunchild/shixunchildCss/Shixunfork_list.css b/public/react/src/tpm/shixunchild/shixunchildCss/Shixunfork_list.css
new file mode 100644
index 000000000..d6ef5ebfe
--- /dev/null
+++ b/public/react/src/tpm/shixunchild/shixunchildCss/Shixunfork_list.css
@@ -0,0 +1,6 @@
+.ant-rate{
+ color: #FFAA05 !important;
+}
+.ant-pagination-options-quick-jumper input{
+ height: 22 !important;
+}
\ No newline at end of file
diff --git a/public/react/src/tpm/shixuns/ShixunCard.js b/public/react/src/tpm/shixuns/ShixunCard.js
new file mode 100644
index 000000000..9f62ed6b7
--- /dev/null
+++ b/public/react/src/tpm/shixuns/ShixunCard.js
@@ -0,0 +1,200 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
+
+import PropTypes from 'prop-types';
+
+import classNames from 'classnames';
+
+import { Rating ,Pagination} from "@icedesign/base";
+
+import {getImageUrl,setImagesUrl, toPath,getUrl} from 'educoder';
+
+import { Spin,Icon,Tooltip ,Rate} from 'antd';
+import LoadingSpin from '../../../common/LoadingSpin';
+import './shixunCss/shixunCard.css';
+
+// 引入业务组件样式
+
+import axios from 'axios';
+
+const $ = window.$;
+
+class ShixunCard extends Component {
+ constructor(props) {
+ super(props)
+
+ this.state = {
+ startValue:[],
+ order_by:"",
+ page:1,
+ limit:16,
+ keyword:"",
+ status:0,
+ diff:0,
+ hideme:false,
+ tag_level:3,
+ tag_id:''
+ }
+
+ }
+
+ PaginationonChange=(pageNumber)=> {
+ this.props.shixunsPage(pageNumber);
+ }
+
+ render() {
+ let {middleshixundata, pagination, typepvisible, pages, totalcount} = this.props;
+ const MyRate = ({ defaultValue, ...rest }) => {
+ let myValue = defaultValue;
+ // console.log(myValue-Math.floor(myValue))
+ // if (myValue < Math.ceil(myValue)) {
+ // myValue = Math.floor(myValue) + 0.5;
+ // }
+
+ return ;
+ };
+ return (
+
+
+
+
+ { middleshixundata === undefined?"":middleshixundata.length === 0 ?
+
+
}/)
+
暂时还没有相关数据哦!
+
:""}
+
+
+
+
+
+ {middleshixundata === undefined || middleshixundata.length === 0?" ":middleshixundata.map((item,key)=>{
+ return(
+
+
+ {
+ item.tag_name === null ? "":
+
+
{item.tag_name}
+ {/*
}/)
*/}
+
+ }
+
+
})
+
非试用内容,需要授权
+
+
+
+ {/*
*/}
+
+
+ {/*target="_blank"*/}
+
+
+
+
+ {item.name}
+
+
+
+ {/*target="_blank"*/}
+ {/**/}
+
+
+ {/**/}
+
+
+ {item.score_info===null?"5分":item.score_info+"分"}
+
+
+
+
+
+ {item.challenges_count}
+
+
+
+ {/**/}
+ {/**/}
+ {/*{item.exp}*/}
+ {/**/}
+ {/**/}
+
+
+
+ {item.stu_num}
+
+
+
+ {item.level}
+
+
+
+
+ )
+ })
+ }
+
+
+
+
+ {/*totalcount*/}
+
+ {/*
*/}
+ {/* 不加参数请求的时候,没返回总数了。加了个比较大的数字,让他可以翻页 */}
+
+
+
+
+
+
+
+
+ )
+ }
+}
+
+export default ShixunCard;
diff --git a/public/react/src/tpm/shixuns/ShixunCardList.js b/public/react/src/tpm/shixuns/ShixunCardList.js
new file mode 100644
index 000000000..d95ef75fe
--- /dev/null
+++ b/public/react/src/tpm/shixuns/ShixunCardList.js
@@ -0,0 +1,253 @@
+import React, { Component } from 'react';
+import { Redirect } from 'react-router';
+
+import { BrowserRouter as Router, Route} from "react-router-dom";
+
+import { Switch ,Input,Tooltip,Icon} from 'antd';
+
+import PropTypes from 'prop-types';
+
+import classNames from 'classnames'
+
+import 'antd/lib/switch/style/index.css'
+
+import './shixunCss/ShixunCardList.css';
+
+import { on, off } from 'educoder'
+
+const $ = window.$;
+
+const Search = Input.Search;
+
+class ShixunCardList extends Component {
+
+ constructor(props) {
+ super(props);
+ this.state={
+ allevent:"desc",
+ mine:0,
+ InputValue: props.keyword || "",
+ typemy:0,
+ hots:0,
+ news:0,
+ shixunid:"",
+ upcircle:false,
+ typekeyid:undefined,
+ }
+ }
+
+ componentDidUpdate = (prevProps, prevState) => {
+ if (this.props.keyword != prevProps.keyword) {
+ this.setState({
+ InputValue: this.props.keyword
+ })
+ }
+ }
+ componentDidMount = () => {
+ on('searchKeywordChange', (event, data) => {
+ // console.log(data)
+ this.Input_search(data)
+ })
+ }
+ componentWillUnmount = () => {
+ off('searchKeywordChange')
+ }
+
+
+ latestHot=(e,key)=>{
+
+ let{upcircle,typekeyid}=this.state;
+
+ let id = e.target.id;
+ $("#"+id).siblings().removeClass("active");
+ $("#"+id).addClass("active");
+
+ let type;
+
+ // if(id==="all"){
+ // type="publish_time";
+ // }
+ if(id==="hot"){
+ type="hot";
+ }else if(id==="new"){
+ type="new";
+
+ }
+ if(typekeyid===key){
+ if(upcircle===true){
+ this.setState({
+ upcircle:false,
+ })
+ this.props.Shixunsupcircles("desc")
+ }else if(upcircle===false){
+ this.setState({
+ upcircle:true,
+ })
+ this.props.Shixunsupcircles("asc")
+ }
+ }else{
+ this.setState({
+ typekeyid:key
+ })
+ }
+
+ //allevent
+ this.props.ShixunsState(false,type);
+ }
+
+
+ onSwitchChange=(e,key)=>{
+ let id=e.target.id
+ $("#"+id).siblings().removeClass("active");
+ $("#"+id).addClass("active");
+ let {typemy,upcircle,typekeyid}=this.state;
+
+ if(typekeyid===key){
+ if(upcircle===true){
+ this.setState({
+ upcircle:false,
+ })
+ this.props.Shixunsupcircles("desc")
+ }else if(upcircle===false){
+ this.setState({
+ upcircle:true
+ })
+ this.props.Shixunsupcircles("asc")
+ }
+ }else{
+ this.setState({
+ typekeyid:key
+ })
+ }
+
+
+ if(typemy===0){
+ this.setState({
+ typemy:1
+ })
+ }else{
+ this.setState({
+ typemy:0
+ })
+ }
+ // allevent
+ this.props.ShixunsSwitch();
+ }
+ //输入框搜索
+ Input_search = (value) => {
+ this.setState({
+ InputValue: value
+ })
+ this.props.OnSearchInput(value,true);
+ }
+
+ Input_searchs = (e) => {
+ this.setState({
+ InputValue: e.target.value
+ })
+ this.props.OnSearchInput(e.target.value,false);
+ }
+ upcircles=(val)=>{
+ if(val==="asc"){
+ this.setState({
+ upcircle:false,
+ })
+ this.props.Shixunsupcircles("desc")
+ }else if(val==="desc"){
+ this.setState({
+ upcircle:true
+ })
+ this.props.Shixunsupcircles("asc")
+ }
+ }
+ render(){
+ let {mine,InputValue,upcircle}=this.state;
+ return (
+
+
+
+ {/*
this.latestHot(e,1)}>全部*/}
+ {/*
*/}
+ {/*
this.onSwitchChange(e,2)}>我的*/}
+ {/*
*/}
+
+
this.latestHot(e,4)}>最新
+
+
+
this.latestHot(e,3)}>最热
+
+
+
+ {/*
this.upcircles("asc")}*/}
+ {/*>*/}
+ {/**/}
+ {/**/}
+ {/*/!**!/*/}
+ {/**/}
+ {/*
*/}
+ {/*
this.upcircles("desc")}*/}
+ {/*style={{display:upcircle===true?"none":"block"}}*/}
+ {/*>*/}
+ {/**/}
+ {/**/}
+ {/*/!**!/*/}
+ {/**/}
+ {/*
*/}
+
+ {/*
*/}
+ {/* this.Input_search(value)}*/}
+ {/*enterButton*/}
+ {/*/>*/}
+
+ {/* this.Input_search(value)}
+ autoComplete="off"
+ > */}
+ {/*
*/}
+ {/*
*/}
+ {/*
{*/}
+ {/*this.props.search_tags === null ? "" : this.props.search_tags*/}
+ {/*}*/}
+ {/*
*/}
+ {/*/!*
*/}
+ {/*
*!/*/}
+ {/*
*/}
+ {/*
*/}
+ {/*
隐藏我的*/}
+
+ {/*
*/}
+ {/*
*/}
+
+
+ );
+ }
+}
+
+export default ShixunCardList;
diff --git a/public/react/src/tpm/shixuns/ShixunSearchBar.js b/public/react/src/tpm/shixuns/ShixunSearchBar.js
new file mode 100644
index 000000000..f9c4a7936
--- /dev/null
+++ b/public/react/src/tpm/shixuns/ShixunSearchBar.js
@@ -0,0 +1,292 @@
+import React, { Component } from 'react';
+
+import { Select, Input,Menu, Dropdown } from 'antd';
+
+import 'antd/lib/style/index.css';
+
+import 'antd/lib/select/style/index.css';
+
+import 'antd/lib/input/style/index.css';
+
+import './shixunCss/ShixunSearchBar.css';
+
+import axios from 'axios';
+
+const $ = window.$;
+
+const Option = Select.Option;
+
+const Search = Input.Search;
+
+
+class ShixunSearchBar extends Component {
+
+ constructor(props) {
+ super(props)
+ this.state = {
+ status: undefined,
+ diff: 0,
+ InputValue: undefined,
+ shixunhoverData: [],
+ shixunchildValues:'',
+ shixunsearchAllvalue:"a",
+ openStatus:false,
+ openLevel:false
+ }
+}
+
+ //状态筛选
+ status_search = (value) => {
+ let newvalue = value;
+ if (newvalue === "0") {
+ newvalue = " "
+ } else if (newvalue === "1") {
+ newvalue = 2
+ } else if (newvalue === "2") {
+ newvalue = 1
+ } else if (newvalue === "3") {
+ newvalue = 3
+ }
+
+ this.setState({
+ status: newvalue,
+ openStatus:false
+ })
+ let list = [{'type': 1}, {'value': newvalue}];
+ this.props.StatusEnquiry(list);
+}
+
+ //难度筛选
+diff_search = (value) => {
+ this.setState({
+ diff: value,
+ openLevel:false
+ })
+ let list=[{'type':2},{'value':value}];
+ this.props.StatusEnquiry(list);
+}
+
+ //输入框搜索
+Input_search = (value) => {
+ this.setState({
+ InputValue: value
+ })
+ this.props.OnSearchInput(value);
+}
+ //查询
+shixunsearchAll = (e) => {
+ let{shixunsearchAllvalue}=this.state;
+ let id = e.target.value;
+
+ if(shixunsearchAllvalue===id){
+ return
+ }
+ if(id===0){
+ id=" "
+ this.setState({
+ InputValue: " "
+ })
+ this.props.OnSearchInput("");
+ }
+ let list=[{'tag_level':1},{'tag_id':id}];
+ if(id!=undefined){
+ this.setState({
+ shixunsearchAllvalue:id,
+ shixunchildValues:""
+ })
+ this.props.Updatasearchlist(list);
+ }
+
+}
+
+ shixunsearchall=(e)=>{
+ let{shixunsearchAllvalue}=this.state;
+ let id = "a";
+
+ if(shixunsearchAllvalue===id){
+ return
+ }
+ this.setState({
+ shixunsearchAllvalue:"a",
+ shixunchildValues:""
+ })
+ this.props.allUpdatashixunlist();
+ }
+
+ //选择Tab页详情
+ getshixunchildValue = (e) => {
+
+ debugger
+ let id = e.target.name;
+ let newid=e.target.id;
+ let list=[{'tag_level':2},{'tag_id':id}];
+ if(id!=undefined||newid!=undefined){
+ this.setState({
+ shixunsearchAllvalue:newid
+ })
+ this.props.Updatasearchlist(list);
+ }
+ }
+
+getshixunchildValues = (e) => {
+ let id = e.target.id;
+ let newid=e.target.name;
+ let list=[{'tag_level':3},{'tag_id':id}];
+ if(id!=undefined||newid!=undefined){
+ this.setState({
+ shixunchildValues:id,
+ shixunsearchAllvalue:newid
+ })
+ this.props.Updatasearchlist(list);
+ }
+
+}
+
+componentDidMount() {
+ let hoverUrlArr = [];
+ let hoverUrl = `/shixuns/menus.json`;
+ axios.get(hoverUrl
+ ).then((response) => {
+ hoverUrlArr = response.data;
+ // hoverUrlArr.reverse();
+ this.setState({
+ shixunhoverData: hoverUrlArr
+ })
+ }).catch((error) => {
+ console.log(error)
+ })
+}
+
+render() {
+ let {shixunhoverData, shixunchildValues, shixunsearchAllvalue, InputValue,openStatus,openLevel} = this.state;
+ let {typepvisible} = this.props;
+ // //实训首页筛选的移入和点击事件
+ // $(".shaiItem").hover(function(){
+ // var hei=parseInt($(".shaiAllItem").height())-2;
+ // $(this).find(".subshaicontent").css("top", '34px');
+ // $(this).find(".subshaicontent").show();
+ // },function(){
+ // $(this).find(".subshaicontent").hide();
+ // });
+ //
+ // $(".shaiItem").live("click",function(){
+ // $(".shaiItem").removeClass("active");
+ // $(this).addClass("active");
+ // $(".subshaicontent").hide();
+ // });
+ //
+ // $(".subshaicontent").live("click", function(event){
+ // $(".subshaicontent").hide();
+ // event.stopPropagation();
+ // });
+
+ let overlaymenu=(item,id)=>(
+
+ )
+
+ return (
+
+
+
+
+
方向:
+
+
全部
+
+ {
+ shixunhoverData.map((item,key)=>{
+ return(
+
+
+ {item.name}
+
+
+ )
+ })
+ }
+
+
+
+
+
+
筛选:
+ {
+
+ }
+
+
this.diff_search(0)}>全部难度
+ this.diff_search(1)}>初级学员
+ this.diff_search(2)}>中级学员
+ this.diff_search(3)}>高级学员
+ this.diff_search(4)}>顶级学员
+
+
+
+
+
+
+ );
+}
+}
+
+export default ShixunSearchBar;
diff --git a/public/react/src/tpm/shixuns/ShixunsIndex.js b/public/react/src/tpm/shixuns/ShixunsIndex.js
new file mode 100644
index 000000000..15579610d
--- /dev/null
+++ b/public/react/src/tpm/shixuns/ShixunsIndex.js
@@ -0,0 +1,422 @@
+import React, { Component } from 'react';
+
+import { Redirect } from 'react-router';
+
+import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
+
+import axios from 'axios';
+
+import { Spin } from 'antd';
+
+import { TPMIndexHOC } from '../TPMIndexHOC';
+
+import { SnackbarHOC } from 'educoder';
+
+import ShixunCardList from './ShixunCardList';
+
+import ShixunSearchBar from './ShixunSearchBar';
+
+import ShixunCard from './ShixunCard';
+
+import UpgradeModals from '../../modals/UpgradeModals';
+
+const queryString = require('query-string');
+
+const $ = window.$;
+
+class ShixunsIndex extends Component {
+ constructor(props) {
+ super(props)
+ this.state={
+ order_by: "new",
+ page:1,
+ limit:16,
+ keyword:"",
+ status:0,
+ diff:0,
+ tag_level: 1,
+ tag_id:'',
+ middleshixundata:[],
+ typepvisible:true,
+ pages:1,
+ search_tags:null,
+ parsedid:undefined,
+ newtag_level:undefined,
+ newpalce:undefined,
+ sort:"desc"
+ }
+ }
+ componentDidMount(){
+
+ const upsystem=`/users/system_update.json`;
+ axios.get(upsystem).then((response)=>{
+ let updata=response.data;
+ this.setState({
+ updata:updata
+ })
+ }).catch((error)=>{
+ console.log(error);
+ })
+
+
+
+ let _keyword;
+ if (window.__headSearchKeyword) {
+ this.setState({ keyword: window.__headSearchKeyword })
+ _keyword = window.__headSearchKeyword
+ delete window.__headSearchKeyword
+ }
+ const parsed = queryString.parse(this.props.location.search);
+ if(parsed.id===undefined&&parsed.type===undefined){
+ let {order_by, tag_level, tag_id, page, limit, keyword, status, diff} = this.state;
+ let params={
+ order_by:order_by,
+ tag_level:tag_level,
+ tag_id:tag_id,
+ page:page,
+ limit:limit,
+ keyword: _keyword || keyword ,
+ status:status,
+ diff:diff,
+ sort: "desc"
+ }
+ this.shixunresultend(params);
+ }else{
+ let {order_by,page, limit, keyword, status, diff} = this.state;
+ let nawparsed=parsed.type;
+ let newpalce=parsed.palce;
+ if(nawparsed==="rep"){
+ nawparsed=1
+ }
+ else if(nawparsed==="sub"){
+ nawparsed=2
+ }else if(nawparsed==="tag"){
+ nawparsed=3
+ }
+ let params={
+ order_by:order_by,
+ tag_level:nawparsed,
+ tag_id:parsed.id,
+ page:page,
+ limit:limit,
+ keyword: _keyword || keyword,
+ status:status,
+ diff:diff,
+ sort: "desc"
+ }
+ this.setState({
+ parsedid:parsed.id,
+ newtag_level:nawparsed,
+ newpalce:newpalce
+ })
+ this.shixunresultend(params);
+ }
+
+ }
+
+ allUpdatashixunlist=()=>{
+ let{sort,order_by}=this.state;
+
+ this.setState({
+ tag_level: 1,
+ tag_id:'',
+ page: 1,
+ limit: 16,
+ keyword:'',
+ status: 0,
+ diff: 0,
+ })
+
+ let params={
+ order_by:order_by,
+ tag_level: 1,
+ tag_id:'',
+ page: 1,
+ limit: 16,
+ keyword:'',
+ status: 0,
+ diff: 0,
+ sort:sort
+ }
+ this.shixunresultend(params)
+ }
+ Updatasearchlist=(value)=>{
+ if (value[1].tag_id === " ") {
+ this.setState({
+ keyword: ""
+ })
+ }
+ this.setState({
+ tag_level:value[0].tag_level,
+ tag_id:value[1].tag_id,
+ typepvisible:true
+ })
+
+ let {order_by, sort, limit, keyword, status, diff} = this.state;
+
+ let params={
+ order_by:order_by,
+ tag_level:value[0].tag_level,
+ tag_id:value[1].tag_id,
+ page:1,
+ limit:limit,
+ keyword:keyword,
+ status:status,
+ diff:diff,
+ sort:sort
+ }
+
+ this.shixunresultend(params)
+ }
+
+ StatusEnquiry=(key)=>{
+
+ let Vrl=`/shixuns.json`;
+ let newstatus;
+ let newdiff;
+ if(key[0].type===1){
+ this.setState({
+ status: key[1].value,
+ typepvisible:true
+ })
+ newstatus=key[1].value;
+ newdiff=this.state.diff;
+ }else if(key[0].type===2){
+ this.setState({
+ diff: key[1].value,
+ typepvisible:true
+ })
+ newdiff=key[1].value;
+ newstatus=this.state.status;
+ }
+ let params= {
+ order_by:this.state.order_by,
+ tag_level:this.state.tag_level,
+ tag_id:this.state.tag_id,
+ page:1,
+ limit:this.state.limit,
+ keyword:this.state.keyword,
+ status:newstatus,
+ diff:newdiff,
+ }
+ this.shixunresultend(params)
+
+ }
+
+ OnSearchInput=(value,type)=>{
+ if(type===true){
+ this.setState({
+ keyword:value,
+ typepvisible:true,
+ pages:1
+ })
+ let {order_by, tag_level, tag_id, sort, limit, status, diff} = this.state;
+ let params= {
+ order_by:order_by,
+ tag_level:tag_level,
+ tag_id:tag_id,
+ page:1,
+ limit:limit,
+ keyword:value,
+ status:status,
+ diff:diff,
+ sort:sort
+ }
+ this.shixunresultend(params)
+ }else{
+ this.setState({
+ keyword:value,
+ pages:1
+ })
+ }
+
+
+ }
+
+ ShixunsSwitch=()=>{
+ //types
+ this.setState({
+ order_by:"mine",
+ typepvisible:true,
+ pages:1,
+ })
+ let{tag_level,tag_id,page,limit,keyword,status,diff,sort}=this.state;
+ let newsort=sort;
+ if(newsort===undefined){
+ newsort="desc"
+ }
+ let params= {
+ order_by:"mine",
+ tag_level:tag_level,
+ tag_id:tag_id,
+ page:1,
+ limit:limit,
+ keyword:keyword,
+ status:status,
+ diff:diff,
+ sort:newsort
+ }
+ this.shixunresultend(params)
+ }
+
+
+ shixunsPage=(value)=>{
+ this.setState({
+ page:value,
+ typepvisible:true,
+ pages:value
+ })
+ let {order_by, tag_level, tag_id, limit, keyword, status, diff,sort} = this.state;
+ let params= {
+ order_by:order_by,
+ tag_level:tag_level,
+ tag_id:tag_id,
+ page:value,
+ limit:limit,
+ keyword:keyword,
+ status:status,
+ diff:diff,
+ sort:sort
+ }
+
+ let Url=`/shixuns.json`;
+ axios.get(Url,{
+ params
+ }).then((response)=> {
+ if(response.status===200){
+ this.setState({
+ middleshixundata: response.data,
+ typepvisible:false,
+ });
+ }
+ }).catch((error)=>{
+ console.log(error)
+ });
+ }
+ ShixunsState=(val,type)=>{
+ // sort,
+ let {tag_level, tag_id, page, limit, keyword, status, diff,sort} = this.state;
+ let newsort=sort;
+ this.setState({
+ order_by:type,
+ typepvisible:true,
+ pages:1,
+ // sort:sort
+ })
+
+ let params
+ // let vals=false
+ if(newsort===undefined){
+ newsort="desc"
+ }
+ params= {
+ order_by:type,
+ tag_level:tag_level,
+ tag_id:tag_id,
+ page:1,
+ limit:limit,
+ keyword:keyword,
+ status:status,
+ diff:diff,
+ sort:newsort
+ }
+ this.shixunresultend(params)
+ }
+
+ Shixunsupcircles=(sort)=>{
+ console.log(sort)
+ this.setState({
+ sort:sort
+ })
+ let {
+ order_by,
+ tag_level,
+ tag_id,
+ limit,
+ keyword,
+ status,
+ diff,
+ } = this.state;
+
+
+
+ let params= {
+ order_by:order_by,
+ tag_level:tag_level,
+ tag_id:tag_id,
+ page:1,
+ limit:limit,
+ keyword:keyword,
+ status:status,
+ diff:diff,
+ sort:sort
+ }
+ this.shixunresultend(params)
+ }
+
+
+
+
+ shixunresultend=(params)=>{
+ let Url=`/shixuns.json`;
+ axios.get(Url,{
+ params
+ }).then((response)=> {
+ // TODO 有keyword返回值时 显示一共有多少条记录
+ if(response.status===200){
+ this.setState({
+ search_tags:response.data.search_tags,
+ middleshixundata: response.data,
+ typepvisible:false,
+ pages:1
+ });
+ }
+ }).catch((error)=>{
+ console.log(error)
+ });
+ }
+ render() {
+ let {middleshixundata, typepvisible, pages, search_tags, keyword,parsedid,newtag_level,newpalce} = this.state;
+
+ // console.log(this.state.updata)
+ return (
+
+ {this.state.updata===undefined?"":}
+ {/**/}
+
+
+
+
+
+ {/**/}
+
+ );
+ }
+}
+
+export default SnackbarHOC() (TPMIndexHOC ( ShixunsIndex ));
diff --git a/public/react/src/tpm/shixuns/css/TPMBanner.css b/public/react/src/tpm/shixuns/css/TPMBanner.css
new file mode 100644
index 000000000..fe059fccd
--- /dev/null
+++ b/public/react/src/tpm/shixuns/css/TPMBanner.css
@@ -0,0 +1,114 @@
+.shixunsdiffcult{
+ width: 40px;
+ height: 21px;
+ overflow: hidden;
+ margin-left: 8px;
+ }
+
+ .rateYo{
+ text-align: center;
+ cursor: default;
+ width: 111px;
+ }
+
+ a:link, a:visited {
+ color: #05101a;
+}
+
+a:link{text-decoration:none;}
+
+a:visited{text-decoration:none;}
+
+a:hover{text-decoration:none;}
+
+a:active{text-decoration:none;}
+
+
+.next-rating-overlay .next-icon{
+ color: #FFA800!important;
+}
+
+.displayblock{
+ display:block;
+ text-align: center;
+ margin-bottom: 20px;
+}
+
+.totalScore{
+ justify-content: center;
+ align-items: center;
+ display: -webkit-flex;
+ height: 100%;
+}
+
+.next-progress-line{
+ width: 210px !important;
+ margin-left: 10px;
+ margin-top: 4px;
+}
+
+.next-progress-line-overlay-normal{
+ background-color: #FFA800 !important;
+}
+.next-rating-base-disabled{
+ cursor: default!important;
+}
+/*#challenge_begin {*/
+/*!*height: 40px !important;*!*/
+/*line-height: 30px;*/
+/*}*/
+.ant-modal-title{
+ font-size: 16px;
+ font-weight: bold !important;
+ color: #333;
+}
+
+.ml60{
+ margin-left:20px;
+}
+
+.marginauto{
+ margin:0 auto;
+}
+.margin152{
+ margin-left: 152px;
+}
+
+.margin-tp26{
+ margin-top: -26px;
+}
+.edu-h315{
+ height:315px;
+}
+
+.height39 {
+ height: 39px !important;
+}
+
+#commentsStar{
+ margin-top: -7px;
+ width: 90px;
+ height: 80px;
+}
+
+.startbtnModal .ant-modal-content{
+ background: transparent;
+ box-shadow: 0 4px 12px transparent;
+}
+
+.startbtnModal .ant-modal-content .ant-modal-body .ant-spin-spinning{
+ margin-left: 45%;
+}
+
+.mr51{
+ margin-right:51px;
+}
+
+.flexbannerright{
+ display: flex;
+ justify-content: flex-end;
+}
+
+.width360{
+ width:360px;
+}
\ No newline at end of file
diff --git a/public/react/src/tpm/shixuns/shixunCss/ShixunCardList.css b/public/react/src/tpm/shixuns/shixunCss/ShixunCardList.css
new file mode 100644
index 000000000..c806434f5
--- /dev/null
+++ b/public/react/src/tpm/shixuns/shixunCss/ShixunCardList.css
@@ -0,0 +1,13 @@
+#myshixuns_count{
+ text-decoration:none !important;
+}
+#created_at{
+ text-decoration:none !important;
+}
+.shixun_repertoire{
+ cursor: pointer ;
+}
+.next-btn-medium:hover{
+ color: #4CACFF;
+ border:1px solid #4CACFF;
+}
\ No newline at end of file
diff --git a/public/react/src/tpm/shixuns/shixunCss/ShixunSearchBar.css b/public/react/src/tpm/shixuns/shixunCss/ShixunSearchBar.css
new file mode 100644
index 000000000..9fba271ce
--- /dev/null
+++ b/public/react/src/tpm/shixuns/shixunCss/ShixunSearchBar.css
@@ -0,0 +1,20 @@
+.iconfontShixunSearchBar{
+ z-index: 1000;
+ position: absolute;
+ right: 3px;
+ top: 0px;
+}
+
+.diffSelect{
+ margin-left:20px !important;
+ }
+ .ant-input-search-button{
+ /*margin-right: 10px;*/
+ border: 1px solid transparent;
+ }
+.Mousebox{
+ width: 800px !important;
+}
+.subshaicontent a{
+ height:30px;
+}
\ No newline at end of file
diff --git a/public/react/src/tpm/shixuns/shixunCss/shixunCard.css b/public/react/src/tpm/shixuns/shixunCss/shixunCard.css
new file mode 100644
index 000000000..1ec00a26e
--- /dev/null
+++ b/public/react/src/tpm/shixuns/shixunCss/shixunCard.css
@@ -0,0 +1,42 @@
+.ml350 {
+ margin-left: 40%;
+}
+
+.ml32 {
+ margin-left: 32%;
+}
+
+.square-img{
+ min-height: 210px;
+}
+.task-hide{
+ margin-bottom: 0em;
+}
+.backFAFAFA{
+ background:#FAFAFA;
+}
+
+.demo {
+ width: 500px;
+ background-color: #0dcecb;
+ text-align: center;
+ padding:50px;
+}
+.next-loading {
+ margin-bottom: 5px;
+ width:100%;
+}
+
+.next-rating-overlay .next-icon{
+ color: #FFA800!important;
+}
+
+.custom-pagination {
+ display: inline-block;
+ margin-left: 10px;
+}
+
+.ml425{
+ margin-left:42.5%;
+ margin-top:20px;
+}
\ No newline at end of file
diff --git a/public/react/src/tpm/shixuns/shixunCss/tag2.png b/public/react/src/tpm/shixuns/shixunCss/tag2.png
new file mode 100644
index 0000000000000000000000000000000000000000..423d2f7e39a62908f164fd3315dcc03b82007541
GIT binary patch
literal 1170
zcmeAS@N?(olHy`uVBq!ia0vp^0zfRo!3HEV4DF?Wlw^r(L`iUdT1k0gQ7VIDN`6wR
zf@f}GdTLN=VoGJ<$y6H#24=O)kcg59UmvUF{9L_6kQ%*;+ybC(1_m4Zih{)C?9>v4
zq}24xJX@vryZ0+8WTx0Eg`4^s_!c;)W@LI)6{QAO`Gq7`WhYyvDB0U7*i={n4aiL`
zNmQuF&B-gas<2f8n`;GRgM{^!6u?SKvTcwn`Gt*5rG`3JMx70H<
zwX`rY(NQomFf`LQu+%p+(KRr%GO)BVFjRm7C7^9ZDQQ+gE^bh}fIM5JjFOT9D}DX)
z@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7^KE~&-IMVSR9nfZANAQKal
z@=Hr>m4GgVcpfZU!c9<|c-Qt`
Date: Wed, 20 Nov 2019 08:50:50 +0800
Subject: [PATCH 07/17] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8F=90=E4=BA=A4?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../modules/developer/newOrEditTask/index.js | 83 +++++++---
.../newOrEditTask/rightpane/RightPaneCode.js | 122 --------------
.../rightpane/RightPaneControl.js | 71 --------
.../newOrEditTask/rightpane/index.js | 154 +++++++++++++++++-
4 files changed, 201 insertions(+), 229 deletions(-)
delete mode 100644 public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneCode.js
delete mode 100644 public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneControl.js
diff --git a/public/react/src/modules/developer/newOrEditTask/index.js b/public/react/src/modules/developer/newOrEditTask/index.js
index 05f599f63..6d9a14663 100644
--- a/public/react/src/modules/developer/newOrEditTask/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/index.js
@@ -3,43 +3,72 @@
* @Author: tangjiang
* @Date: 2019-11-15 16:38:34
* @Last Modified by: tangjiang
- * @Last Modified time: 2019-11-19 11:34:19
+ * @Last Modified time: 2019-11-19 23:23:41
*/
import './index.scss';
-import React, { Component } from 'react';
+import React from 'react';
import { connect } from 'react-redux';
import SplitPane from 'react-split-pane';// import { Form } from 'antd';
import { Button, Icon } from 'antd';
import { Link } from 'react-router-dom';
import LeftPane from './leftpane';
-import RightPane from './rightpane';
-class NewOrEditTask extends Component {
+import RightPane from './rightpane/index';
- render() {
- return (
-
-
-
- 后退
-
- 标题内容
-
-
-
-
-
-
-
-
-
-
-
+// class NewOrEditTask extends React.Component {
+// render() {
+// return (
+//
+//
+//
+// 后退
+//
+// 标题内容
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+// )
+// }
+// }
+
+const NewOrEditTask = () => {
+
+ // 表单提交
+ const handleSubmitForm = () => {}
+ return (
+
+
+
+ 后退
+
+ 标题内容
+
+
+
+
-
- )
- }
+
+ )
}
const mapStateToProps = (state) => ({
diff --git a/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneCode.js b/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneCode.js
deleted file mode 100644
index 98fb3d7a6..000000000
--- a/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneCode.js
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * @Description: 右侧代码块
- * @Author: tangjiang
- * @Date: 2019-11-18 08:42:04
- * @Last Modified by: tangjiang
- * @Last Modified time: 2019-11-19 08:55:08
- */
-
-import './index.scss';
-
-import React, { Fragment, useState } from 'react';
-import { Icon, Drawer, Tabs, Button } from 'antd';
-// import MonacoEditor from 'react-monaco-editor';
-import MonacoEditor from '@monaco-editor/react';
-import InitTabCtx from './initTabCtx';
-
-const { TabPane } = Tabs;
-const tabsArrs = [
- {
- title: '自定义测试用例',
- key: '1',
- content: '这是自定测试用例内容'
- },
- {
- title: '代码执行结果',
- key: '2',
- content: '这是自定代码执行结果'
- }
-];
-
-const RightPaneCode = () => {
-
- const [showDrawer, setShowDrawer] = useState(false);
- const [defaultActiveKey, setDefaultActiveKey] = useState('1');
- const [showTextResult, setShowTextResult] = useState(false);
- const [editCode, setEditCode] = useState('console.log("test")');
-
- // 打开设置
- const handleShowDrawer = () => {
- setShowDrawer(true);
- }
- // 关闭设置
- const handleDrawerClose = () => {
- setShowDrawer(false);
- }
- // 切换tab
- const handleTabChange = (key) => {
- setDefaultActiveKey(key);
- }
- // 显示/隐藏tab
- const handleShowControl = () => {
- setShowTextResult(!showTextResult);
- }
- // 沉浸tab内容
- const tabs = tabsArrs.map((tab) => (
-
-
-
- ));
-
- const handleEditorChange = (newValue, e) => {
- setEditCode(newValue);
- }
-
- const classNames = showTextResult ? 'control_tab active' : 'control_tab';
- const editorOptions = {
- selectOnLineNumbers: true,
- automaticLayout: true,
- fontSize: '16px'
- }
- return (
-
-
-
- ts.js
- 已保存
-
-
- {/** 代码编辑器 */}
-
- {/* 控制台信息 */}
-
-
-
- Some contents...
- Some contents...
- Some contents...
-
-
- );
-}
-
-export default RightPaneCode;
diff --git a/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneControl.js b/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneControl.js
deleted file mode 100644
index fd631a622..000000000
--- a/public/react/src/modules/developer/newOrEditTask/rightpane/RightPaneControl.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import './index.scss';
-
-import React, { Component } from 'react';
-import { Tabs, Button, Icon } from 'antd';
-import InitTabCtx from './initTabCtx';
-
-const { TabPane } = Tabs;
-
-const tabsArrs = [
- {
- title: '自定义测试用例',
- key: '1',
- content: '这是自定测试用例内容'
- },
- {
- title: '代码执行结果',
- key: '2',
- content: '这是自定代码执行结果'
- }
-];
-
-class RightPaneControl extends Component {
-
- state = {
- defaultActiveKey: '1'
- }
-
- handleTabChange = (key) => {
- this.setState({
- defaultActiveKey: key,
- })
- }
-
- handleShowControl = () => {
- this.setState((oldState) => ({
- showTextResult: !oldState.showTextResult
- }))
- }
-
- render () {
- const { defaultActiveKey, showTextResult } = this.state;
- // tab内容区块
- const tabs = tabsArrs.map((tab) => (
-
-
-
- ));
-
- return (
-
- )
- }
-}
-
-export default RightPaneControl;
diff --git a/public/react/src/modules/developer/newOrEditTask/rightpane/index.js b/public/react/src/modules/developer/newOrEditTask/rightpane/index.js
index b47c26425..8b5cf4917 100644
--- a/public/react/src/modules/developer/newOrEditTask/rightpane/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/rightpane/index.js
@@ -1,20 +1,156 @@
/*
- * @Description: 右侧部分: 包含代码块与控制区
+ * @Description: 右侧代码块
* @Author: tangjiang
- * @Date: 2019-11-18 08:42:40
+ * @Date: 2019-11-18 08:42:04
* @Last Modified by: tangjiang
- * @Last Modified time: 2019-11-18 22:58:39
+ * @Last Modified time: 2019-11-20 00:00:34
*/
-import React from 'react';
-import RightPaneCode from './RightPaneCode';
+import './index.scss';
-const RightPane = () => {
+import React, { Fragment, useState, useRef } from 'react';
+import { Icon, Drawer, Tabs, Button, notification } from 'antd';
+// import MonacoEditor from 'react-monaco-editor';
+import MonacoEditor from '@monaco-editor/react';
+import InitTabCtx from './initTabCtx';
+const { TabPane } = Tabs;
+const tabsArrs = [
+ {
+ title: '自定义测试用例',
+ key: '1',
+ content: '这是自定测试用例内容'
+ },
+ {
+ title: '代码执行结果',
+ key: '2',
+ content: '这是自定代码执行结果'
+ }
+];
+
+const RightPaneCode = (props) => {
+
+ const [showDrawer, setShowDrawer] = useState(false); // 控制配置滑框
+ const [defaultActiveKey, setDefaultActiveKey] = useState('1'); // 当前选中的tab
+ const [showTextResult, setShowTextResult] = useState(false); // 是否点击控制台按钮
+ const [editCode, setEditCode] = useState('console.log("test")'); // monaco编辑器内容
+ const editorRef = useRef(null); // 编辑器ref
+
+ // 打开设置
+ const handleShowDrawer = () => {
+ setShowDrawer(true);
+ }
+
+ // 关闭设置
+ const handleDrawerClose = () => {
+ setShowDrawer(false);
+ }
+
+ // 切换tab
+ const handleTabChange = (key) => {
+ setDefaultActiveKey(key);
+ }
+
+ // 显示/隐藏tab
+ const handleShowControl = () => {
+ setShowTextResult(!showTextResult);
+ }
+
+ // 沉浸tab内容
+ const tabs = tabsArrs.map((tab) => (
+
+
+
+ ));
+
+ // 文本框内容变化时,记录文本框内容
+ const handleEditorChange = (origin, monaco) => {
+ editorRef.current = monaco; // 获取当前monaco实例
+ setEditCode(origin); // 保存编辑器初始值
+ editorRef.current.onDidChangeModelContent(e => { // 监听编辑器内容的变化
+ const val = editorRef.current.getValue();
+ setEditCode(val);
+ });
+ }
+
+ // 提交按钮点击
+ const handleSubmit = () => {
+ if (!editCode) {
+ notification['error']({
+ message: '必填',
+ description: '代码块内容必须输入!'
+ });
+ editorRef.current.focus();
+ return;
+ }
+ const { onSubmit } = props;
+ onSubmit(editCode);
+ }
+
+ // 控制台点击时 添加active属性
+ const classNames = showTextResult ? 'control_tab active' : 'control_tab';
+
+ // 配置编辑器属性
+ const editorOptions = {
+ selectOnLineNumbers: true,
+ automaticLayout: true,
+ fontSize: '16px'
+ }
+
+ // 返回渲染值
return (
-
+
+
+
+ ts.js
+ 已保存
+
+
+ {/** 代码编辑器 */}
+
+ {/* 控制台信息 */}
+
+
+
+ Some contents...
+ Some contents...
+ Some contents...
+
+
);
-
}
-export default RightPane;
+export default RightPaneCode;
From 12b725d215182a0e70eb945d809338b1f391be96 Mon Sep 17 00:00:00 2001
From: tangjiang <465264938@qq.com>
Date: Sun, 24 Nov 2019 10:01:54 +0800
Subject: [PATCH 08/17] =?UTF-8?q?=E5=BC=80=E5=8F=91=E8=80=85=E7=A4=BE?=
=?UTF-8?q?=E5=8C=BA=E4=BB=A3=E7=A0=81=E4=BF=9D=E5=AD=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
public/react/package.json | 1 +
public/react/src/App.js | 11 +-
public/react/src/constants/index.js | 19 ++
.../src/modules/developer/DeveloperHome.js | 215 ++++++++-----
public/react/src/modules/developer/St | 0
public/react/src/modules/developer/index.js | 4 +-
public/react/src/modules/developer/index.scss | 7 +-
.../src/modules/developer/meditor/MEditor.js | 201 ++++++++++++
.../modules/developer/newOrEditTask/index.js | 71 ++---
.../developer/newOrEditTask/index.scss | 80 +----
.../leftpane/editorTab/AddTestDemo.js | 159 ++++++++++
.../newOrEditTask/leftpane/editorTab/index.js | 295 ++++++++++++++++--
.../leftpane/editorTab/index.scss | 66 ++++
.../developer/newOrEditTask/leftpane/index.js | 4 +-
.../newOrEditTask/leftpane/index.scss | 10 +-
.../newOrEditTask/rightpane/index.js | 22 +-
.../rightpane/initTabCtx/index.js | 13 +-
.../modules/developer/split_pane_resizer.scss | 118 +++++++
.../modules/developer/studentStudy/index.js | 59 ++++
.../modules/developer/studentStudy/index.scss | 1 +
.../developer/studentStudy/leftpane/index.js | 18 ++
.../developer/studentStudy/rightpane/index.js | 18 ++
public/react/src/redux/actions/actionTypes.js | 19 +-
public/react/src/redux/actions/index.js | 34 +-
public/react/src/redux/actions/ojForm.js | 234 ++++++++++++++
public/react/src/redux/actions/ojList.js | 23 ++
public/react/src/redux/reducers/index.js | 10 +-
.../react/src/redux/reducers/ojFormReducer.js | 143 +++++++++
.../react/src/redux/reducers/ojListReducer.js | 29 ++
public/react/src/services/ojService.js | 36 +++
30 files changed, 1672 insertions(+), 248 deletions(-)
create mode 100644 public/react/src/constants/index.js
delete mode 100644 public/react/src/modules/developer/St
create mode 100644 public/react/src/modules/developer/meditor/MEditor.js
create mode 100644 public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js
create mode 100644 public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.scss
create mode 100644 public/react/src/modules/developer/split_pane_resizer.scss
create mode 100644 public/react/src/modules/developer/studentStudy/index.js
create mode 100644 public/react/src/modules/developer/studentStudy/index.scss
create mode 100644 public/react/src/modules/developer/studentStudy/leftpane/index.js
create mode 100644 public/react/src/modules/developer/studentStudy/rightpane/index.js
create mode 100644 public/react/src/redux/actions/ojForm.js
create mode 100644 public/react/src/redux/actions/ojList.js
create mode 100644 public/react/src/redux/reducers/ojFormReducer.js
create mode 100644 public/react/src/redux/reducers/ojListReducer.js
create mode 100644 public/react/src/services/ojService.js
diff --git a/public/react/package.json b/public/react/package.json
index 61146f126..526041410 100644
--- a/public/react/package.json
+++ b/public/react/package.json
@@ -29,6 +29,7 @@
"dotenv": "4.0.0",
"dotenv-expand": "4.2.0",
"echarts": "^4.2.0-rc.2",
+ "editor.md": "^1.5.0",
"eslint": "4.10.0",
"eslint-config-react-app": "^2.1.0",
"eslint-loader": "1.9.0",
diff --git a/public/react/src/App.js b/public/react/src/App.js
index c498b5859..8c3b6d3cc 100644
--- a/public/react/src/App.js
+++ b/public/react/src/App.js
@@ -305,6 +305,11 @@ const NewOrEditTask = Loadable({
loader: () => import('./modules/developer/newOrEditTask'),
loading: Loading
});
+// 学员学习
+const StudentStudy = Loadable({
+ loader: () => import('./modules/developer/studentStudy'),
+ loading: Loading
+});
// //个人竞赛报名
// const PersonalCompetit = Loadable({
// loader: () => import('./modules/competition/personal/PersonalCompetit.js'),
@@ -483,8 +488,6 @@ class App extends Component {
-
-
{/*题库*/}
()
}/>
-
+
+
+
{name}
},
{
title: '分类',
dataIndex: 'category',
- width: '20%'
+ width: '20%',
+ align: 'center',
+ render: (category) => {category ? testMaps['category'][+category] : '-'}
},
{
title: '难度',
- dataIndex: 'level',
+ dataIndex: 'difficult',
align: 'center',
- width: '10%'
+ width: '10%',
+ render: (difficult) => {
+ if (difficult) {
+ return {testMaps['difficult'][+difficult]}
+ } else {
+ return '-';
+ }
+ }
},
{
title: '热度',
- dataIndex: 'hot',
+ dataIndex: 'hack_user_lastest_codes_count',
sorter: true,
align: 'center',
width: '10%'
},
{
title: '通过率',
- dataIndex: 'pass',
+ dataIndex: 'passed_rate',
sorter: true,
align:'right',
- width: '10%'
+ width: '10%',
+ render: val => {`${val}%`}
}
];
@@ -130,52 +159,41 @@ class DeveloperHome extends PureComponent {
state = {
data: [],
pagination: {
+ total: 1, // 总条数
+ pageSize: 10, // 每页显示条数
+ current: 1, // 当前页数
showQuickJumper: true
},
loading: false,
+ searchParams: {
+ search: '', // 查询关键字
+ 'come_from': '', // 来源
+ difficult: '', // 难易度
+ status: '', // 未做
+ category: '', // 分类
+ 'sort_by': '', // 排序
+ 'sort_direction': '' // 排序方向
+ }
};
componentDidMount() {
- this.fetch();
+ this.fetchData();
+ const {hacks_count} = this.props.ojListReducer;
+ this.setState({
+ pagination: {
+ total: hacks_count
+ }
+ });
}
handleTableChange = (pagination, filters, sorter) => {
- const pager = { ...this.state.pagination };
- pager.current = pagination.current;
- this.setState({
- pagination: pager,
- });
- this.fetch({
- results: pagination.pageSize,
- page: pagination.current,
- sortField: sorter.field,
- sortOrder: sorter.order,
- ...filters,
- });
+ // console.log(pagination, filters, sorter);
+ const {field, order} = sorter;
+ this.handleFilterSearch({sort_by: field, sort_direction: order === 'descend' ? 'desc' : 'asc'});
};
- fetch = (params = {}) => {
- console.log('params:', params);
- this.setState({ loading: true });
- // reqwest({
- // url: 'https://randomuser.me/api',
- // method: 'get',
- // data: {
- // results: 10,
- // ...params,
- // },
- // type: 'json',
- // }).then(data => {
- // const pagination = { ...this.state.pagination };
- // // Read total count from server
- // // pagination.total = data.totalCount;
- // pagination.total = 200;
- // this.setState({
- // loading: false,
- // data: data.results,
- // pagination,
- // });
- // });
+ fetchData = () => {
+ this.props.fetchOJList(this.state.searchParams);
};
/**
@@ -198,27 +216,55 @@ class DeveloperHome extends PureComponent {
)
};
-
+ getOptionsItem = (type) => {
+ return maps[type].map(item => {
+ return
+ });
+ }
+ // 点击条件时加载数据
+ handleFilterSearch = (obj) => {
+ const searchParams = Object.assign({}, this.state.searchParams, obj);
+ this.setState({
+ searchParams: searchParams
+ }, () => {
+ this.fetchData();
+ });
+ }
/**
* 搜索输入框
* @param value 输入框值
*/
handleInputSearch = (value) => {
- console.log('搜索值==', value);
+ value = value.trim();
+ // if (value.length === 0) return;
+ this.handleFilterSearch({search: value});
}
+ // handleSearchChange = (e) => {
+ // console.log(e.target.value);
+ // const value = e.target.value.trim();
+ // }
// 下拉类别菜单
- handleCategoryMenuClick = (e) => {
- console.log('dropdown ==>>>', e);
+ handleCategoryMenuClick = (item) => {
+ this.handleFilterSearch({category: +item.key === 0 ? '' : +item.key});
}
// 难度下拉
- handleHardMenuClick = (e) => {}
+ handleHardMenuClick = (item) => {
+ this.handleFilterSearch({difficult: +item.key});
+ }
// 状态下拉
- handleSatusMenuClick = (e) => {}
+ handleSatusMenuClick = (item) => {
+ this.handleFilterSearch({status: +item.key});
+ }
// 来源下拉
- handleOriginMenuClick = (e) => {}
+ handleOriginMenuClick = (item) => {
+ this.handleFilterSearch({come_from: item.key === 'all' ? '' : item.key});
+ }
render () {
// const { testReducer, handleClick } = this.props;
+ const { ojListReducer: {hacks_list, top_data, hacks_count} } = this.props;
+ const {passed_count = 0, simple_count = 0, medium_count = 0, diff_count = 0} = top_data;
+ // console.log( '======>>>>>>', ojListReducer );
return (
@@ -226,11 +272,11 @@ class DeveloperHome extends PureComponent {
-
已解决 589 / 1800 题
+
已解决 {passed_count} / {hacks_count} 题
-
-
-
+
+
+
-
+
分类
-
+
难度
-
+
状态
-
+
来源
this.handleInputSearch(value)}
style={{ width: 320, float: 'right' }}
/>
@@ -263,7 +310,7 @@ class DeveloperHome extends PureComponent {
Math.random()}
- dataSource={this.state.data}
+ dataSource={hacks_list}
pagination={this.state.pagination}
onChange={this.handleTableChange}
/>
@@ -281,12 +328,14 @@ class DeveloperHome extends PureComponent {
* @param {*} ownProps DeveloperHome 中的 props
*/
const mapStateToProps = (state, ownProps) => ({
- testReducer: state.testReducer
+ testReducer: state.testReducer,
+ ojListReducer: state.ojListReducer
});
const mapDispatchToProps = (dispatch) => ({
- handleClick: () => dispatch(actions.toggleTodo())
+ handleClick: () => dispatch(actions.toggleTodo()),
+ fetchOJList: (params) => dispatch(actions.getOJList(params))
});
export default connect(
diff --git a/public/react/src/modules/developer/St b/public/react/src/modules/developer/St
deleted file mode 100644
index e69de29bb..000000000
diff --git a/public/react/src/modules/developer/index.js b/public/react/src/modules/developer/index.js
index 524dd6104..cf082fa70 100644
--- a/public/react/src/modules/developer/index.js
+++ b/public/react/src/modules/developer/index.js
@@ -11,9 +11,7 @@ import DeveloperHome from './DeveloperHome';
const App = () => {
return (
-
-
-
+
);
}
diff --git a/public/react/src/modules/developer/index.scss b/public/react/src/modules/developer/index.scss
index f041da670..ca7454092 100644
--- a/public/react/src/modules/developer/index.scss
+++ b/public/react/src/modules/developer/index.scss
@@ -9,7 +9,10 @@
}
.developer-list{
- overflow: hidden;
+ // overflow: hidden;
+ .ant-spin-container{
+ padding-bottom: 100px;
+ }
.card-top {
border-radius:4px;
background:rgba(255,255,255,1);
@@ -50,4 +53,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/public/react/src/modules/developer/meditor/MEditor.js b/public/react/src/modules/developer/meditor/MEditor.js
new file mode 100644
index 000000000..7ab7129fd
--- /dev/null
+++ b/public/react/src/modules/developer/meditor/MEditor.js
@@ -0,0 +1,201 @@
+/*
+ * @Description:
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-11-21 16:57:34
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-11-21 20:11:05
+ */
+import React from 'react';
+import { getUrl } from 'educoder';
+
+const $ = window.$;
+const path = getUrl("/editormd/lib/")
+const imageUrl = `/api/attachments.json`;
+// 恢复数据
+function md_rec_data(k,mdu,id, editor){
+ if(window.sessionStorage.getItem(k+mdu) !== null){
+ editor.setValue(window.sessionStorage.getItem(k+mdu));
+ md_clear_data(k,mdu,id);
+ }
+}
+
+// 保存数据
+function md_add_data(k,mdu,d){
+ window.sessionStorage.setItem(k+mdu,d);
+}
+
+// 清空保存的数据
+function md_clear_data(k,mdu,id){
+ window.sessionStorage.removeItem(k+mdu);
+ var id1 = "#e_tip_"+id;
+ var id2 = "#e_tips_"+id;
+ if(k == 'content'){
+ $(id2).html("");
+ }else{
+ $(id1).html("");
+ }
+}
+
+function md_elocalStorage(editor,mdu,id){
+ if (window.sessionStorage){
+ var oc = window.sessionStorage.getItem('content'+mdu);
+ if(oc !== null ){
+ console.log("#e_tips_"+id)
+ $("#e_tips_"+id).data('editor', editor);
+ var h = '您上次有已保存的数据,是否恢复 ? / 不恢复';
+ $("#e_tips_"+id).html(h);
+ }
+ setInterval(function() {
+ var d = new Date();
+ var h = d.getHours();
+ var m = d.getMinutes();
+ var s = d.getSeconds();
+ h = h < 10 ? '0' + h : h;
+ m = m < 10 ? '0' + m : m;
+ s = s < 10 ? '0' + s : s;
+ if(editor.getValue().trim() != ""){
+ md_add_data("content",mdu,editor.getValue());
+ var id1 = "#e_tip_"+id;
+ var id2 = "#e_tips_"+id;
+
+ $(id1).html(" 数据已于 " + h + ':' + m + ':' + s +" 保存 ");
+ $(id2).html("");
+ }
+ },10000);
+
+ }else{
+ $("#e_tip_"+id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!');
+ }
+}
+
+
+function create_editorMD(id, width, high, placeholder, imageUrl, callback) {
+ var editorName = window.editormd(id, {
+ width: width,
+ height: high,
+ path: path, // "/editormd/lib/"
+
+ syncScrolling: "single",
+ tex: true,
+ tocm: true,
+ emoji: true,
+ taskList: true,
+ codeFold: true,
+ searchReplace: true,
+ htmlDecode: "style,script,iframe",
+ sequenceDiagram: true,
+ autoFocus: false,
+ toolbarIcons: function () {
+ // Or return editormd.toolbarModes[name]; // full, simple, mini
+ // Using "||" set icons align right.
+ return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"]
+ },
+ toolbarCustomIcons: {
+ testIcon: "",
+ testIcon1: ""
+ },
+ //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。
+ saveHTMLToTextarea: true,
+ // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标
+ dialogMaskOpacity: 0.6,
+ placeholder: placeholder,
+ imageUpload: true,
+ imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"],
+ imageUploadURL: imageUrl,//url
+ onload: function () {
+ // this.previewing();
+ $("#" + id + " [type=\"latex\"]").bind("click", function () {
+ editorName.cm.replaceSelection("```latex");
+ editorName.cm.replaceSelection("\n");
+ editorName.cm.replaceSelection("\n");
+ editorName.cm.replaceSelection("```");
+ var __Cursor = editorName.cm.getDoc().getCursor();
+ editorName.cm.setCursor(__Cursor.line - 1, 0);
+ });
+
+ $("#" + id + " [type=\"inline\"]").bind("click", function () {
+ editorName.cm.replaceSelection("`$$$$`");
+ var __Cursor = editorName.cm.getDoc().getCursor();
+ editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3);
+ editorName.cm.focus();
+ });
+ $("[type=\"inline\"]").attr("title", "行内公式");
+ $("[type=\"latex\"]").attr("title", "多行公式");
+
+ md_elocalStorage(editorName, `answers__${id}`, "Memoanswers");
+
+ callback && callback()
+ }
+ });
+ return editorName;
+}
+
+function initialEditorMd(id, width, height, placeholder, imageUrl, callback) {
+
+ const testEditor = window.editormd(id, {
+ width: width,
+ height: height,
+ path : path,
+ // theme : "light",
+ // previewTheme : "light",
+ // editorTheme : "pastel-on-dark",
+ markdown : '/test code',
+ codeFold : true,
+ //syncScrolling : false,
+ saveHTMLToTextarea : true, // 保存 HTML 到 Textarea
+ searchReplace : true,
+ //watch : false, // 关闭实时预览
+ htmlDecode : "style,script,iframe|on*", // 开启 HTML 标签解析,为了安全性,默认不开启
+ //toolbar : false, //关闭工具栏
+ //previewCodeHighlight : false, // 关闭预览 HTML 的代码块高亮,默认开启
+ emoji : true,
+ taskList : true,
+ tocm : true, // Using [TOCM]
+ tex : true, // 开启科学公式TeX语言支持,默认关闭
+ flowChart : true, // 开启流程图支持,默认关闭
+ sequenceDiagram : true, // 开启时序/序列图支持,默认关闭,
+ //dialogLockScreen : false, // 设置弹出层对话框不锁屏,全局通用,默认为true
+ //dialogShowMask : false, // 设置弹出层对话框显示透明遮罩层,全局通用,默认为true
+ //dialogDraggable : false, // 设置弹出层对话框不可拖动,全局通用,默认为true
+ //dialogMaskOpacity : 0.4, // 设置透明遮罩层的透明度,全局通用,默认值为0.1
+ //dialogMaskBgColor : "#000", // 设置透明遮罩层的背景颜色,全局通用,默认为#fff
+ imageUpload : true,
+ imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
+ imageUploadURL : imageUrl,
+ onload : function() {
+ $("#" + id + " [type=\"latex\"]").bind("click", function () {
+ testEditor.cm.replaceSelection("```latex");
+ testEditor.cm.replaceSelection("\n");
+ testEditor.cm.replaceSelection("\n");
+ testEditor.cm.replaceSelection("```");
+ var __Cursor = testEditor.cm.getDoc().getCursor();
+ testEditor.cm.setCursor(__Cursor.line - 1, 0);
+ });
+
+ $("#" + id + " [type=\"inline\"]").bind("click", function () {
+ testEditor.cm.replaceSelection("`$$$$`");
+ var __Cursor = testEditor.cm.getDoc().getCursor();
+ testEditor.cm.setCursor(__Cursor.line, __Cursor.ch - 3);
+ testEditor.cm.focus();
+ });
+ $("[type=\"inline\"]").attr("title", "行内公式");
+ $("[type=\"latex\"]").attr("title", "多行公式");
+ }
+ });
+
+ return testEditor;
+}
+
+export default class MEditor extends React.Component {
+
+ componentDidMount () {
+ // create_editorMD('editormd_area', '100%', 400, '', imageUrl);
+ initialEditorMd('editormd_area', '100%', 400, '', imageUrl);
+ }
+ render () {
+ return (
+
+ )
+ }
+}
diff --git a/public/react/src/modules/developer/newOrEditTask/index.js b/public/react/src/modules/developer/newOrEditTask/index.js
index 6d9a14663..3a2c11728 100644
--- a/public/react/src/modules/developer/newOrEditTask/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/index.js
@@ -6,45 +6,37 @@
* @Last Modified time: 2019-11-19 23:23:41
*/
import './index.scss';
-import React from 'react';
+import React, { useCallback, useEffect } from 'react';
import { connect } from 'react-redux';
import SplitPane from 'react-split-pane';// import { Form } from 'antd';
import { Button, Icon } from 'antd';
import { Link } from 'react-router-dom';
import LeftPane from './leftpane';
import RightPane from './rightpane/index';
+import actions from '../../../redux/actions';
-// class NewOrEditTask extends React.Component {
-// render() {
-// return (
-//
-//
-//
-// 后退
-//
-// 标题内容
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-// )
-// }
-// }
-
-const NewOrEditTask = () => {
+const NewOrEditTask = (props) => {
// 表单提交
- const handleSubmitForm = () => {}
+ const handleSubmitForm = (code) => {
+ props.saveOjFormCode(code); // 保存代码块值
+ props.handleFormSubmit(); // 提交表单
+ };
+
+ useEffect(() => {
+ console.log('获取路由参数: ====', props.match.params);
+ const id = props.match.params.id;
+ // 保存OJForm的id号,指明是编辑还是新增
+ props.saveOJFormId(id);
+ if (id) { // id号即 identifier
+ // TODO id 存在时, 编辑, 获取 store 中的记录数
+ // props.getOJFormById(id);
+ } else {
+ // 清空store中的测试用例集合
+ props.clearOJFormStore();
+ }
+ }, []);
+
return (
@@ -57,12 +49,10 @@ const NewOrEditTask = () => {
-
+
-
+
@@ -75,7 +65,18 @@ const mapStateToProps = (state) => ({
});
-const mapDispatchToProps = (dispatch) => ({});
+const mapDispatchToProps = (dispatch) => ({
+ // 保存提交的代码值
+ saveOjFormCode: (value) => dispatch(actions.saveOjFormCode(value)),
+ // 表单提交时,调用表单验证功能
+ handleFormSubmit: () => dispatch(actions.validateOjForm()),
+ // 根据id号获取表单信息
+ getOJFormById: (id) => dispatch(actions.getOJFormById(id)),
+ // 保存 OJ form id值
+ saveOJFormId: (id) => dispatch(actions.saveOJFormId(id)),
+ // 清空测试用例的集合
+ clearOJFormStore: () => dispatch(actions.clearOJFormStore()),
+});
export default connect(
mapStateToProps,
diff --git a/public/react/src/modules/developer/newOrEditTask/index.scss b/public/react/src/modules/developer/newOrEditTask/index.scss
index 1d5c6e2a4..75646c4db 100644
--- a/public/react/src/modules/developer/newOrEditTask/index.scss
+++ b/public/react/src/modules/developer/newOrEditTask/index.scss
@@ -1,80 +1,2 @@
-.new_add_task_wrap{
- height: 100vh;
- .task_header{
- display: flex;
- align-items: center;
- // justify-content: space-between;
- height: 65px;
- background:rgba(34,34,34,1);
- padding:0 30px;
+@import '../split_pane_resizer.scss';
- .header_btn,
- .header_title{
- color: #fff;
- }
- .header_btn{
- width: 88px;
- }
- .header_title{
- flex: 1;
- text-align: center;
- }
- }
- .split-pane-area{
- position: relative;
- height: calc(100% - 65px);
- .left_pane,
- .right_pane{
- height: 100%;
- }
- }
-}
-.Resizer {
- background: #000;
- opacity: 0.2;
- z-index: 1;
- -moz-box-sizing: border-box;
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
- -moz-background-clip: padding;
- -webkit-background-clip: padding;
- background-clip: padding-box;
-}
-
-.Resizer:hover {
- -webkit-transition: all 2s ease;
- transition: all 2s ease;
-}
-
-.Resizer.horizontal {
- height: 11px;
- margin: -5px 0;
- border-top: 5px solid rgba(255, 255, 255, 0);
- border-bottom: 5px solid rgba(255, 255, 255, 0);
- cursor: row-resize;
- width: 100%;
-}
-
-.Resizer.horizontal:hover {
- border-top: 5px solid rgba(0, 0, 0, 0.5);
- border-bottom: 5px solid rgba(0, 0, 0, 0.5);
-}
-
-.Resizer.vertical {
- width: 11px;
- margin: 0 -5px;
- border-left: 5px solid rgba(255, 255, 255, 0);
- border-right: 5px solid rgba(255, 255, 255, 0);
- cursor: col-resize;
-}
-
-.Resizer.vertical:hover {
- border-left: 5px solid rgba(0, 0, 0, 0.5);
- border-right: 5px solid rgba(0, 0, 0, 0.5);
-}
-.Resizer.disabled {
- cursor: not-allowed;
-}
-.Resizer.disabled:hover {
- border-color: transparent;
-}
diff --git a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js
new file mode 100644
index 000000000..8930bfc63
--- /dev/null
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/AddTestDemo.js
@@ -0,0 +1,159 @@
+/*
+ * @Description: 添加测试用例
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-11-21 09:19:38
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-11-22 19:45:48
+ */
+import './index.scss';
+import React, { useEffect, useState } from 'react';
+import { Collapse, Icon, Input, Form, Button, Modal } from 'antd';
+import { connect } from 'react-redux';
+const { Panel } = Collapse;
+const { TextArea } = Input;
+const FormItem = Form.Item;
+const AddTestDemo = (props) => {
+ const {
+ form: { getFieldDecorator },
+ onSubmitTest,
+ onDeleteTest,
+ testCase,
+ key
+ } = props;
+
+ const [isEditor, setIsEditor] = useState(false);
+ const [loading, setLoading] = useState(false);
+ // console.log('测试用例属性: ====>>>>', props);
+ // 删除操作
+ const handleDeletePanel = (e) => {
+ e.stopPropagation();
+ e.preventDefault();
+ // console.log('点击的删除按钮')
+ Modal.confirm({
+ title: '删除',
+ content: '确定要删除当前测试用例吗?',
+ okText: '确定',
+ cancelText: '取消',
+ onOk() {
+ console.log('确定删除');
+ onDeleteTest(testCase);
+ }
+ })
+ }
+
+ // 右侧删除图标
+ const genExtra = () => (
+
+ )
+
+ // 取消操作
+ const handleReset = (e) => {
+ e.preventDefault();
+ props.form.resetFields();
+ }
+
+ // 保存
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ props.form.validateFields((err, values) => {
+ if (err) {
+ return;
+ }
+ console.log('提交表单: ', values);
+ onSubmitTest(values);
+ });
+ }
+ // 编辑后保存
+ const handleEditorOrSave = (e) => {
+ if (!isEditor) {
+ setIsEditor(true);
+ } else {
+ // TODO 调用修改测试用例接口
+ setIsEditor(false); // 保存后 设置 false
+ setLoading(true);
+ }
+ }
+
+ const renderSubmitBtn = () => {
+ const { identifier, testCase } = props;
+ // console.log('========', identifier);
+ // 1. 新增时,不显示按钮
+ if (identifier) {
+ if (testCase.isAdd) {
+ return (
+
+
+
+
+ );
+ } else {
+ return (
+
+
+
+ );
+ }
+ }
+ }
+
+ // 指定文本框是否可编辑
+ const isDisabled = (testCase) => {
+ return testCase.isAdd && !isEditor;
+ };
+
+ return (
+
+
+
+
+
+ );
+}
+
+const mapStateToProps = (state) => {
+ const ojFormReducer = state.ojFormReducer;
+ return {
+ identifier: ojFormReducer.identifier
+ }
+};
+
+const mapDispatchToProps = (dispatch) => ({
+
+});
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(Form.create()(AddTestDemo));
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 9c4499dee..aa810b445 100644
--- a/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
+++ b/public/react/src/modules/developer/newOrEditTask/leftpane/editorTab/index.js
@@ -1,41 +1,288 @@
+/*
+ * @Description:
+ * @Author: tangjiang
+ * @Github:
+ * @Date: 2019-11-20 10:35:40
+ * @LastEditors: tangjiang
+ * @LastEditTime: 2019-11-22 19:10:53
+ */
+import './index.scss';
import React, { PureComponent } from 'react';
-import { Form, Input, Button } from 'antd';
+import { Form, Input, Select, InputNumber, Button } from 'antd';
+import { connect } from 'react-redux';
+import AddTestDemo from './AddTestDemo';
+import actions from '../../../../../redux/actions';
+import jcLabel from '../../../../../constants';
+import MEditor from '../../../meditor/MEditor';
+// import { getUrl } from 'educoder';
+
+// const path = getUrl("/editormd/lib/")
+// const mEditor = require('editor.md');
+// console.log(mEditor);
const FormItem = Form.Item;
+const { Option } = Select;
+const { TextArea } = Input;
+const maps = {
+ language: [
+ { title: 'C', key: 'C' },
+ { title: 'C++', key: 'C++' },
+ { title: 'Python', key: 'Python' },
+ { title: 'Java', key: 'Java' }
+ ],
+ difficult: [
+ { title: '简单', key: '1' },
+ { title: '中等', key: '2'},
+ { title: '困难', key: '3' }
+ ],
+ category: [
+ { title: '程序设计', key: '1' },
+ { title: '算法', key: '2'}
+ ],
+ openOrNot: [
+ { title: '公开', key: '1' },
+ { title: '私有', key: '0' }
+ ]
+}
class EditTab extends PureComponent {
- handleSubmit = (e) => {
- e.preventDefault();
- this.props.form.validateFieldsAndScroll((err, value) => {
- if (!err) {
- console.log(value);
- }
- })
+ constructor (props) {
+ super(props);
+ this.editorRef = React.createRef();
+ }
+ componentDidMount () {
+ // this.createEditorMd('editormd_section', '100%', 400, '', '', '', path);
+ }
+ // 改变任务名称
+ handleNameChange = (e) => {
+ const value = e.target.value;
+ const {
+ validateOJName,
+ // validateOjLanguage,
+ // validateOjDescription,
+ // validateOjDifficult,
+ // validateOjTimeLimit,
+ // validateOjCategory,
+ // validateOpenOrNot
+ } = this.props;
+ validateOJName(value);
+ }
+ // 改变语言
+ handleLanguageChange = (value) => {
+ this.props.validateOjLanguage(value);
+ }
+ // 改变描述信息
+ handleChangeDescription = (e) => {
+ const value = e.target.value;
+ this.props.validateOjDescription(value);
+ }
+ // 改变难易度
+ handleChangeDifficult = (value) => {
+ this.props.validateOjDifficult(value);
+ }
+ // 改变时间限制
+ handleTimeLimitChange = (value) => {
+ this.props.validateOjTimeLimit(value);
+ }
+ // 改变分类
+ handleChangeCategory = (value) => {
+ this.props.validateOjCategory(value);
+ }
+ // 改变公开程序
+ handleChangeOpenOrNot = (value) => {
+ this.props.validateOpenOrNot(value);
}
render () {
- const { form } = this.props;
- const { getFieldDecorator } = form;
+ const {
+ ojFormReducer: {ojForm, ojFormValidate},
+ testCases = [], // 测试用例集合
+ position, // 添加的测试用例位置
+ addTestCase, // 添加测试用例
+ deleteTestCase, // 删除测试用例
+ } = this.props;
+ console.log('当前位置: ', position);
+ // 表单label
+ const myLabel = (name, subTitle) => {
+ if (subTitle) {
+ return (
+
+ {name}
+
+ ({subTitle})
+
+
+ )
+ } else {
+ return (
+
{name}
+ )
+ }
+ };
+ // 编程语言
+ const getOptions = (key) => {
+ return maps[key].map((opt, i) => {
+ return (
+
+ );
+ });
+ };
+ // 提交测试用例
+ const handleSubmitTest = (obj) => {
+ console.log('提交的测试用例: ', obj);
+ };
+ // 删除测试用例
+ const handleDeleteTest = (obj) => {
+ console.log('删除的测试用例: ', obj);
+ deleteTestCase(obj);
+ };
+ const renderTestCase = () => {
+ return testCases.map((item, i) => (
+
+ ));
+ };
+ // 添加测试用例
+ const handleAddTest = () => {
+ console.log('添加测试用例');
+ const obj = {
+ input: '',
+ output: '',
+ position: position,
+ isAdd: true // 新增的测试用例
+ }
+ addTestCase(obj);
+ // TODO 点击新增时,需要滚到到最底部
+ // this.editorRef.current.scrollTop
+ // const oDiv = this.editorRef.current;
+ // oDiv.scrollTo(oDiv.scrollLeft, 99999);
+ // console.log(oDiv.scrollTop);
+ // oDiv.scrollTop = 99999;
+ }
return (
-
-