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 ( + + { + maps[type].map((item) => { + return ( + + {item.name} + + ) + }) + } + + ) + }; + + /** + * 搜索输入框 + * @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 + 已保存 + +
+ {/** 代码编辑器 */} + + {/* 控制台信息 */} +
+ + {tabs} + +
+ +

+ + +

+
+
+
+ +

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 ( +
+ {/* + {tabs} + */} +
+ +

+ + +

+
+
+ ) + } +} + +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 ( +
+
+
+
+ +
+
+
+
+
+ +
+
+ + + 全部 + + + 即将发布 + + + 进行中 + + + 往期比赛 + + +
+
+ +
+
奖金
+ +
+
浏览数
+ +
+
报名数
+ + + + +
+
¥{item.bonus}
+ +
+
{item.competition_status==="nearly_published"?"--":item.visits_count}
+ +
+
{item.competition_status==="nearly_published"?"--":item.member_count}
+ + + + } + > + +
{item.name}{item.sub_title===null?"":`——${item.sub_title}`} + {/*{item.sub_title===null?"":*/} + {/*{item.sub_title}}*/} + {/**/} + } + /> + {item.description} + + + + + ) + + } + />} + + {datas===undefined?"":count===undefined?"":count >15 ?
+ + + +
:""} + + { + datas===undefined?:datas && datas.length===0? :"" + } + + + + + + + + ) + } +} +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}`} + + + + + + + this.getrightdatas(e)}> + {data && data.competition_modules.map((item, key) => { + if (item.module_type != "enroll") { + return ( + + {/*{item.has_url===false?this.getrightdata(item.id,item.module_type,item.module_url,item.has_url)}*/} + {/*>{item.name}:this.getrightdata(item.id,item.module_type)}*/} + {/*>{item.name}}*/} + {item.name} + + ) + } + })} + + + {/*this.isdownloadpdf(e)}>*/} + {/**/} + {/*证书下载*/} + {/**/} + {/**/} + + + {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以内) + } + +
    + {/* htmlType="submit" */} + + this.props.hideCompetitionedit()}>取消 +
    +
    + + ) + } +} +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: '请输入账号', + }], + })( + + )} + + +
    +

    +
    + {/*
    this.yhBanksfalse()}>

    取消

    */} + +
    +
    + + +
    +
    + +
    +
    + ) + } +} + +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 (
    - +
    + + { getFieldDecorator('name', { + rules: [ + { + required: true, message: '任务名称不能为空' + } + ] + })()} + + + + +
    ) } } -// 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?
    + {/*
    + + 高校智能化教学与实训平台 + + + EduCoder.net +
    */} +
      +
    • 网站首页
    • +
    • 关于我们
    • +
    • 联系我们
    • +
    • 合作伙伴
    • +
    • 服务协议
    • +
    • 帮助中心
    • +
    • 意见反馈
    • +
    +
    :""} +
    + {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 ( + +
    + + {isRender===true?this.Modifyloginvalue()} + {...this.props} + {...this.state} + />:""} + + {AccountProfiletype===true?this.hideAccountProfile()} + {...this.props} + {...this.state} + />:""} + this.headtypesonClick("/",false)} className={"fl mr30 ml25 mt10"}> + { + mygetHelmetapi2 === null ? + "" + : + mygetHelmetapi2===undefined||mygetHelmetapi2.nav_logo_url===null||mygetHelmetapi2.nav_logo_url===undefined? + 高校智能化教学与实训平台 + : + 高校智能化教学与实训平台 + } + + + + { + mygetHelmetapi2 === null ? + "" : + mygetHelmetapi2!==undefined&&mygetHelmetapi2.navbar!==null&&mygetHelmetapi2.navbar!==undefined&&mygetHelmetapi2.navbar.length>0? +
    +
      + {/*
    • 首页
    • */} + {/*
    • 实训路径
    • */} + { + mygetHelmetapi2.navbar && mygetHelmetapi2.navbar.map((item,key)=>{ + // console.log("headtypes"); + // console.log(headtypes);hidden + var str=new RegExp("http"); + var strbool=false; + //test方法返回值为(true或者false) + if(item.link){ + if(str.test(item.link)===true){ + strbool=true + }else{ + strbool=false + } + } + // console.log(item.hidden); + return( +
    • this.headtypesonClick(item.link,true)} className={`${headtypes===undefined?'pr':headtypes===item.link?'pr active':'pr'}`} style={item.hidden==false?{display: 'block'}:{display: 'none'}}> + { + strbool===true? + {item.name} + : + {item.name} + } +
    • + ) + }) + } + {/*
    • */} + {/* 实践课程*/} + {/*
    • */} + + {/*
    • 课堂
    • */} + {/*
    • */} + {/* /!*课堂*!/*/} + {/* 翻转课堂*/} + {/*
    • */} + + {/*
    • */} + {/* 实训项目*/} + {/* */} + {/* */} + {/*
    • */} + + + {/*
    • 教学案例
    • */} + {/*
    • */} + {/* 在线竞赛*/} + {/* */} + {/*
    • */} + {/*
    • 教学案例
    • */} + {/*
    • */} + {/*众包创新*/} + {/*
    • */} + {/*
    • 交流问答
    • */} +
    • 工程认证
    • + +
    • 0 ? 'block' : 'none'}}> + 职业路径 +
      0 ? 'block' : 'none'}}> +
        + {this.props.Headertop === undefined ? "" : this.props.Headertop.career_url.map((item, key) => { + return( +
      • {item.name}
      • + ) + }) + } +
      +
      +
    • +
    +
    + // :mygetHelmetapi2===undefined||mygetHelmetapi2.navbar===null||mygetHelmetapi2.navbar===undefined||mygetHelmetapi2.navbar.length===0? + //
    + // + //
      + // {/*
    • 首页
    • */} + // + // {/*
    • 实训路径
    • */} + //
    • + // 实践课程 + //
    • + // + // {/*
    • 课堂
    • */} + //
    • + // {/*课堂*/} + // 翻转课堂 + //
    • + // + //
    • + // 实训项目 + // {/**/} + // {/**/} + //
    • + // + //
    • 0 ? 'block' : 'none'}}> + // 职业路径 + //
      0 ? 'block' : 'none'}}> + //
        + // {this.props.Headertop === undefined ? "" : this.props.Headertop.career_url.map((item, key) => { + // return( + //
      • {item.name}
      • + // ) + // }) + // } + //
      + //
      + //
    • + // + // {/*
    • 教学案例
    • */} + //
    • + // 在线竞赛 + // {/**/} + //
    • + //
    • 教学案例
    • + // {/*
    • */} + // {/*众包创新*/} + // {/*
    • */} + //
    • 交流问答
    • + //
    • 工程认证
    • + //
    + //
    + : +
    + +
      + {/*
    • 首页
    • */} + + {/*
    • 实训路径
    • */} +
    • + 实践课程 +
    • + + {/*
    • 课堂
    • */} +
    • + {/*课堂*/} + 翻转课堂 +
    • + +
    • + 实训项目 + {/**/} + {/**/} +
    • + +
    • 0 ? 'block' : 'none'}}> + 职业路径 +
      0 ? 'block' : 'none'}}> +
        + {this.props.Headertop === undefined ? "" : this.props.Headertop.career_url.map((item, key) => { + return( +
      • {item.name}
      • + ) + }) + } +
      +
      +
    • + + {/*
    • 教学案例
    • */} +
    • + 在线竞赛 + {/**/} +
    • +
    • 教学案例
    • + {/*
    • */} + {/*众包创新*/} + {/*
    • */} +
    • 交流问答
    • +
    • 工程认证
    • +
    +
    + } + + + + + + + +
    +
    + {/**/} +
    + + 实训 + + +
    + {/**/} + {/*搜索框*/} + {showSearchOpentype===true?
    this.hideshowSearchOpen(e)} onMouseLeave={()=>this.setevaluatinghides()}> + this.onKeywordSearchKeyDowns()} + onSearch={(value) => this.onKeywordSearchKeyDown(value)} + // onPressEnter={this.onKeywordSearchKeyDown} + style={{ width: 300,height:32}} + autoFocus={true} + /> +
    :""} + + {/**/} + {/*/!**!/*/} + {/**/} + + {/**/} + {/* TODO 需要服务端接口提供最近搜索 +
    +
    最近搜索
    + + +
    */} +
    +
    + + {/* + <%= link_to '登录', signin_path, :className => "mr5" %> + + <%= link_to '注册', user_join_path, :className => "ml5" %> + */} + { user===undefined? + + this.educoderlogin()} className="mr5 color-white">登录 + + 注册 + :user.login===""? + this.educoderlogin()} className="mr5 color-white">登录 + + 注册 + : +
    + + + + + +
    + } + {/*href="https://www.educoder.net/login"*/} +
    + {/*{ loadHeader()}*/} + {showSearchOpentype===true?"":this.props.user&&this.props.user.main_site===true?this.showSearchOpen(e)}> + {/*"/images/educoder/icon/search.svg" + */} + + + :""} + + {/*
    */} +
    + + + + +
    +
    + + {coursestypes===true&&this.props.user&&this.props.user.main_site===false?"":} +
    +
    + + {this.props.user&&this.props.user.main_site===true? :""} + + +
    +
    +
      +
      +

      + {submitapplicationsvalue} +

      +
      +
    • + 取消 + 确定 +
    • + +
    +
    +
    +
    + +
    + + + + ); + } +} + +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} + +
    • +
    + +
    this.showonMouseOver()} onMouseOut={()=>this.hideonMouseOut()}> +
    学员评分
    +
    + +
    +
    this.hideonMouseOut()}> +
    + +
    +
    +
    + {star_infos[0]}分 + 总评分 +
    + {showradios === true ? + + : ""} +
    +
    +
    +
    +
    +
    + {showradios === true ? + + : ""} +
    + + {star_infos[1]}% +
    +
    +
    + {showradios === true ? + + : ""} +
    + + {star_infos[2]}% +
    +
    +
    + {showradios === true ? + + : ""} +
    + + {star_infos[3]}% +
    +
    +
    + {showradios === true ? + + : ""} +
    + + {star_infos[4]}% +
    +
    +
    + {showradios === true ? + + : ""} +
    + + {star_infos[5]}% +
    +
    +
    +
    +
    + +
    + + { + 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? + + : +
    +

    复制将在后台执行,平台将为你创建
    一个新的同名实训和内容,请问是否继续?

    +
    +
    + 取消 + 确定 +
    +
    + } + + +
    + + +

    {can_fork}
    请问是否前往进行认证?

    +
    +
    + 取消 + 确定 +
    +
    + {!!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 ( + +
    + +
    + Fork实训列表 + 返回 +
    + + + {/**/} + +
    + + { 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 ( +
    + + 实训详情 + 配置 + + +
    +
    + 配置 + { + this.props.identity===1&&this.state.status==2? + this.operateshixuns(2)}> + 永久关闭 + :"" + } + { + this.props.identity < 5 && this.state.status==0? + this.operateshixuns(1)}> + 删除实训 + :"" + } + { + this.props.identity == 1 && this.state.status == 2 ? + this.operateshixuns(1)}> + 删除实训 + :"" + } + + +
    + {delType===1?

    是否确认删除 ?

    :

    关闭后,
    用户不能再开始挑战了是否确认关闭 ?

    } +
    +
    + 取消 + {delType===1?确定:确定} +
    +
    + +
    + +
    + +

    实训名称

    + +
    + * +
    +
    + {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.saveselectpath(e)} + value={selectpath}/> +
    + + this.evaluationenter()}>确定 + this.evaluationhideModal()}>取消 +
    +
    +
    + +
    +
    +

    评测执行文件

    +
    + * +
    + 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 { + 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 ( + +
    + + +
    + + +
  • + 本关任务 +
  • +
    + + { + questionaddarray.length===0?"":questionaddarray.map((item,key)=>{ + return( +
  • this.questionlist(key,item.choose_id,item.type):""} + > + + { + item.choose_id!=0? + this.gochooseid("/shixuns/"+this.props.match.params.shixunId+"/challenges/"+this.props.match.params.checkpointId+"/editquestion"+"/"+item.choose_id)}> + {key+1}.{item.type===2?"多选题":item.type===1?"单选题":'选择题'} + :activetype==="first"?"":{key+1}.{item.type===2?"多选题":item.type===1?"单选题":'选择题'} + } + +
  • + ) + }) + } + + +
  • + + + + +
  • + +
    + + {/*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.questionlists===undefined||this.props.questionlists.length===0?"":this.props.questionlists.map((item,key)=>{ + return( +
  • + + + this.props.delquestionlists(key)}> + + +
  • + ) + }) + } +

    + this.props.addquestionlists()} + className="fl edu-default-btn edu-greyline-btn mb20 option_icon_add">新增选项 + + + {this.props.newcnttypesum===0?"请选择答案":"选项内容不能为空"} + +

    +
  • + + +
  • +
    +
    +
    + + +
    +
    +

    参考答案

    +
    +
    + +
    +
    + 必填项 +
    +
    +

    +

    +
    +
    + +
    +

    难度系数

    +
    + + 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"}}> + this.props.answer_subit()}>提交 + 取消 + + this.delecbtns()} + className="delectshixuncdbtn fr">删除 +
    + +
    + + ) + } +} + + + 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.questionlists===undefined||this.props.questionlists.length===0?"":this.props.questionlists.map((item,key)=>{ + return( +
  • + + + this.props.delquestionlists(key)}> + + + + + +
  • + ) + }) + } +

    + this.props.addquestionlists()} + className="fl edu-default-btn edu-greyline-btn mb20 option_icon_add">新增选项 + + + {this.props.newcnttypesum===0?"请选择答案":"选项内容不能为空"} + +

    +
  • + + +
  • +
    +
    +
    + + +
    +
    +

    参考答案

    +
    +
    + +
    +
    + 必填项 +
    +
    +

    +

    + +
    +
    + +
    +

    难度系数

    +
    + + 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( +
    + + 69?1526971094 + +
    + + {item.name} + +

    + {item.stu_num} 人学习 +

    +

    {item.level}

    +
    +
    + ) + }) + } +
    +
    :"" + } +
    + } +
    + ) + + + } +} + +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 ( +// +//
    +//
    +// +//
    +// +// 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?实训制作指南:""} +

    + +
    +

    实训名称

    +
    + * +
    + + + 必填项 + +
    + +
    +
    + +
    + + +
    + +

    简介

    + +
    +
    + +
    +
    +

    +

    +
    + +
    +

    技术平台

    +
    + * +
    + +

    + 列表中没有? + 申请新建 +

    + + + {/*
    */} +
    +
  • + + +
  • +
    {this.state.languagewritetype===true?"请填写该镜像语言":""}
    +
  • + + +
  • +
    {this.state.systemenvironmenttype===true?"请填写该镜像语言系统环境":""}
    +
  • + + + +
  • +
    {this.state.testcoderunmodetype===true?"请填写该镜像测试代码运行方式":""}
    +
  • + +
    + + + 上传附件 + (单个文件50M以内) + + +
    + +
  • +
    + {this.state.attachmentidstype===true?"请上传附件":""} +
    +
  • + this.sendhideModaly()} + >取消 + +
  • +
    +
    + {/**/} +
    + + + + +
    +

    新建申请已提交,请等待管理员的审核

    +
  • 我们将在1-2个工作日内与您联系 +
  • +
    +
    + 知道啦 +
    +
    +
    +
    +
    + +
    +

    请在配置页面完成后续的评测脚本设置操作

    +
    + 必填项 +
    +
    +
    + + +
    +

    命令行

    +
    + + 无命令行窗口 (选中则不给学员的实践任务提供命令窗口) + 命令行练习窗口 (选中则给学员提供用于练习操作的命令行窗口) + 命令行评测窗口 (选中则给学员提供用于关卡评测的命令行窗口) + + 多个命令行窗口(选中则允许学员同时开启多个命令行窗口) + + +
    +
    + + +
    +

    公开程度

    +
    + + 对所有公开 (选中则所有已被试用授权的用户可以学习) + 对指定单位公开 (选中则下方指定单位的已被试用授权的用户可以学习) + + +
    +
    +
    +
    +
    + +
    + (搜索选中添加单位名称) + {this.state.datalisttype===true?请勿选择重复单位:""} + {/*+ 添加*/} +
    +
    + +
    +
    + { + 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 ( +
    + +
    + + {item.st === 0 ? + + + + : + + + + } + + 第{key+1}关 + + {this.props.identity<5? + item.st === 1 ? + this.EditTraining(this.props.identity, item.challenge_id, "/editquestion")} + className="font-16 color05101a">{item.name} + : + this.EditTraining(this.props.identity, item.challenge_id, "/editcheckpoint")} + className="font-16 color05101a">{item.name}: this.startshixunCombat(this.props.identity, item.challenge_id, "/editcheckpoint")} + className="font-16 color05101a">{item.name} + } + + + + + + + + {item.delete_url != undefined && + + this.delOperations(item.challenge_id)} + style={{ display:this.props.user.admin===true?"block":this.props.identity < 5 && ChallengesDataList.shixun_status === 0 ? "block" : 'none' }} + className="fl ring-op-green mr25"> + + + + } + + + {item.up_url != undefined && + + this.operations(item.challenge_id, "up")} + style={{ display:this.props.user.admin===true?"block":this.props.identity < 5 && ChallengesDataList.shixun_status === 0 ? "block" : 'none' }} + className="fl ring-op-green mr25"> + + + + } + {item.down_url != undefined && + + this.operations(item.challenge_id, "down")} + style={{ display: this.props.user.admin===true?"block":this.props.identity < 5 && ChallengesDataList.shixun_status=== 0 ? "block" : 'none' }} + className="fl ring-op-green mr25"> + + + + + } + + { + item.st === 1 ? + + + + + + : + + + + + + + } + + +
    +
    + {item.passed_count} 人完成挑战 + {item.playing_count} 人正在挑战 + 完成挑战可获得经验值 {item.score} + + + {/*判断比较复杂 有排第一不能是灰色按钮*/} + {item.status === 2 ? + this.startshixunCombat(false,undefined, item.challenge_id)} + // onClick={() => this.startshixunCombat(false)} + title={"查看挑战关卡"} + >已完成 : "" + } + + { + ChallengesDataList.allow_skip === true && item.status === 1? + this.startshixunCombat(false,undefined, item.challenge_id)} + // onClick={() => this.startshixunCombat(false)} + >直接挑战 : "" + } + + + { + ChallengesDataList.allow_skip === false ? item.status === 1? + + this.startshixunCombat(false,undefined, item.challenge_id)} + style={{marginTop: '-2px'}}>直接挑战 + :"":"" + + } + + + + { + item.status === 0 ? + + this.startshixunCombat(false,undefined, item.challenge_id):""} + style={{marginTop: '-2px'}}>直接挑战 + :"" + } + + + +
    +
    + ) + })} +
    + + + + + + +
    +

    目前该实训项目尚在内测中,将于{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 */} + {/*
    + + + 分支 1 + + Git使用指南 +
    */} + + { 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 && + +添加文件 + :"" + } + + + +
    + + + { + jsCopy() + }} data-tip-down="点击复制版本库地址" + className="fl ml5"> + + + + + {/* Git使用指南 */} + + + { $('#repository_url_tip').css('display') === 'none' + ? $('#repository_url_tip').show() + : $('#repository_url_tip').hide() }} + className="fl ml6 mt1"> + + + + +
    +
    + + {this.props.secret_repository_tab && + + } + +
    +
    + + + {/* 用户、最近提交时间 */} + { + trees === undefined || trees === null ||trees.length===0? : +
    + {commits===undefined?"":commits===null||commits.length===0?"":
    + {author.name} + {commits[0].author.name} + 提交于 + + {commits===undefined?"":commits[0].time} + :{commits===undefined?"":commits[0].title} + + + + 提交记录 + +
    } + +
    +
    + {/* 当前目录位置 */} + + +
    + { trees === undefined ?"": trees === null || trees.length===0?"":trees.map((item, index) => { + return ( +
  • + + + this.onRepoFileClick(item)}> +  {item.name} + + +
  • + ) + })} +
    +
    +
    +
    + } + + {/* 当前分支的文件 */} + +
    +
    + } +
    + + ); + } +} +/* + 提交记录 +
    + { 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 && +
    + fetchRepo(0)} + > + {match.params.shixunId} + + / + { pathArray.map((item, index) => { + // /shixuns/3ozvy5f8/repository/3ozvy5f8/master/shixun_show/src + return ( + + { this.props.nameTypeMap[item] === 'tree' || item.indexOf('.') === -1 + ? fetchRepo(index + 1)} + className="color-blue"> + {item} + : + + {item} + } + {index !== pathArray.length - 1 && /} + + ) + }) + } +
    } + +
    + + ); + } +} +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.user.name} + {item.time} + [第{item.round}关] +
    +
    + +
    +
    +

    {item.content}

    +
    +
    +
    +
    + + { + item.replies.map((i,k)=>{ + return( +
    +
    +
    +
    +
    + {i.user.name} + {i.time} +
    +

    + + + + + + + +

    +
    +
    +
    +
    +

    {i.content}

    +
    +
    +
    +
    +
    +
    + + ) + }) + } + + +

    + + + + + + + + + + + + + + + + + 3 + + +

    + + +
    +
    + + 0?1442652658 + +
    + +
    +
    + +
    +
    调整高度
    + 发送 +
    +
    +
    +
    +
    +
    + ) + }) + } + +
    +
    +
    + ) + } + } + + 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)=>( + + { + item.map((list,k)=>{ + return( + +
    + {list.name} +
    + { + list.tags.map((tag,e)=>{ + return( + {tag.name} + ) + }) + } +
    +
    +
    + ) + }) + } +
    + ) + + 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 - 已保存 - -
    - {/** 代码编辑器 */} - - {/* 控制台信息 */} -
    - - {tabs} - -
    - -

    - - -

    -
    -
    -
    - -

    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 ( -
    - {/* - {tabs} - */} -
    - -

    - - -

    -
    -
    - ) - } -} - -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 + 已保存 + +
    + {/** 代码编辑器 */} + + {/* 控制台信息 */} +
    + + {tabs} + +
    + +

    + + +

    +
    +
    +
    + +

    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 ( + + +
    + + { + getFieldDecorator('input', { + rules: [ + { required: true, message: '输入值不能为空'} + ], + initialValue: testCase && testCase.input + })(