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;