webpack 升级 适当优化

dev_aliyun2
harry 5 years ago
parent 1b8c0a3ad8
commit 1fa2b11310

@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

@ -0,0 +1,68 @@
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `npm start`
Runs the app in the development mode.<br />
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.<br />
You will also see any lint errors in the console.
### `npm test`
Launches the test runner in the interactive watch mode.<br />
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `npm run build`
Builds the app for production to the `build` folder.<br />
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.<br />
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `npm run eject`
**Note: this is a one-way operation. Once you `eject`, you cant go back!**
If you arent satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point youre on your own.
You dont have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldnt feel obligated to use this feature. However we understand that this tool wouldnt be useful if you couldnt customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
### Analyzing the Bundle Size
This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
### Making a Progressive Web App
This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
### Advanced Configuration
This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
### Deployment
This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
### `npm run build` fails to minify
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify

@ -1,34 +0,0 @@
新版tpi改动的文件
Index.js
contex/TPIContextProvider.js
page/main/LeftViewContainer.js
taskList/TaskList.js
TPMIndexHOC.js
App.js
CodeRepositoryViewContainer.js
Index.js
choose={context.chooses}
TPIContextProvider.js
LeftViewContainer.js
TaskList.js
TPMIndexHOC.js
MainContentContainer
rep_content返回值多了一层 {content: '...'}
TODO
待同步
1、timer图标样式更换
index.html
WebSSHTimer.css
WebSSHTimer.js

@ -0,0 +1,53 @@
const {
override,
addLessLoader,
disableEsLint,
addBundleVisualizer,
addWebpackAlias,
fixBabelImports,
addWebpackPlugin
} = require("customize-cra")
const path = require('path');
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
const UglifyJsPlugin = require("uglifyjs-webpack-plugin")
const myPlugin = [
new UglifyJsPlugin(
{
uglifyOptions: {
warnings: false,
compress: {
drop_debugger: true,
drop_console: true
}
}
}
)
]
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
module.exports = override(
disableEsLint(),
// addBundleVisualizer(),
addLessLoader({
javascriptEnabled: true
}),
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true
}),
addWebpackPlugin(new MonacoWebpackPlugin({})),
(config) => {
if (process.env.NODE_ENV === "production") config.devtool = false;
if (process.env.NODE_ENV !== "development") config.plugins = [...config.plugins, ...myPlugin]
if (process.env.NODE_ENV !== "development") {
config.output.publicPath = `/h5educoderbuild/`;
}
config.resolve.plugins = config.resolve.plugins.filter(plugin => !(plugin instanceof ModuleScopePlugin));
return config
},
addWebpackAlias({
"educoder": path.resolve(__dirname, './src/common/educoder.js')
}),
);

@ -1,93 +0,0 @@
'use strict';
const fs = require('fs');
const path = require('path');
const paths = require('./paths');
// Make sure that including paths.js after env.js will read .env variables.
delete require.cache[require.resolve('./paths')];
const NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV) {
throw new Error(
'The NODE_ENV environment variable is required but was not specified.'
);
}
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
var dotenvFiles = [
`${paths.dotenv}.${NODE_ENV}.local`,
`${paths.dotenv}.${NODE_ENV}`,
// Don't include `.env.local` for `test` environment
// since normally you expect tests to produce the same
// results for everyone
NODE_ENV !== 'test' && `${paths.dotenv}.local`,
paths.dotenv,
].filter(Boolean);
// Load environment variables from .env* files. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set. Variable expansion is supported in .env files.
// https://github.com/motdotla/dotenv
// https://github.com/motdotla/dotenv-expand
dotenvFiles.forEach(dotenvFile => {
if (fs.existsSync(dotenvFile)) {
require('dotenv-expand')(
require('dotenv').config({
path: dotenvFile,
})
);
}
});
// We support resolving modules according to `NODE_PATH`.
// This lets you use absolute paths in imports inside large monorepos:
// https://github.com/facebookincubator/create-react-app/issues/253.
// It works similar to `NODE_PATH` in Node itself:
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
// https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421
// We also resolve them to make sure all tools using them work consistently.
const appDirectory = fs.realpathSync(process.cwd());
process.env.NODE_PATH = (process.env.NODE_PATH || '')
.split(path.delimiter)
.filter(folder => folder && !path.isAbsolute(folder))
.map(folder => path.resolve(appDirectory, folder))
.join(path.delimiter);
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
// injected into the application via DefinePlugin in Webpack configuration.
const REACT_APP = /^REACT_APP_/i;
function getClientEnvironment(publicUrl) {
const raw = Object.keys(process.env)
.filter(key => REACT_APP.test(key))
.reduce(
(env, key) => {
env[key] = process.env[key];
return env;
},
{
// Useful for determining whether were running in production mode.
// Most importantly, it switches React into the correct mode.
NODE_ENV: process.env.NODE_ENV || 'development',
// Useful for resolving the correct path to static assets in `public`.
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
// This should only be used as an escape hatch. Normally you would put
// images into the `src` and `import` them in code to get their paths.
PUBLIC_URL: '/react/build/.',
}
);
// Stringify all values so we can feed into Webpack DefinePlugin
const stringified = {
'process.env': Object.keys(raw).reduce((env, key) => {
env[key] = JSON.stringify(raw[key]);
return env;
}, {}),
};
return { raw, stringified };
}
module.exports = getClientEnvironment;

@ -1,14 +0,0 @@
'use strict';
// This is a custom Jest transformer turning style imports into empty objects.
// http://facebook.github.io/jest/docs/en/webpack.html
module.exports = {
process() {
return 'module.exports = {};';
},
getCacheKey() {
// The output is always the same.
return 'cssTransform';
},
};

@ -1,12 +0,0 @@
'use strict';
const path = require('path');
// This is a custom Jest transformer turning file imports into filenames.
// http://facebook.github.io/jest/docs/en/webpack.html
module.exports = {
process(src, filename) {
return `module.exports = ${JSON.stringify(path.basename(filename))};`;
},
};

@ -1,55 +0,0 @@
'use strict';
const path = require('path');
const fs = require('fs');
const url = require('url');
// Make sure any symlinks in the project folder are resolved:
// https://github.com/facebookincubator/create-react-app/issues/637
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
const envPublicUrl = process.env.PUBLIC_URL;
function ensureSlash(path, needsSlash) {
const hasSlash = path.endsWith('/');
if (hasSlash && !needsSlash) {
return path.substr(path, path.length - 1);
} else if (!hasSlash && needsSlash) {
return `${path}/`;
} else {
return path;
}
}
const getPublicUrl = appPackageJson =>
envPublicUrl || require(appPackageJson).homepage;
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
// "public path" at which the app is served.
// Webpack needs to know it to put the right <script> hrefs into HTML even in
// single-page apps that may serve index.html for nested URLs like /todos/42.
// We can't use a relative path in HTML because we don't want to load something
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
function getServedPath(appPackageJson) {
const publicUrl = getPublicUrl(appPackageJson);
const servedUrl =
envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/');
return ensureSlash(servedUrl, true);
}
// config after eject: we're in ./config/
module.exports = {
dotenv: resolveApp('.env'),
appBuild: resolveApp('build'),
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveApp('src/index.js'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveApp('src/setupTests.js'),
appNodeModules: resolveApp('node_modules'),
publicUrl: getPublicUrl(resolveApp('package.json')),
servedPath: getServedPath(resolveApp('package.json')),
};

@ -1,22 +0,0 @@
'use strict';
if (typeof Promise === 'undefined') {
// Rejection tracking prevents a common issue where React gets into an
// inconsistent state due to an error, but it gets swallowed by a Promise,
// and the user has no idea what causes React's erratic future behavior.
require('promise/lib/rejection-tracking').enable();
window.Promise = require('promise/lib/es6-extensions.js');
}
// fetch() polyfill for making API calls.
require('whatwg-fetch');
// Object.assign() is commonly used with React.
// It will use the native implementation if it's present and isn't buggy.
Object.assign = require('object-assign');
// In tests, polyfill requestAnimationFrame since jsdom doesn't provide it yet.
// We don't polyfill it in the browser--this is user's responsibility.
if (process.env.NODE_ENV === 'test') {
require('raf').polyfill(global);
}

@ -1,287 +0,0 @@
'use strict';
const autoprefixer = require('autoprefixer');
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
// const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const getClientEnvironment = require('./env');
const paths = require('./paths');
// Webpack uses `publicPath` to determine where the app is being served from.
// In development, we always serve from the root. This makes config easier.
const publicPath = '/';
// `publicUrl` is just like `publicPath`, but we will provide it to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
const publicUrl = '';
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);
// This is the development configuration.
// It is focused on developer experience and fast rebuilds.
// The production configuration is different and lives in a separate file.
// 测试用的
module.exports = {
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.s
//devtool: "cheap-module-eval-source-map",
// 开启调试
devtool: "source-map", // 开启调试
// These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle.
// The first two entry points enable "hot" CSS and auto-refreshes for JS.
entry: [
// We ship a few polyfills by default:
require.resolve('./polyfills'),
// Include an alternative client for WebpackDevServer. A client's job is to
// connect to WebpackDevServer by a socket and get notified about changes.
// When you save a file, the client will either apply hot updates (in case
// of CSS changes), or refresh the page (in case of JS changes). When you
// make a syntax error, this client will display a syntax error overlay.
// Note: instead of the default WebpackDevServer client, we use a custom one
// to bring better experience for Create React App users. You can replace
// the line below with these two lines if you prefer the stock client:
// require.resolve('webpack-dev-server/client') + '?/',
// require.resolve('webpack/hot/dev-server'),
require.resolve('react-dev-utils/webpackHotDevClient'),
// Finally, this is your app's code:
paths.appIndexJs,
// We include the app code last so that if there is a runtime error during
// initialization, it doesn't blow up the WebpackDevServer client, and
// changing JS code would still trigger a refresh.
],
output: {
// Add /* filename */ comments to generated require()s in the output.
pathinfo: true,
// This does not produce a real file. It's just the virtual path that is
// served by WebpackDevServer in development. This is the JS bundle
// containing code from all our entry points, and the Webpack runtime.
filename: 'static/js/bundle.js',
// There are also additional JS chunk files if you use code splitting.
chunkFilename: 'static/js/[name].chunk.js',
// This is the URL that app is served from. We use "/" in development.
publicPath: publicPath,
// Point sourcemap entries to original disk location (format as URL on Windows)
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'),
},
resolve: {
// This allows you to set a fallback for where Webpack should look for modules.
// We placed these paths second because we want `node_modules` to "win"
// if there are any conflicts. This matches Node resolution mechanism.
// https://github.com/facebookincubator/create-react-app/issues/253
modules: ['node_modules', paths.appNodeModules].concat(
// It is guaranteed to exist because we tweak it in `env.js`
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
// These are the reasonable defaults supported by the Node ecosystem.
// We also include JSX as a common component filename extension to support
// some tools, although we do not recommend using it, see:
// https://github.com/facebookincubator/create-react-app/issues/290
// `web` extension prefixes have been added for better support
// for React Native Web.
extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'],
alias: {
"educoder": __dirname + "/../src/common/educoder.js",
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
},
plugins: [
// Prevents users from importing files from outside of src/ (or node_modules/).
// This often causes confusion because we only process files within src/ with babel.
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
// please link the files into your node_modules/ and let module-resolution kick in.
// Make sure your source files are compiled, as they will not be processed in any way.
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
// MonacoEditor
// https://github.com/Microsoft/monaco-editor/blob/master/docs/integrate-esm.md
// https://github.com/Microsoft/monaco-editor-webpack-plugin/issues/56
// new MonacoWebpackPlugin(),
],
},
module: {
strictExportPresence: true,
rules: [
// TODO: Disable require.ensure as it's not a standard language feature.
// We are waiting for https://github.com/facebookincubator/create-react-app/issues/2176.
// { parser: { requireEnsure: false } },
// First, run the linter.
// It's important to do this before Babel processes the JS.
// {
// test: /\.(js|jsx|mjs)$/,
// enforce: 'pre',
// use: [
// {
// options: {
// formatter: eslintFormatter,
// eslintPath: require.resolve('eslint'),
//
// },
// loader: require.resolve('eslint-loader'),
// },
// ],
// include: paths.appSrc,
// },
{
// "oneOf" will traverse all following loaders until one will
// match the requirements. When no loader matches it will fall
// back to the "file" loader at the end of the loader list.
oneOf: [
// "url" loader works like "file" loader except that it embeds assets
// smaller than specified limit in bytes as data URLs to avoid requests.
// A missing `test` is equivalent to a match.
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
},
},
// Process JS with Babel.
{
test: /\.(js|jsx|mjs)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
},
},
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader turns CSS into JS modules that inject <style> tags.
// In production, we use a plugin to extract that CSS to a file, but
// in development "style" loader enables hot editing of CSS.
{
test: /\.css$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
},
},
{
loader: require.resolve('postcss-loader'),
options: {
// Necessary for external CSS imports to work
// https://github.com/facebookincubator/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
}),
],
},
},
],
},
{
test: /\.scss$/,
use: [
require.resolve("style-loader"),
{
loader: require.resolve("css-loader"),
options: {
importLoaders: 1,
},
},
{
loader: require.resolve("sass-loader")
}
],
},
// "file" loader makes sure those assets get served by WebpackDevServer.
// When you `import` an asset, you get its (virtual) filename.
// In production, they would get copied to the `build` folder.
// This loader doesn't use a "test" so it will catch all modules
// that fall through the other loaders.
{
// Exclude `js` files to keep "css" loader working as it injects
// its runtime that would otherwise processed through "file" loader.
// Also exclude `html` and `json` extensions so they get processed
// by webpacks internal loaders.
exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
loader: require.resolve('file-loader'),
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
},
],
},
// ** STOP ** Are you adding a new loader?
// Make sure to add the new loader(s) before the "file" loader.
],
},
plugins: [
// Makes some environment variables available in index.html.
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
// In development, this will be an empty string.
new InterpolateHtmlPlugin(env.raw),
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
}),
// Add module names to factory functions so they appear in browser profiler.
new webpack.NamedModulesPlugin(),
// Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
new webpack.DefinePlugin(env.stringified),
// This is necessary to emit hot updates (currently CSS only):
new webpack.HotModuleReplacementPlugin(),
// Watcher doesn't work well if you mistype casing in a path so we use
// a plugin that prints an error when you attempt to do this.
// See https://github.com/facebookincubator/create-react-app/issues/240
new CaseSensitivePathsPlugin(),
// If you require a missing module and then `npm install` it, you still have
// to restart the development server for Webpack to discover it. This plugin
// makes the discovery automatic so you don't have to restart.
// See https://github.com/facebookincubator/create-react-app/issues/186
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
// Moment.js is an extremely popular library that bundles large locale files
// by default due to how Webpack interprets its code. This is a practical
// solution that requires the user to opt into importing specific locales.
// 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.
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty',
},
// Turn off performance hints during development because we don't do any
// splitting or minification in interest of speed. These warnings become
// cumbersome.
performance: {
hints: false,
},
};

@ -1,391 +0,0 @@
'use strict';
// extract-css-assets-webpack-plugin
const autoprefixer = require('autoprefixer');
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
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 TerserPlugin = require('terser-webpack-plugin');
const paths = require('./paths');
const getClientEnvironment = require('./env');
// Webpack uses `publicPath` to determine where the app is being served from.
// It requires a trailing slash, or the file assets will get an incorrect path.
const publicPath = paths.servedPath;
// Some apps do not use client-side routing with pushState.
// For these, "homepage" can be set to "." to enable relative asset paths.
const shouldUseRelativeAssetPaths = publicPath === './';
// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
// `publicUrl` is just like `publicPath`, but we will provide it to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
const publicUrl = publicPath.slice(0, -1);
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);
// Assert this just to be safe.
// Development builds of React are slow and not intended for production.
if (env.stringified['process.env'].NODE_ENV !== '"production"') {
throw new Error('Production builds must have NODE_ENV=production.');
}
// Note: defined here because it will be used more than once.
const cssFilename = './static/css/[name].[contenthash:8].css';
// ExtractTextPlugin expects the build output to be flat.
// (See https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/27)
// However, our output is structured with css, js and media folders.
// To have this structure working with relative paths, we have to use custom options.
const extractTextPluginOptions = shouldUseRelativeAssetPaths
? // Making sure that the publicPath goes back to to build folder.
{ publicPath: Array(cssFilename.split('/').length).join('../') }
: {};
// This is the production configuration.
// It compiles slowly and is focused on producing a fast and minimal bundle.
// The development configuration is different and lives in a separate file.
// 上线用的
// console.log('publicPath ', publicPath)
module.exports = {
// optimization: {
// minimize: true,
// minimizer: [new TerserPlugin()],
// },
// externals: {
// 'react': 'window.React'
// },
// Don't attempt to continue if there are any errors.
bail: true,
// We generate sourcemaps in production. This is slow but gives good results.
// You can exclude the *.map files from the build during deployment.
// devtool: shouldUseSourceMap ? 'nosources-source-map' : false, //正式版
devtool:false,//测试版
// In production, we only want to load the polyfills and the app code.
entry: [require.resolve('./polyfills'), paths.appIndexJs],
output: {
// The build folder.
path: paths.appBuild,
// Generated JS file names (with nested folders).
// There will be one main bundle, and one file per asynchronous chunk.
// We don't currently advertise code splitting but Webpack supports it.
filename: './static/js/[name].[chunkhash:8].js',
chunkFilename: './static/js/[name].[chunkhash:8].chunk.js',
// We inferred the "public path" (such as / or /my-project) from homepage.
// cdn
// publicPath: 'https://shixun.educoder.net/react/build/', //publicPath, https://cdn.educoder.net
// publicPath: 'https://cdn-testeduplus2.educoder.net/react/build/', //publicPath, https://cdn.educoder.net
publicPath: '/react/build/', //publicPath, https://cdn.educoder.net
// Point sourcemap entries to original disk location (format as URL on Windows)
devtoolModuleFilenameTemplate: info =>
path
.relative(paths.appSrc, info.absoluteResourcePath)
.replace(/\\/g, '/'),
},
resolve: {
// This allows you to set a fallback for where Webpack should look for modules.
// We placed these paths second because we want `node_modules` to "win"
// if there are any conflicts. This matches Node resolution mechanism.
// https://github.com/facebookincubator/create-react-app/issues/253
modules: ['node_modules', paths.appNodeModules].concat(
// It is guaranteed to exist because we tweak it in `env.js`
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
// These are the reasonable defaults supported by the Node ecosystem.
// We also include JSX as a common component filename extension to support
// some tools, although we do not recommend using it, see:
// https://github.com/facebookincubator/create-react-app/issues/290
// `web` extension prefixes have been added for better support
// for React Native Web.
extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'],
alias: {
"educoder": __dirname + "/../src/common/educoder.js",
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
},
plugins: [
// Prevents users from importing files from outside of src/ (or node_modules/).
// This often causes confusion because we only process files within src/ with babel.
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
// please link the files into your node_modules/ and let module-resolution kick in.
// Make sure your source files are compiled, as they will not be processed in any way.
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
],
},
module: {
strictExportPresence: true,
rules: [
// TODO: Disable require.ensure as it's not a standard language feature.
// We are waiting for https://github.com/facebookincubator/create-react-app/issues/2176.
// { parser: { requireEnsure: false } },
// First, run the linter.
// It's important to do this before Babel processes the JS.
{
test: /\.(js|jsx|mjs)$/,
enforce: 'pre',
use: [
{
options: {
formatter: eslintFormatter,
eslintPath: require.resolve('eslint'),
},
loader: require.resolve('eslint-loader'),
},
],
include: paths.appSrc,
},
{
// "oneOf" will traverse all following loaders until one will
// match the requirements. When no loader matches it will fall
// back to the "file" loader at the end of the loader list.
oneOf: [
// "url" loader works just like "file" loader but it also embeds
// assets smaller than specified size as data URLs to avoid requests.
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
},
},
// Process JS with Babel.
{
test: /\.(js|jsx|mjs)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
compact: true,
},
},
// The notation here is somewhat confusing.
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader normally turns CSS into JS modules injecting <style>,
// but unlike in development configuration, we do something different.
// `ExtractTextPlugin` first applies the "postcss" and "css" loaders
// (second argument), then grabs the result CSS and puts it into a
// separate file in our build process. This way we actually ship
// a single CSS file in production instead of JS code injecting <style>
// tags. If you use code splitting, however, any async bundles will still
// use the "style" loader inside the async code so CSS from them won't be
// in the main CSS file.
{
test: /\.css$/,
loader: ExtractTextPlugin.extract(
Object.assign(
{
fallback: {
loader: require.resolve('style-loader'),
options: {
hmr: false,
},
},
use: [
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
minimize: true,
sourceMap: shouldUseSourceMap,
},
},
{
loader: require.resolve('postcss-loader'),
options: {
// Necessary for external CSS imports to work
// https://github.com/facebookincubator/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
}),
],
},
},
],
},
extractTextPluginOptions
)
),
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
},
{
test: /\.scss$/,
use: [
require.resolve("style-loader"),
{
loader: require.resolve("css-loader"),
options: {
importLoaders: 1,
minimize: true,
sourceMap: shouldUseSourceMap,
},
},
{
loader: require.resolve("sass-loader")
}
],
},
// "file" loader makes sure assets end up in the `build` folder.
// When you `import` an asset, you get its filename.
// This loader doesn't use a "test" so it will catch all modules
// that fall through the other loaders.
{
loader: require.resolve('file-loader'),
// Exclude `js` files to keep "css" loader working as it injects
// it's runtime that would otherwise processed through "file" loader.
// Also exclude `html` and `json` extensions so they get processed
// by webpacks internal loaders.
exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
},
// ** STOP ** Are you adding a new loader?
// Make sure to add the new loader(s) before the "file" loader.
],
},
],
},
plugins: [
// Makes some environment variables available in index.html.
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
// In production, it will be an empty string unless you specify "homepage"
// in `package.json`, in which case it will be the pathname of that URL.
new InterpolateHtmlPlugin(env.raw),
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}),
// Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
// It is absolutely essential that NODE_ENV was set to production here.
// Otherwise React will be compiled in the very slow development mode.
new webpack.DefinePlugin(env.stringified),
// Minify the code.
// new webpack.optimize.UglifyJsPlugin({
// compress: {
// warnings: false,
// // Disabled because of an issue with Uglify breaking seemingly valid code:
// // https://github.com/facebookincubator/create-react-app/issues/2376
// // Pending further investigation:
// // https://github.com/mishoo/UglifyJS2/issues/2011
// comparisons: false,
// },
// mangle: {
// safari10: true,
// },
// output: {
// comments: false,
// // Turned on because emoji and regex is not minified properly using default
// // https://github.com/facebookincubator/create-react-app/issues/2488
// ascii_only: true,
// },
// sourceMap: shouldUseSourceMap,
// }),
//正式版上线后打开去掉debuger和console
new ParallelUglifyPlugin({
cacheDir: '.cache/',
uglifyJS:{
output: {
comments: false
},
compress: {
drop_debugger: true,
drop_console: true
}
}
}),
// Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`.
new ExtractTextPlugin({
filename: cssFilename,
}),
// Generate a manifest file which contains a mapping of all asset filenames
// to their corresponding output file so that tools can pick it up without
// having to parse `index.html`.
new ManifestPlugin({
fileName: 'asset-manifest.json',
}),
// Generate a service worker script that will precache, and keep up to date,
// the HTML & assets that are part of the Webpack build.
new SWPrecacheWebpackPlugin({
// By default, a cache-busting query parameter is appended to requests
// used to populate the caches, to ensure the responses are fresh.
// If a URL is already hashed by Webpack, then there is no concern
// about it being stale, and the cache-busting can be skipped.
dontCacheBustUrlsMatching: /\.\w{8}\./,
filename: 'service-worker.js',
logger(message) {
if (message.indexOf('Total precache size is') === 0) {
// This message occurs for every build and is a bit too noisy.
return;
}
if (message.indexOf('Skipping static resource') === 0) {
// This message obscures real errors so we ignore it.
// https://github.com/facebookincubator/create-react-app/issues/2612
return;
}
// console.log(message);
},
minify: true,
// For unknown URLs, fallback to the index page
navigateFallback: publicUrl + '/index.html',
// Ignores URLs starting from /__ (useful for Firebase):
// https://github.com/facebookincubator/create-react-app/issues/2237#issuecomment-302693219
navigateFallbackWhitelist: [/^(?!\/__).*/],
// Don't precache sourcemaps (they're large) and build asset manifest:
staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/],
}),
// Moment.js is an extremely popular library that bundles large locale files
// by default due to how Webpack interprets its code. This is a practical
// solution that requires the user to opt into importing specific locales.
// 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.
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty',
},
};

@ -1,95 +0,0 @@
'use strict';
const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware');
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
const ignoredFiles = require('react-dev-utils/ignoredFiles');
const config = require('./webpack.config.dev');
const paths = require('./paths');
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const host = process.env.HOST || '0.0.0.0';
module.exports = function(proxy, allowedHost) {
return {
// WebpackDevServer 2.4.3 introduced a security fix that prevents remote
// websites from potentially accessing local content through DNS rebinding:
// https://github.com/webpack/webpack-dev-server/issues/887
// https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
// However, it made several existing use cases such as development in cloud
// environment or subdomains in development significantly more complicated:
// https://github.com/facebookincubator/create-react-app/issues/2271
// https://github.com/facebookincubator/create-react-app/issues/2233
// While we're investigating better solutions, for now we will take a
// compromise. Since our WDS configuration only serves files in the `public`
// folder we won't consider accessing them a vulnerability. However, if you
// use the `proxy` feature, it gets more dangerous because it can expose
// remote code execution vulnerabilities in backends like Django and Rails.
// So we will disable the host check normally, but enable it if you have
// specified the `proxy` setting. Finally, we let you override it if you
// really know what you're doing with a special environment variable.
disableHostCheck:
!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true',
// Enable gzip compression of generated files.
compress: true,
// Silence WebpackDevServer's own logs since they're generally not useful.
// It will still show compile warnings and errors with this setting.
clientLogLevel: 'none',
// By default WebpackDevServer serves physical files from current directory
// in addition to all the virtual build products that it serves from memory.
// This is confusing because those files wont automatically be available in
// production build folder unless we copy them. However, copying the whole
// project directory is dangerous because we may expose sensitive files.
// Instead, we establish a convention that only files in `public` directory
// get served. Our build script will copy `public` into the `build` folder.
// In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%:
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
// In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
// Note that we only recommend to use `public` folder as an escape hatch
// for files like `favicon.ico`, `manifest.json`, and libraries that are
// for some reason broken when imported through Webpack. If you just want to
// use an image, put it in `src` and `import` it from JavaScript instead.
contentBase: paths.appPublic,
// By default files from `contentBase` will not trigger a page reload.
watchContentBase: true,
// Enable hot reloading server. It will provide /sockjs-node/ endpoint
// for the WebpackDevServer client so it can learn when the files were
// updated. The WebpackDevServer client is included as an entry point
// in the Webpack development configuration. Note that only changes
// to CSS are currently hot reloaded. JS changes will refresh the browser.
hot: true,
// It is important to tell WebpackDevServer to use the same "root" path
// as we specified in the config. In development, we always serve from /.
publicPath: config.output.publicPath,
// WebpackDevServer is noisy by default so we emit custom message instead
// by listening to the compiler events with `compiler.plugin` calls above.
quiet: true,
// Reportedly, this avoids CPU overload on some systems.
// https://github.com/facebookincubator/create-react-app/issues/293
// src/node_modules is not ignored to support absolute imports
// https://github.com/facebookincubator/create-react-app/issues/1065
watchOptions: {
ignored: ignoredFiles(paths.appSrc),
},
// Enable HTTPS if the HTTPS environment variable is set to 'true'
https: protocol === 'https',
host: host,
overlay: false,
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebookincubator/create-react-app/issues/387.
disableDotRule: true,
},
public: allowedHost,
proxy,
before(app) {
// This lets us open files from the runtime error overlay.
app.use(errorOverlayMiddleware());
// This service worker file is effectively a 'no-op' that will reset any
// previous service worker registered for the same host:port combination.
// We do this in development to avoid hitting the production cache if
// it used the same host and port.
// https://github.com/facebookincubator/create-react-app/issues/2272#issuecomment-302832432
app.use(noopServiceWorkerMiddleware());
},
};
};

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

@ -1,186 +1,90 @@
{
"name": "educoder",
"name": "h5",
"version": "0.1.0",
"private": true,
"dependencies": {
"@icedesign/base": "^0.2.5",
"@monaco-editor/react": "^2.3.0",
"@material-ui/core": "^4.9.4",
"@novnc/novnc": "^1.1.0",
"antd": "^3.23.2",
"array-flatten": "^2.1.2",
"autoprefixer": "7.1.6",
"axios": "^0.18.0",
"babel-core": "6.26.0",
"babel-eslint": "7.2.3",
"babel-jest": "20.0.3",
"babel-loader": "7.1.2",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-preset-react-app": "^3.1.1",
"babel-runtime": "6.26.0",
"axios": "^0.19.2",
"bizcharts": "^3.5.5",
"bundle-loader": "^0.5.6",
"case-sensitive-paths-webpack-plugin": "2.1.1",
"chalk": "1.1.3",
"classnames": "^2.2.5",
"clipboard": "^2.0.4",
"codemirror": "^5.46.0",
"connected-react-router": "4.4.1",
"css-loader": "0.28.7",
"dotenv": "4.0.0",
"dotenv-expand": "4.2.0",
"codemirror": "^5.52.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",
"eslint-plugin-flowtype": "2.39.1",
"eslint-plugin-import": "2.8.0",
"eslint-plugin-jsx-a11y": "5.1.1",
"eslint-plugin-react": "7.4.0",
"extract-text-webpack-plugin": "3.0.2",
"file-loader": "1.1.5",
"fs-extra": "3.0.1",
"html-webpack-plugin": "2.29.0",
"immutability-helper": "^2.6.6",
"install": "^0.12.2",
"jest": "20.0.4",
"js-base64": "^2.5.1",
"immutability-helper": "^3.0.1",
"js-base64": "^2.5.2",
"katex": "^0.11.1",
"lodash": "^4.17.5",
"loglevel": "^1.6.1",
"material-ui": "^1.0.0-beta.40",
"md5": "^2.2.1",
"moment": "^2.23.0",
"monaco-editor": "^0.15.6",
"monaco-editor-webpack-plugin": "^1.7.0",
"npm": "^6.10.1",
"monaco-editor": "^0.20.0",
"monaco-editor-webpack-plugin": "^1.9.0",
"numeral": "^2.0.6",
"object-assign": "4.1.1",
"postcss-flexbugs-fixes": "3.2.0",
"postcss-loader": "2.0.8",
"promise": "8.0.1",
"prop-types": "^15.6.1",
"qs": "^6.6.0",
"quill": "^1.3.7",
"quill-delta-to-html": "^0.11.0",
"raf": "3.4.0",
"rc-form": "^2.1.7",
"rc-pagination": "^1.16.2",
"rc-rate": "^2.4.0",
"rc-select": "^8.0.12",
"rc-tree": "^1.7.11",
"rc-upload": "^2.5.1",
"react": "^16.9.0",
"react": "^16.12.0",
"react-beautiful-dnd": "^10.0.4",
"react-codemirror": "^1.0.0",
"react-codemirror2": "^6.0.0",
"react-content-loader": "^3.1.1",
"react-cookie": "^4.0.3",
"react-cookies": "^0.1.1",
"react-dev-utils": "^5.0.0",
"react-dom": "^16.9.0",
"react-hot-loader": "^4.0.0",
"react-dom": "^16.12.0",
"react-infinite-scroller": "^1.2.4",
"react-loadable": "^5.3.1",
"react-monaco-editor": "^0.25.1",
"react-monaco-editor": "^0.34.0",
"react-player": "^1.11.1",
"react-redux": "5.0.7",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
"react-scripts": "3.4.0",
"react-split-pane": "^0.1.89",
"react-url-query": "^1.4.0",
"redux": "^4.0.0",
"redux-thunk": "2.3.0",
"redux-thunk": "^2.3.0",
"rsuite": "^4.0.1",
"sass-loader": "7.3.1",
"scroll-into-view": "^1.12.3",
"showdown": "^1.9.1",
"store": "^2.0.12",
"style-loader": "0.19.0",
"styled-components": "^4.1.3",
"sw-precache-webpack-plugin": "0.11.4",
"url-loader": "0.6.2",
"webpack": "3.8.1",
"webpack-dev-server": "2.9.4",
"webpack-manifest-plugin": "1.3.2",
"webpack-parallel-uglify-plugin": "^1.1.0",
"styled-components": "^5.0.1",
"whatwg-fetch": "2.0.3",
"wrap-md-editor": "^0.2.20"
},
"scripts": {
"start": "node --max_old_space_size=15360 scripts/start.js",
"build": "node --max_old_space_size=15360 scripts/build.js",
"concat": "node scripts/concat.js",
"gen_stats": "NODE_ENV=production webpack --profile --config=./config/webpack.config.prod.js --json > stats.json",
"ana": "webpack-bundle-analyzer ./stats.json",
"analyze": "npm run build -- --stats && webpack-bundle-analyzer build/bundle-stats.json",
"analyz": "NODE_ENV=production npm_config_report=true npm run build"
"start": "PORT=3007 react-app-rewired start",
"build": "react-app-rewired build ",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,jsx,mjs}"
],
"setupFiles": [
"<rootDir>/config/polyfills.js"
],
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,mjs}",
"<rootDir>/src/**/?(*.)(spec|test).{js,jsx,mjs}"
],
"testEnvironment": "node",
"testURL": "http://localhost",
"transform": {
"^.+\\.(js|jsx|mjs)$": "<rootDir>/node_modules/babel-jest",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|mjs|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$"
],
"moduleNameMapper": {
"^react-native$": "react-native-web"
},
"moduleFileExtensions": [
"web.js",
"mjs",
"js",
"json",
"web.jsx",
"jsx",
"node"
]
},
"babel": {
"presets": [
"react",
"react-app"
],
"plugins": [
[
"import",
{
"libraryName": "antd",
"libraryDirectory": "lib",
"style": "css"
"eslintConfig": {
"extends": "react-app"
},
"ant"
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"syntax-dynamic-import"
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"eslintConfig": {
"extends": "react-app"
},
"proxy": "http://localhost:3000",
"port": "3007",
"devDependencies": {
"@babel/runtime": "7.0.0-beta.51",
"babel-plugin-import": "^1.11.0",
"compression-webpack-plugin": "^1.1.12",
"concat": "^1.0.3",
"happypack": "^5.0.1",
"mockjs": "^1.1.0",
"node-sass": "^4.12.0",
"reqwest": "^2.0.5",
"webpack-bundle-analyzer": "^3.0.3",
"webpack-parallel-uglify-plugin": "^1.1.0"
"babel-plugin-import": "^1.13.0",
"customize-cra": "^0.5.0",
"less": "^3.11.1",
"less-loader": "^5.0.0",
"react-app-rewired": "^2.1.5",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack-bundle-analyzer": "^3.6.0"
}
}

@ -1,51 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<head>
<meta charset="utf-8">
<!--<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">-->
<!-- width=device-width, initial-scale=1 , shrink-to-fit=no -->
<!-- <meta name="viewport" content=""> -->
<meta name=”Keywords” Content=”EduCoder,信息技术实践教学,精品课程网,慕课MOOC″>
<meta name=”Keywords” Content=”实践课程,项目实战,java实训,python实战,人工智能技术,后端开发学习,移动开发入门″>
<meta name=”Keywords” Content=”翻转课堂,高效课堂创建,教学模式″>
<meta name=”Keywords” Content=”实训项目,python教程,C语言入门,java书,php后端开发,app前端开发,数据库技术″>
<meta name=”Keywords” Content=”在线竞赛,计算机应用大赛,编程大赛,大学生计算机设计大赛,全国高校绿色计算机大赛″>
<meta name=”Description” Content=”EduCoder是信息技术类实践教学平台。EduCoder涵盖了计算机、大数据、云计算、人工智能、软件工程、物联网等专业课程。超10000个实训案例及22000个技能评测点建立学、练、评、测一体化实验环境。”>
<meta name=”Description” Content=”EduCoder实践课程旨在于通过企业级实战实训案例帮助众多程序员提升各项业务能力。解决学生、学员、企业员工等程序设计能力、算法设计能力、问题求解能力、应用开发能力、系统运维能力等。”>
<meta name=”Description” Content=”EduCoder翻转课堂教学模式颠覆了传统教学模式让教师与学生的关系由“权威”变成了“伙伴”。将学习的主动权转交给学生使学生可个性化化学学生的学习主体得到了彰显。”>
<meta name=”Description”
Content=”EduCoder是信息技术类实践教学平台。EduCoder涵盖了计算机、大数据、云计算、人工智能、软件工程、物联网等专业课程。超10000个实训案例及22000个技能评测点建立学、练、评、测一体化实验环境。”>
<meta name=”Description”
Content=”EduCoder实践课程旨在于通过企业级实战实训案例帮助众多程序员提升各项业务能力。解决学生、学员、企业员工等程序设计能力、算法设计能力、问题求解能力、应用开发能力、系统运维能力等。”>
<meta name=”Description”
Content=”EduCoder翻转课堂教学模式颠覆了传统教学模式让教师与学生的关系由“权威”变成了“伙伴”。将学习的主动权转交给学生使学生可个性化化学学生的学习主体得到了彰显。”>
<meta name=”Description” Content=”EduCoder实训项目为单个知识点关卡实践训练帮助学生巩固单一弱点强化学习。 >
<meta name=”Description” Content=”EduCoder实践教学平台各类大赛为进一步提高各类学生综合运用高级语言程序设计能力培养创新意识和实践探索精神发掘优秀软件人才。 >
<!-- <meta name="viewport" id="viewport" content="width=device-width, initial-scale=0.3, maximum-scale=0.3, user-scalable=no">-->
<meta name="viewport" id="viewport" content="width=device-width, initial-scale=0.3, maximum-scale=0.3">
<meta name="theme-color" content="#000000">
<!--<meta http-equiv="cache-control" content="no-cache,no-store, must-revalidate" />-->
<!--<meta http-equiv="pragma" content="no-cache" />-->
<!--<meta http-equiv="Expires" content="0" />-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<!-- <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">-->
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<!-- <title>EduCoder</title>-->
<!--react-ssr-head-->
<script type="text/javascript">
window.__isR = true;
// 不支持ie9 ie10
if (
( navigator.userAgent.indexOf('MSIE 9') != -1
|| navigator.userAgent.indexOf('MSIE 10') != -1 )
(navigator.userAgent.indexOf('MSIE 9') != -1
|| navigator.userAgent.indexOf('MSIE 10') != -1)
&&
location.pathname.indexOf("/compatibility") == -1) {
debugger;
@ -59,39 +41,8 @@
}
</script>
<!-- <link rel="stylesheet" type="text/css" href="/css/edu-common.css">
<link rel="stylesheet" type="text/css" href="/css/edu-public.css">
<link rel="stylesheet" type="text/css" href="/css/taskstyle.css">
<link rel="stylesheet" type="text/css" href="/css/font-awesome.css">
<link rel="stylesheet" type="text/css" href="/css/editormd.min.css">
<link rel="stylesheet" type="text/css" href="/css/merge.css"> -->
<link rel="stylesheet" type="text/css" href="/css/css_min_all.css">
<!--<link rel="stylesheet" type="text/css" href="/css/css_min_all.css">-->
<!--<link rel="stylesheet" type="text/css" href="//at.alicdn.com/t/font_653600_nm6lho7nxxq.css">-->
<!-- <link href="/react/build/css/iconfont.css" rel="stylesheet" type="text/css"> -->
<!--<link href="http://47.96.87.25:48080/stylesheets/educoder/edu-all.css" rel="stylesheet" type="text/css">-->
<!--<link href="https://pandao.github.io/editor.md/examples/css/style.css" rel="stylesheet" type="text/css">-->
<!--<link href="https://pandao.github.io/editor.md/css/editormd.preview.css" rel="stylesheet" type="text/css">-->
<!-- <link href="https://testeduplus2.educoder.net/stylesheets/css/edu-common.css" rel="stylesheet" type="text/css">
<link href="https://testeduplus2.educoder.net/stylesheets/educoder/edu-main.css" rel="stylesheet" type="text/css">
<link href="https://testeduplus2.educoder.net/stylesheets/educoder/antd.min.css" rel="stylesheet" type="text/css"> -->
<!-- <link rel="stylesheet" type="text/css" href="https://www.educoder.net/stylesheets/css/font-awesome.css?1510652321"> -->
<!--<link rel="stylesheet" type="text/css" href="http://47.96.87.25:48080/stylesheets/educoder/iconfont/iconfont.css">-->
<!--需要去build js配置-->
<link rel="stylesheet" type="text/css" href="/css/iconfont.css">
<link rel="stylesheet" type="text/css" href="https://cdn.bootcss.com/quill/1.3.7/quill.core.min.css">
@ -103,50 +54,19 @@
user-select: none;
</style>
</head>
<body>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<!--用于markdown转html -->
<div id="md_div" style="display: none;"></div>
<div id="root" class="page -layout-v -fit widthunit">
<!--<div class="d2-home">-->
<!--<div class="d2-home__main">-->
<!--&lt;!&ndash;<img class="d2-home__loading"&ndash;&gt;-->
<!--&lt;!&ndash;src="loading-spin.svg"&ndash;&gt;-->
<!--&lt;!&ndash;alt="loading">&ndash;&gt;-->
<!--<div class="lds-ripple"><div></div><div></div></div>-->
<!--<div class="d2-home__title">-->
<!--正在加载资源-->
<!--</div>-->
<!--<div class="d2-home__sub-title">-->
<!--加载资源可能需要较多时间 请耐心等待-->
<!--</div>-->
<!--</div>-->
<!--<div class="d2-home__footer">-->
<!--&lt;!&ndash;<a href="www.educoder.net"&ndash;&gt;-->
<!--&lt;!&ndash;target="_blank">&ndash;&gt;-->
<!--&lt;!&ndash;&ndash;&gt;-->
<!--&lt;!&ndash;</a>&ndash;&gt;-->
<!--EduCoder-->
<!--</div>-->
<!--</div>-->
</div>
<div id="root" class="page -layout-v -fit widthunit"></div>
<div id="picture_display" style="display: none;"></div>
<!-- js css合并 文件优先级的问题 -->
<script type="text/javascript" src="/js/js_min_all.js"></script>
<!-- <script type="text/javascript" src="/js/js_min_all_2.js"></script> -->
<!--
<script type="text/javascript" src="/js/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="/js/editormd/underscore.min.js"></script>
<script type="text/javascript" src="/js/js_min_all.js"></script>
<script type="text/javascript" src="/js/editormd/marked.min.js"></script>
<script type="text/javascript" src="/js/editormd/prettify.min.js"></script>
<script type="text/javascript" src="/js/editormd/raphael.min.js"></script>
<script type="text/javascript" src="/js/editormd/sequence-diagram.min.js"></script>
<script type="text/javascript" src="/js/editormd/flowchart.min.js"></script>
@ -155,9 +75,6 @@
<script type="text/javascript" src="/js/editormd/editormd.min.js"></script>
-->
<!-- codemirror addon -->
<!--
<script type="text/javascript" src="/js/codemirror/codemirror.js"></script>
<script type="text/javascript" src="/js/codemirror/mode/javascript.js"></script>
@ -166,14 +83,10 @@
<script type="text/javascript" src="/js/merge.js"></script>
<script type="text/javascript" src="/js/edu_tpi.js"></script>
-->
<!-- testbdweb.trustie.net testbdweb.educoder.net -->
<!-- 在tpi js里加载这3个脚本 -->
<script>
(function() { // Scoping function to avoid globals
(function () { // Scoping function to avoid globals
var href = location.href;
if(window.location.port === "3007"){
if (window.location.port === "3007") {
if (href.indexOf('/tasks/') != -1) {
document.write('<script type="text/javascript" src="https://newweb.educoder.net/assets/kindeditor/kindeditor.js"><\/script>');
// build.js中会将这个url附加一个前缀 react/build
@ -183,7 +96,7 @@
document.write('<script type="text/javascript" src="https://newweb.educoder.net/javascripts/educoder/edu_application.js"><\/script>');
}
}else{
} else {
if (href.indexOf('/tasks/') != -1) {
document.write('<script type="text/javascript" src="/assets/kindeditor/kindeditor.js"><\/script>');
// build.js中会将这个url附加一个前缀 react/build
@ -203,10 +116,6 @@
<script type="text/javascript" src="https://testeduplus2.educoder.net/javascripts/educoder/edu_application.js"></script> -->
<script type="text/javascript" src="https://cdn.bootcss.com/quill/1.3.7/quill.core.min.js"></script>
<!-- <script>-->
<!-- document.body.addEventListener('touchmove', function (e) {-->
<!-- e.preventDefault(); //阻止默认的处理方式(阻止下拉滑动的效果)-->
<!-- }, {passive: false});-->
<!-- </script>-->
</body>
</body>
</html>

@ -1,172 +0,0 @@
其他的文档位置:
/educoder/public/react/public/js/readme.txt 关于js_min_all
/educoder/educoder/public/react/scripts/readme-cdn.txt 关于CDN
/educoder/public/react/src/modules/page/readme.txt 关于TPI
/educoder/public/editormd/lib/readme-marked.txt 关于md编辑器 marked.js
1、 安装node v6.9.x此安装包含了node和npm。
2、 安装cnpm命令行 npm install -g cnpm --registry=https://registry.npm.taobao.org
3、 安装依赖的js库public/react目录下<即项目package.json所在目录>,开启命令行): cnpm install
4、 如果你的ruby服务使用的是3000端口则需要在package.json中修改"port"参数的值
5、 启动服务(命令行-目录同3 npm start
6、 build初始化 npm run build
注意:
1、cnpm install 之前先需要修改下ruby mine的一个settings防止ruby mine对node_modules目录里的内容建索引详情见线上文档-react开发环境搭建
线上文档-react开发环境搭建 地址: https://www.trustie.net/boards/6862/topics/46425
2、package.json中配置
"proxy": "http://localhost:3000",
"port": "3007"
目前暂时必须写为和上面的一样ruby服务端口为3000node服务端口为3007当当前端口为3007时程序会将axios发出的请求转到localhost:3000上进行跨域请求。
3、静态js加载问题
editormd源码改动注释掉了564行 加载codemirror/codemirror.min的js代码。因为codemirror 已经加载了codemirror对象会带有插件重复加载会覆盖全局codemirror对象使得之前加载的插件失效
----------------------------------------------------------------------------------------------
React开发相关知识点
需要了解的ES6的知识 https://www.trustie.net/boards/6862/topics/46427
----------------------------------------------------------------------------------------------
新加入的lib有 axios、material-ui、lodash、classnames、moment、immutability-helper
rc-tree、rc-form 、rc-rate、rc-pagination、rc-select 、showdown
考虑替代删除确认弹出框的组件http://react-component.github.io/tooltip/examples/onVisibleChange.html
----------------------------------------------------------------------------------------------
TPI State整理 START
----------------------------------------------------------------------------------------------
TPIContextProvider 详情接口的所有state
Index.js
taskListLoading
challenges
challengesDrawerOpen
MainContentContainer.js
repositoryCode: '',
currentPath: '', // 当前所选的path可能是一个只读的path只读path的话challenge.athIndex为-1
isEditablePath // 是否是可以编辑的path
open: false, // 繁忙等级等提示用Dialog TODO 考虑重构封装到根组件
gameBuilding: false, // 评测中标志
codeStatus: 2, // 0 已修改 1 保存中 2 已保存 3 保存失败
codeLoading: false, // code加载中
resetCodeDialogOpen: false, // TODO考虑重构封装到根组件
resetPassedCodeDialogOpen: false, // TODO考虑重构封装到根组件
LeftViewContainer.js
tabIndex: 0, 页签index
dialogOpen: false,
gameAnswer: '', 答案
snackbarOpen: false,
comments: [], 评论
comment_count_without_reply: 0, 评论数量 TODO 和详情接口字段重复
// 默认pageSize为10
currentPage: 1, 评论分页
loadingComments: true, 评论加载中
gotNewReply: false, 新的回复
CodeRepositoryViewContainer.js
drawerOpen: false,
loadingFirstRepoFiles: false, drawer里的loading状态
fileTreeData: "", 文件树
codeRepositoryViewExpanded: false, 展开状态
CodeEvaluateView.js
testSetsInitedArray: testSetsExpandedArrayInitVal.slice(0), 测试集是否初始化标志
evaluateViewExpanded: false,
tabIndex: 1, 页签index
----------------------------------------------------------------------------------------------
TPI State整理 END
----------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------
重要TPI实现时修改的js库的记录 START
----------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------
重要TPI实现时修改的js库的记录 END
----------------------------------------------------------------------------------------------
create_kindeditor.js __isR 表示是react环境react环境下采用事件通知react组件来处理
if (window['__isR'] === true) {
$(document).trigger("onReply", { commentContent:tContents, id:id, editor:params.editor } );
} else {
params.form.submit();
}
editormd.min.js 直接注释掉了codemirror.min的加载应该改成有codeMirror了则不加载
// codemirror 已经加载了codemirror会有插件重复加载会使得之前加载的插件失效
// editormd.loadScript(loadPath + "codemirror/codemirror.min", function() {
对应提交项
Revision: 73d95ce266d5d7e55a3a88d08d1247b3a08c7caf
Date: 2018/4/2 16:12:21
Message: 切下一题时更新左侧editormd里的内容更新右侧codemirror内容。
js_min_all.js 最后面手动加入了若干js代码还没做分离、再合并处理 date:180507
is_cdn_link tpi_html_show方法
----------------------------------------------------------------------------------------------
TPM使用react实现的利弊 START
----------------------------------------------------------------------------------------------
1、全部使用react重写
做法第一屏使用新接口之前的js脚本还是继续使用有必要的话需要局部刷新的将部分jquery实现改为react实现
利:
tpi中评论组件、文件树组件方便复用
js、css库管理方便
暂时不依赖于react的状态管理
之前的ajax请求还是可以暂时复用
弊:
接口评估?
rails模板要改成jsx语法
头部功能区域、底部静态链接区域会存在重复代码 react版和非react版
codemirror等组件的使用会不会有问题
学习成本
目前决定新页面或者评论组件所在页面使用react实现
----------------------------------------------------------------------------------------------
TPM使用react实现的利弊 END
----------------------------------------------------------------------------------------------
其他方式comments组件build到新入口后将代码copy到rails页面
----------------------------------------------------------------------------------------------
不错的库 START
----------------------------------------------------------------------------------------------
https://livicons.com/icons-original -- 收费 动画icon
https://github.com/maxwellito/vivus -- 让SVG标签动起来
http://ianlunn.github.io/Hover/ -- hover 动画
https://github.com/legomushroom/mojs
https://github.com/juliangarnier/anime --js动画
https://codepen.io/juliangarnier/pen/gmOwJX
https://github.com/daneden/animate.css
A responsive tour snippet, with a step-by-step guide(onboarding) to help users understand how to use your website.
https://github.com/sorich87/bootstrap-tour
https://github.com/linkedin/hopscotch
https://github.com/Robophil/Product-Tour
code editor
https://microsoft.github.io/monaco-editor/

@ -1,251 +0,0 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const path = require('path');
const chalk = require('chalk');
const fs = require('fs-extra');
const webpack = require('webpack');
const config = require('../config/webpack.config.prod');
const paths = require('../config/paths');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
const printBuildError = require('react-dev-utils/printBuildError');
var CombinedStream = require('combined-stream');
var fs2 = require('fs');
const measureFileSizesBeforeBuild =
FileSizeReporter.measureFileSizesBeforeBuild;
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
const useYarn = fs.existsSync(paths.yarnLockFile);
// These sizes are pretty large. We'll warn for bundles exceeding them.
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
function removeExceptGitDir(dir) {
// readdirSync
const list = fs2.readdirSync(dir)
// if (err) return done(err);
var pending = list.length;
// if (!pending) return done(null, results);
list.forEach(function(file) {
if (file.indexOf('.git') == -1) {
file = path.resolve(dir, file);
fs.removeSync(file)
}
});
}
// First, read the current file sizes in build directory.
// This lets us display how much they changed later.
measureFileSizesBeforeBuild(paths.appBuild)
.then(previousFileSizes => {
// Remove all content but keep the directory so that
// if you're in it, you don't end up in Trash
// fs.emptyDirSync(paths.appBuild);
console.log('removeExceptGitDir')
removeExceptGitDir(paths.appBuild)
console.log('copyPublicFolder')
// Merge with the public folder
copyPublicFolder();
// Start the webpack build
return build(previousFileSizes);
})
.then(
({ stats, previousFileSizes, warnings }) => {
if (warnings.length) {
console.log(chalk.yellow('Compiled with warnings.\n'));
console.log(warnings.join('\n\n'));
console.log(
'\nSearch for the ' +
chalk.underline(chalk.yellow('keywords')) +
' to learn more about each warning.'
);
console.log(
'To ignore, add ' +
chalk.cyan('// eslint-disable-next-line') +
' to the line before.\n'
);
} else {
console.log(chalk.green('Compiled successfully.\n'));
}
console.log('File sizes after gzip:\n');
printFileSizesAfterBuild(
stats,
previousFileSizes,
paths.appBuild,
WARN_AFTER_BUNDLE_GZIP_SIZE,
WARN_AFTER_CHUNK_GZIP_SIZE
);
console.log();
const appPackage = require(paths.appPackageJson);
const publicUrl = paths.publicUrl;
const publicPath = config.output.publicPath;
const buildFolder = path.relative(process.cwd(), paths.appBuild);
printHostingInstructions(
appPackage,
publicUrl,
publicPath,
buildFolder,
useYarn
);
},
err => {
console.log(chalk.red('Failed to compile.\n'));
printBuildError(err);
process.exit(1);
}
);
// Create the production build and print the deployment instructions.
function build(previousFileSizes) {
console.log('Creating an optimized production build...');
let compiler = webpack(config);
return new Promise((resolve, reject) => {
compiler.run((err, stats) => {
if (err) {
return reject(err);
}
const messages = formatWebpackMessages(stats.toJson({}, true));
if (messages.errors.length) {
// Only keep the first error. Others are often indicative
// of the same problem, but confuse the reader with noise.
if (messages.errors.length > 1) {
messages.errors.length = 1;
}
return reject(new Error(messages.errors.join('\n\n')));
}
if (
process.env.CI &&
(typeof process.env.CI !== 'string' ||
process.env.CI.toLowerCase() !== 'false') &&
messages.warnings.length
) {
console.log(
chalk.yellow(
'\nTreating warnings as errors because process.env.CI = true.\n' +
'Most CI servers set it automatically.\n'
)
);
return reject(new Error(messages.warnings.join('\n\n')));
}
generateNewIndexJsp();
return resolve({
stats,
previousFileSizes,
warnings: messages.warnings,
});
});
});
}
function copyPublicFolder() {
fs.copySync(paths.appPublic, paths.appBuild, {
dereference: true,
filter: file => file !== paths.appHtml,
});
}
// 给build脚本增加的方法对其生成的index.html做一些文本替换以及cdn处理
function generateNewIndexJsp() {
// var combinedStream = CombinedStream.create();
var filePath = paths.appBuild + '/index.html';
// var htmlContent = fs2.createReadStream( filePath )
// stream没有replace方法
// htmlContent = htmlContent.replace('/js/js_min_all.js', '/react/build/js/js_min_all.js')
// htmlContent = htmlContent.replace('/css/css_min_all.css', '/react/build/css/css_min_all.css')
// combinedStream.append(htmlContent);
// combinedStream.pipe(fs2.createWriteStream( filePath ));
var outputPath = paths.appBuild + '/../../../public/react/build/index.html'
fs2.readFile(filePath, 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
const newVersion = '1.1.1'
let cdnHost = 'https://shixun.educoder.net'
cdnHost = 'https://ali-cdn.educoder.net'
cdnHost = ''
var mainRegex = /<script type="text\/javascript" src="\/react\/build\/.\/static\/js\/main.([a-zA-Z0-9]{8,}).js"><\/script>/
var matchResult = data.match(mainRegex)
var code = `
<script>
(function() {
var _host = '/react/build/'
/**/
if (window.location.host == 'pre-newweb.educoder.net') {
_host = 'https://testali-cdn.educoder.net/react/build/'
} else if (window.location.host == 'www.educoder.net') {
_host = 'https://ali-cdn.educoder.net/react/build/'
}
document.write('<script type="text/javascript" src="' + _host + 'js/js_min_all.js"><\\/script>');
document.write('<script type="text/javascript" src="' + _host + 'static/js/main.${matchResult[1]}.js"><\\/script>');
})()
</script>
`
var jsMinAllRegex = /<script type="text\/javascript" src="\/js\/js_min_all.js"><\/script>/
// <script type="text/javascript" src="/js/js_min_all.js"></script>
var result = data
.replace(jsMinAllRegex, code)
// .replace('/js/js_min_all.js', `${cdnHost}/react/build/js/js_min_all.js?v=${newVersion}`)
// .replace('/js/js_min_all_2.js', `${cdnHost}/react/build/js/js_min_all_2.js?v=${newVersion}`)
// ${cdnHost} 加了cdn后这个文件里的字体文件加载会有跨域的报错 ../fonts/fontawesome-webfont.eot
// TODO tpi 评测结果关闭也使用了fontawesome
.replace('/css/css_min_all.css', `${cdnHost}/react/build/css/css_min_all.css?v=${newVersion}`)
.replace('/css/iconfont.css', `${cdnHost}/react/build/css/iconfont.css?v=${newVersion}`)
.replace(/\/js\/create_kindeditor.js/g, `${cdnHost}/react/build/js/create_kindeditor.js?v=${newVersion}`)
.replace(mainRegex, '')
// .replace('/react/build/./static/css/main', `${cdnHost}/react/build/./static/css/main`)
// .replace('/react/build/./static/js/main', `${cdnHost}/react/build/./static/js/main`)
// .replace(/https:\/\/testeduplus2.educoder.net/g, '');
// .replace(/http:\/\/testbdweb.educoder.net/g, '');
// .replace('/css/css_min_all.css', '/react/build/css/css_min_all.css');
fs2.writeFile(outputPath, result, 'utf8', function (err) {
if (err) return console.log(err);
// commitAndPush();
});
});
}
function commitAndPush() {
var exec = require('child_process').exec;
function puts(error, stdout, stderr) { console.log(stdout) }
var options = {cwd:"./build"};
exec("git status && git commit -am 'b' && git push", options, puts);
}

@ -1,98 +0,0 @@
var fs = require('fs');
var uglify = require("uglify-js");
var path = require('path');
var concat = require('concat')
var results = [];
var walk = function(dir, done) {
fs.readdir(dir, function(err, list) {
console.log(list)
if (err) return done(err);
var pending = list.length;
if (!pending) return done(null, results);
list.forEach(function(file) {
file = path.resolve(dir, file);
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
// results = results.concat(res);
if (!--pending) done(null, results);
});
} else {
results.push(file);
if (!--pending) done(null, results);
}
});
});
});
};
// 需要输出文件名数组时改为true
var jsDir = './public/js/';
var cssDir = './public/css'
// true &&
false &&
walk(cssDir, function() {
console.log('results', results.length, results)
})
// return;
// ----------------------------------------------------------------------------- CSS
var cssResults = [
'D:\\Code\\trustieplus\\public\\react\\public\\css\\edu-common.css',
'D:\\Code\\trustieplus\\public\\react\\public\\css\\edu-public.css',
'D:\\Code\\trustieplus\\public\\react\\public\\css\\taskstyle.css' ,
'D:\\Code\\trustieplus\\public\\react\\public\\css\\font-awesome.css',
'D:\\Code\\trustieplus\\public\\react\\public\\css\\editormd.min.css',
'D:\\Code\\trustieplus\\public\\react\\public\\css\\merge.css',
]
concat(cssResults, './public/css/css_min_all.css')
return;
// ----------------------------------------------------------------------------- JS
var _results = [
'D:\\Code\\trustieplus\\public\\react\\public\\js\\jquery-1.8.3.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\underscore.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\marked.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\prettify.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\raphael.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\sequence-diagram.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\flowchart.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\jquery.flowchart.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\editormd\\editormd.min.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\codemirror\\codemirror.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\codemirror\\mode\\javascript.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\diff_match_patch.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\merge.js',
'D:\\Code\\trustieplus\\public\\react\\public\\js\\edu_tpi.js',
]
concat(_results, './public/js/js_min_all.js')
// var uglified = uglify.minify(['./public/js/merge.js']);
// console.log('uglified', uglified)
// fs.writeFile('concat.min.js', uglified.code, function (err){
// if(err) {
// console.log(err);
// } else {
// console.log("Script generated and saved:", 'concat.min.js');
// }
// });
// var uglified = uglify.minify(['file1.js', 'file2.js', 'file3.js']);

@ -1,23 +0,0 @@
var fs2 = require('fs');
function generateNewIndexJsp() {
var filePath = './build/index.html';
var outputPath = filePath
fs2.readFile(filePath, 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
var result = data
.replace('/js/create_kindeditor.js', '/react/build/js/create_kindeditor.js')
.replace(/https:\/\/testeduplus2.educoder.net/g, '');
// .replace(/http:\/\/testbdweb.educoder.net/g, '');
.replace('/css/css_min_all.css', '/react/build/css/css_min_all.css');
fs2.writeFile(outputPath, result, 'utf8', function (err) {
if (err) return console.log(err);
});
});
}

@ -1,16 +0,0 @@
目前是判断域名的方式动态访问对应的cdn资源
静态资源处理在build.js中如下代码
if (window.location.host == 'pre-newweb.educoder.net') {
_host = 'https://testali-cdn.educoder.net/react/build/'
} else if (window.location.host == 'www.educoder.net') {
_host = 'https://ali-cdn.educoder.net/react/build/'
}
只对预上线和正式版做了处理
动态的chunk资源处理在public-path.js中如下代码
if ( window.location.host == 'pre-newweb.educoder.net') {
__webpack_public_path__ = 'https://testali-cdn.educoder.net/react/build/'
} else if ( window.location.host == 'www.educoder.net') {
__webpack_public_path__ = 'https://ali-cdn.educoder.net/react/build/'
}

@ -1,114 +0,0 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const fs = require('fs');
const chalk = require('chalk');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const clearConsole = require('react-dev-utils/clearConsole');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const {
choosePort,
createCompiler,
prepareProxy,
prepareUrls,
} = require('react-dev-utils/WebpackDevServerUtils');
const openBrowser = require('react-dev-utils/openBrowser');
const paths = require('../config/paths');
const config = require('../config/webpack.config.dev');
const createDevServerConfig = require('../config/webpackDevServer.config');
const useYarn = fs.existsSync(paths.yarnLockFile);
const isInteractive = process.stdout.isTTY;
const portSetting = require(paths.appPackageJson).port
if ( portSetting ) {
process.env.port = portSetting
}
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// Tools like Cloud9 rely on this.
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3007;
const HOST = process.env.HOST || '0.0.0.0';
if (process.env.HOST) {
console.log(
chalk.cyan(
`Attempting to bind to HOST environment variable: ${chalk.yellow(
chalk.bold(process.env.HOST)
)}`
)
);
console.log(
`If this was unintentional, check that you haven't mistakenly set it in your shell.`
);
console.log(`Learn more here: ${chalk.yellow('http://bit.ly/2mwWSwH')}`);
console.log();
}
// We attempt to use the default port but if it is busy, we offer the user to
// run on a different port. `choosePort()` Promise resolves to the next free port.
choosePort(HOST, DEFAULT_PORT)
.then(port => {
if (port == null) {
// We have not found a port.
return;
}
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const appName = require(paths.appPackageJson).name;
const urls = prepareUrls(protocol, HOST, port);
// Create a webpack compiler that is configured with custom messages.
const compiler = createCompiler(webpack, config, appName, urls, useYarn);
// Load proxy config
const proxySetting = require(paths.appPackageJson).proxy;
console.log('-------------------------proxySetting:', proxySetting)
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
// Serve webpack assets generated by the compiler over a web sever.
const serverConfig = createDevServerConfig(
proxyConfig,
urls.lanUrlForConfig
);
const devServer = new WebpackDevServer(compiler, serverConfig);
// Launch WebpackDevServer.
devServer.listen(port, HOST, err => {
if (err) {
return console.log(err);
}
if (isInteractive) {
clearConsole();
}
console.log(chalk.cyan('Starting the development server...\n'));
openBrowser(urls.localUrlForBrowser);
});
['SIGINT', 'SIGTERM'].forEach(function(sig) {
process.on(sig, function() {
devServer.close();
process.exit();
});
});
})
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});

@ -1,27 +0,0 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
process.env.PUBLIC_URL = '';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const jest = require('jest');
const argv = process.argv.slice(2);
// Watch unless on CI or in coverage mode
if (!process.env.CI && argv.indexOf('--coverage') < 0) {
argv.push('--watch');
}
jest.run(argv);

@ -1,107 +0,0 @@
.App {
text-align: center;
}
.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 80px;
}
.App-header {
background-color: #222;
height: 150px;
padding: 20px;
color: white;
}
.App-title {
font-size: 1.5em;
}
.App-intro {
font-size: large;
}
@keyframes App-logo-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* md
codermirror maybeUpdateLineNumberWidth
*/
.editormd .CodeMirror-linenumbers {
padding: 0;
}
.editormd-html-preview hr, .editormd-preview-container hr {
/* 颜色加深 */
border-top: 1px solid #ccc;
}
/* 重置掉antd的一些样式 */
html, body {
-webkit-font-smoothing: auto !important;
}
.ant-progress-textyes {
color: #52c41a;
}
.ant-progress-textno{
color: #f5222d;
}
/* md多空格 */
.markdown-body p {
white-space: pre-wrap;
font-size: 16px!important
}
.markdown-body > p {
line-height: 25px;
}
/* https://www.educoder.net/courses/2346/group_homeworks/34405/question */
.renderAsHtml.markdown-body p {
white-space: inherit;
}
/* resize */
.editormd .CodeMirror {
border-right: none !important;
}
.editormd-preview {
border-left: 1px solid rgb(221, 221, 221);
/* 某些情况下被cm盖住了 */
z-index: 99;
}
/* 图片点击放大的场景,隐藏图片链接 */
.editormd-image-click-expand .editormd-image-dialog {
height: 234px !important;
}
.editormd-image-click-expand .editormd-image-dialog .image-link {
display: none;
}
/* 解决鼠标框选时,左边第一列没高亮的问题 */
.CodeMirror .CodeMirror-lines pre.CodeMirror-line, .CodeMirror .CodeMirror-lines pre.CodeMirror-line-like {
padding: 0 12px ;
}
/* antd扩展 */
.formItemInline.ant-form-item {
display: flex;
}
.formItemInline .ant-form-item-control-wrapper {
flex: 1;
}
/* AutoComplete placeholder 不显示的问题 */
.ant-select-auto-complete.ant-select .ant-select-selection__placeholder {
z-index: 2;
}
/* 兼容性 */
/* 火狐有滚动条时高度问题 */
@-moz-document url-prefix() {
.newContainers {
min-height: calc(100% - 60px) !important;
}
}

@ -1,8 +1,6 @@
import React, {Component} from 'react';
import React, { Component } from 'react';
import './public-path';
import logo from './logo.svg';
import './App.css';
import {ConfigProvider} from 'antd'
import { ConfigProvider } from 'antd'
import zhCN from 'antd/lib/locale-provider/zh_CN';
import {
BrowserRouter as Router,
@ -10,9 +8,6 @@ import {
Switch
} from 'react-router-dom';
import axios from 'axios';
import '@icedesign/base/dist/ICEDesignBase.css';
import '@icedesign/base/index.scss';
import LoginDialog from './modules/login/LoginDialog';
import Notcompletedysl from './modules/user/Notcompletedysl';
@ -21,45 +16,21 @@ import Trialapplicationreview from './modules/user/Trialapplicationreview';
import Addcourses from "./modules/courses/coursesPublic/Addcourses";
import AccountProfile from "./modules/user/AccountProfile";
import Accountnewprofile from './modules/user/Accountnewprofile';
import Trialapplication from './modules/login/Trialapplication';
import Certifiedprofessional from './modules/modals/Certifiedprofessional';
import NotFoundPage from './NotFoundPage'
import Loading from './Loading'
import Loadable from 'react-loadable';
import moment from 'moment'
import {MuiThemeProvider, createMuiTheme} from 'material-ui/styles';
// import './AppConfig'
import history from './history';
import {SnackbarHOC} from 'educoder'
import {initAxiosInterceptors} from './AppConfig'
import { SnackbarHOC } from './common/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: {
primary: {
main: '#4CACFF',
contrastText: 'rgba(255, 255, 255, 0.87)'
},
secondary: {main: '#4CACFF'}, // #11cb5f This is just green.A700 as hex.
},
});
//
// const Trialapplication= Loadable({
// loader: () =>import('./modules/login/Trialapplication'),
// loading:Loading,
// })
//登入
const EducoderLogin = Loadable({
loader: () => import('./modules/login/EducoderLogin'),
@ -68,30 +39,26 @@ const EducoderLogin = Loadable({
//微信登录
const Otherlogin=Loadable({
const Otherlogin = Loadable({
loader: () => import('./modules/login/Otherlogin'),
loading: Loading,
})
//微信登录
const Loginqq=Loadable({
const Loginqq = Loadable({
loader: () => import('./modules/login/Loginqq'),
loading: Loading,
})
const Otherloginstart=Loadable({
const Otherloginstart = Loadable({
loader: () => import('./modules/login/Otherloginstart'),
loading: Loading,
})
const Otherloginsqq=Loadable({
const Otherloginsqq = Loadable({
loader: () => import('./modules/login/Otherloginqq'),
loading: Loading,
})
// const TestIndex = Loadable({
// loader: () => import('./modules/test'),
// loading: Loading,
// })
const IndexWrapperComponent = Loadable({
loader: () => import('./modules/page/IndexWrapper'),
@ -103,24 +70,6 @@ const CommentComponent = Loadable({
loading: Loading,
})
// const TestMaterialDesignComponent = Loadable({
// loader: () => import('./modules/test/md/TestMaterialDesign'),
// loading: Loading,
// })
// const TestCodeMirrorComponent = Loadable({
// loader: () => import('./modules/test/codemirror/TestCodeMirror'),
// loading: Loading,
// })
// const TestComponent = Loadable({
// loader: () => import('./modules/test/TestRC'),
// loading: Loading,
// })
// const TestUrlQueryComponent = Loadable({
// loader: () => import('./modules/test/urlquery/TestUrlQuery'),
// loading: Loading,
// })
const TPMIndexComponent = Loadable({
loader: () => import('./modules/tpm/TPMIndex'),
loading: Loading,
@ -146,49 +95,12 @@ const SearchPage = Loadable({
loading: Loading,
})
// 课堂讨论
// const BoardIndex = Loadable({
// loader: () => import('./modules/courses/boards/BoardIndex'),
// loading:Loading,
// })
// //课堂普通作业&分组作业
// const CoursesWorkIndex = Loadable({
// loader: () => import('./modules/courses/busyWork/Index'),
// loading:Loading,
// })
//
// const TPMShixunchildIndexComponent = Loadable({
// loader: () => import('./modules/tpm/shixunchild/ShixunChildIndex'),
// loading: Loading,
// })
// const TPMshixunfork_listIndexComponent = Loadable({
// loader: () => import('./modules/tpm/shixunchild/Shixunfork_list'),
// loading: Loading,
// })
const ForumsIndexComponent = Loadable({
loader: () => import('./modules/forums/ForumsIndex'),
loading: Loading,
})
// trustie plus forum
// const TPForumsIndexComponent = Loadable({
// loader: () => import('./modules/tp-forums/TPForumsIndex'),
// loading: Loading,
// })
// const TestPageComponent = Loadable({
// loader: () => import('./modules/page/Index'),
// loading: Loading,
// })
//新建实训
const Newshixuns = Loadable({
loader: () => import('./modules/tpm/newshixuns/Newshixuns'),
@ -227,21 +139,11 @@ const http500 = Loadable({
loading: Loading,
})
// 登录注册
const LoginRegisterPage = Loadable({
loader: () => import('./modules/user/LoginRegisterPage'),
loading: Loading,
})
const AccountPage = Loadable({
loader: () => import('./modules/user/AccountPage'),
loading: Loading,
})
// 个人主页
const UsersInfo = Loadable({
loader: () => import('./modules/user/usersInfo/Infos'),
loading: Loading,
})
const InfosIndex = Loadable({
loader: () => import('./modules/user/usersInfo/InfosIndex'),
loading: Loading,
@ -259,36 +161,25 @@ const MoopCases = Loadable({
loading: Loading,
})
// 兴趣页面
const Interestpage = Loadable({
loader: () => import('./modules/login/EducoderInteresse'),
loading: Loading,
})
//众包创新
// const ProjectPackages=Loadable({
// loader: () => import('./modules/projectPackages/ProjectPackageIndex'),
// loading: Loading,
// })
//竞赛
const NewCompetitions=Loadable({
const NewCompetitions = Loadable({
loader: () => import('./modules/competitions/Competitions'),
loading: Loading,
})
//黑客松定制竞赛
const Osshackathon=Loadable({
const Osshackathon = Loadable({
loader: () => import('./modules/osshackathon/Osshackathon'),
loading: Loading,
})
const Messagerouting= Loadable({
const Messagerouting = Loadable({
loader: () => import('./modules/message/js/Messagerouting'),
loading: Loading,
})
const Topicbank= Loadable({
const Topicbank = Loadable({
loader: () => import('./modules/topic_bank/Topic_bank'),
loading: Loading,
})
@ -321,28 +212,28 @@ const Questionitem_banks = Loadable({
})
//试卷库
const Testpaperlibrary= Loadable({
const Testpaperlibrary = Loadable({
loader: () => import('./modules/testpaper/Testpaperlibrary'),
loading: Loading
})
//试卷编辑
const Paperlibraryeditid= Loadable({
const Paperlibraryeditid = Loadable({
loader: () => import('./modules/testpaper/Paperlibraryeditid'),
loading: Loading
})
//试卷查看
const Paperlibraryseeid= Loadable({
const Paperlibraryseeid = Loadable({
loader: () => import('./modules/testpaper/Paperlibraryseeid'),
loading: Loading
})
//人工组卷
const Paperreview= Loadable({
const Paperreview = Loadable({
loader: () => import('./modules/question/Paperreview'),
loading: Loading
})
//智能组卷
const Integeneration= Loadable({
const Integeneration = Loadable({
loader: () => import('./modules/testpaper/Intecomponents'),
loading: Loading
})
@ -373,58 +264,48 @@ const JupyterTPI = Loadable({
loader: () => import('./modules/tpm/jupyter'),
loading: Loading
});
// 微信代码编辑器
// const WXCode = Loadable({
// loader: () => import('./modules/wxcode'),
// loading: Loading
// });
// //个人竞赛报名
// const PersonalCompetit = Loadable({
// loader: () => import('./modules/competition/personal/PersonalCompetit.js'),
// loading: Loading,
// });
class App extends Component {
constructor(props) {
super(props)
this.state = {
Addcoursestype:false,
Addcoursestypes:false,
mydisplay:false,
occupation:0,
Addcoursestype: false,
Addcoursestypes: false,
mydisplay: false,
occupation: 0,
mygetHelmetapi: null,
}
}
HideAddcoursestypess=(i)=>{
HideAddcoursestypess = (i) => {
console.log("调用了");
this.setState({
Addcoursestype:false,
Addcoursestypes:false,
mydisplay:true,
occupation:i,
Addcoursestype: false,
Addcoursestypes: false,
mydisplay: true,
occupation: i,
})
};
hideAddcoursestypes=()=>{
hideAddcoursestypes = () => {
this.setState({
Addcoursestypes:false
Addcoursestypes: false
})
};
ModalCancelsy=()=>{
ModalCancelsy = () => {
this.setState({
mydisplay:false,
mydisplay: false,
})
window.location.href = "/";
};
ModalshowCancelsy=()=>{
ModalshowCancelsy = () => {
this.setState({
mydisplay:true,
mydisplay: true,
})
};
disableVideoContextMenu = () => {
window.$( "body" ).on( "mousedown", "video", function(event) {
if(event.which === 3) {
window.$('video').bind('contextmenu',function () { return false; });
window.$("body").on("mousedown", "video", function (event) {
if (event.which === 3) {
window.$('video').bind('contextmenu', function () { return false; });
} else {
window.$('video').unbind('contextmenu');
}
@ -443,20 +324,6 @@ class App extends Component {
initAxiosInterceptors(this.props);
this.getAppdata();
//
// axios.interceptors.response.use((response) => {
// // console.log("response"+response);
// if(response!=undefined)
// // console.log("response"+response.data.statu);
// if (response&&response.data.status === 407) {
// this.setState({
// isRenders: true,
// })
// }
// return response;
// }, (error) => {
// //TODO 这里如果样式变了会出现css不加载的情况
// });
window.addEventListener('error', (event) => {
const msg = `${event.type}: ${event.message}`;
@ -464,9 +331,9 @@ class App extends Component {
});
}
//修改登录方法
Modifyloginvalue=()=>{
Modifyloginvalue = () => {
this.setState({
isRender:false,
isRender: false,
})
};
@ -501,19 +368,17 @@ class App extends Component {
document.head.appendChild(link);
}
//获取当前定制信息
getAppdata=()=>{
getAppdata = () => {
let url = "/setting.json";
axios.get(url).then((response) => {
// console.log("app.js开始请求/setting.json");
// console.log("获取当前定制信息");
if(response){
if(response.data){
if (response) {
if (response.data) {
this.setState({
mygetHelmetapi:response.data.setting
mygetHelmetapi: response.data.setting
});
//存储配置到游览器
localStorage.setItem('chromesetting',JSON.stringify(response.data.setting));
localStorage.setItem('chromesettingresponse',JSON.stringify(response));
localStorage.setItem('chromesetting', JSON.stringify(response.data.setting));
localStorage.setItem('chromesettingresponse', JSON.stringify(response));
try {
if (response.data.setting.tab_logo_url) {
this.gettablogourldata(response);
@ -543,21 +408,18 @@ class App extends Component {
};
render() {
let{mygetHelmetapi}=this.state;
// console.log("appappapp");
// console.log(mygetHelmetapi);
return (
<Provider store={store}>
<ConfigProvider locale={zhCN}>
<MuiThemeProvider theme={theme}>
<Accountnewprofile {...this.props}{...this.state}/>
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={()=>this.Modifyloginvalue()}></LoginDialog>
<Accountnewprofile {...this.props}{...this.state} />
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
<Notcompletedysl {...this.props} {...this.state}></Notcompletedysl>
<Trialapplicationysl {...this.props} {...this.state}></Trialapplicationysl>
<Trialapplicationreview {...this.props} {...this.state}></Trialapplicationreview>
<Addcourses {...this.props} {...this.state} HideAddcoursestypess={(i)=>this.HideAddcoursestypess(i)}/>
<Addcourses {...this.props} {...this.state} HideAddcoursestypess={(i) => this.HideAddcoursestypess(i)} />
<AccountProfile {...this.props} {...this.state} />
<Certifiedprofessional {...this.props} {...this.state} ModalCancelsy={this.ModalCancelsy} ModalshowCancelsy={this.ModalshowCancelsy}/>
<Certifiedprofessional {...this.props} {...this.state} ModalCancelsy={this.ModalCancelsy} ModalshowCancelsy={this.ModalshowCancelsy} />
<Router>
<Switch>
@ -577,8 +439,6 @@ class App extends Component {
return (<Topicbank {...this.props} {...props} {...this.state} />)
}
}></Route>
{/*/!*众包创新*!/*/}
{/*<Route path={"/crowdsourcing"} component={ProjectPackages}/>*/}
{/*竞赛*/}
<Route path={"/competitions"}
render={
@ -592,8 +452,8 @@ class App extends Component {
<Route
path={"/osshackathon"}
render={
(props)=>{
return(
(props) => {
return (
<Osshackathon {...this.props} {...props} {...this.state} />
)
}
@ -601,17 +461,17 @@ class App extends Component {
/>
{/*认证*/}
<Route path="/account" component={AccountPage}/>
<Route path="/account" component={AccountPage} />
{/*403*/}
<Route path="/403" component={Shixunauthority}/>
<Route path="/403" component={Shixunauthority} />
<Route path="/500" component={http500}/>
<Route path="/500" component={http500} />
{/*404*/}
<Route path="/nopage" component={Shixunnopage}/>
<Route path="/nopage" component={Shixunnopage} />
<Route path="/compatibility" component={CompatibilityPageLoadable}/>
<Route path="/compatibility" component={CompatibilityPageLoadable} />
<Route
path="/login"
render={
@ -657,12 +517,6 @@ class App extends Component {
return (<BanksIndex {...this.props} {...props} {...this.state} />)
}
}></Route>
{/*<Route*/}
{/*path="/personalcompetit"*/}
{/*render={*/}
{/*(props) => (<PersonalCompetit {...this.props} {...props} {...this.state}></PersonalCompetit>)*/}
{/*}*/}
{/*/>*/}
<Route
path="/changepassword"
render={
@ -681,91 +535,72 @@ class App extends Component {
<Route path="/colleges/:id/statistics"
render={
(props) => (<College {...this.props} {...props} {...this.state} />)
}/>
} />
{/* jupyter */}
<Route path="/tasks/:identifier/jupyter/"
render={
(props) => {
return (<JupyterTPI {...this.props} {...props} {...this.state}/>)
return (<JupyterTPI {...this.props} {...props} {...this.state} />)
}
}
/>
<Route path="/tasks/:stageId" component={IndexWrapperComponent}/>
<Route path="/tasks/:stageId" component={IndexWrapperComponent} />
{/*<Route path="/shixuns/:shixunId" component={TPMIndexComponent}>*/}
{/*</Route>*/}
<Route path="/shixuns/:shixunId"
render={
(props)=>(<TPMIndexComponent {...this.props} {...props} {...this.state}></TPMIndexComponent>)
(props) => (<TPMIndexComponent {...this.props} {...props} {...this.state}></TPMIndexComponent>)
}
></Route>
{/*列表页 实训项目列表*/}
{/*<Route path="/shixuns" component={TPMShixunsIndexComponent}/>*/}
<Route path="/shixuns"
render={
(props)=>(<TPMShixunsIndexComponent {...this.props} {...props} {...this.state}></TPMShixunsIndexComponent>)
(props) => (<TPMShixunsIndexComponent {...this.props} {...props} {...this.state}></TPMShixunsIndexComponent>)
}
></Route>
{/*实训课程(原实训路径)*/}
<Route path="/paths" component={ShixunPaths}></Route>
<Route path="/search"
render={
(props)=>(<SearchPage {...this.props} {...props} {...this.state}></SearchPage>)
(props) => (<SearchPage {...this.props} {...props} {...this.state}></SearchPage>)
}
></Route>
{/*课堂*/}
<Route path="/courses" component={CoursesIndex} {...this.props} {...this.state}></Route>
{/* <Route path="/forums" component={ForumsIndexComponent}>
</Route> */}
{/* 教学案例 */}
<Route path="/moop_cases"render={
<Route path="/moop_cases" render={
(props) => (<MoopCases {...this.props} {...props} {...this.state} />)
}/>
} />
<Route path="/forums"
render={
(props)=>(<ForumsIndexComponent {...this.props} {...props} {...this.state}></ForumsIndexComponent>)
(props) => (<ForumsIndexComponent {...this.props} {...props} {...this.state}></ForumsIndexComponent>)
}
>
</Route>
<Route path="/comment" component={CommentComponent}/>
{/*<Route path="/testMaterial" component={TestMaterialDesignComponent}/>*/}
{/*<Route path="/test" component={TestIndex}/>*/}
{/*<Route path="/testCodeMirror" component={TestCodeMirrorComponent}/>*/}
{/*<Route path="/testRCComponent" component={TestComponent}/>*/}
{/*<Route path="/testUrlQuery" component={TestUrlQueryComponent}/>*/}
{/*<Route*/}
{/*path="/registration"*/}
{/*render={*/}
{/*(props) => (<Registration {...this.props} {...props} {...this.state}></Registration>)*/}
{/*}*/}
{/*/>*/}
<Route path="/comment" component={CommentComponent} />
<Route path="/messages"
render={
(props)=>(<Messagerouting {...this.props} {...props} {...this.state}></Messagerouting>)
(props) => (<Messagerouting {...this.props} {...props} {...this.state}></Messagerouting>)
}
></Route>
<Route path="/help/:type"
render={
(props)=>(<Help {...this.props} {...props} {...this.state}></Help>)
}/>
(props) => (<Help {...this.props} {...props} {...this.state}></Help>)
} />
<Route path="/ecs"
render={
(props)=>(<Ecs {...this.props} {...props} {...this.state}></Ecs>)
}/>
(props) => (<Ecs {...this.props} {...props} {...this.state}></Ecs>)
} />
<Route path="/problems/new/:id?"
render={
@ -788,20 +623,20 @@ class App extends Component {
<Route path="/Integeneration/:type/:id"
render={
(props) => (<Paperreview {...this.props} {...props} {...this.state} />)
}/>
} />
<Route path="/paperreview/:type"
render={
(props) => (<Paperreview {...this.props} {...props} {...this.state} />)
}/>
} />
<Route path="/paperlibrary/edit/:id"
render={
(props) => (<Paperlibraryeditid {...this.props} {...props} {...this.state} />)
}/>
} />
<Route path="/paperlibrary/see/:id"
render={
(props) => (<Paperlibraryseeid {...this.props} {...props} {...this.state} />)
}/>
} />
<Route path="/myproblems/:id/:tab?"
render={
@ -823,40 +658,36 @@ class App extends Component {
<Route path="/paperlibrary"
render={
(props) => (<Testpaperlibrary {...this.props} {...props} {...this.state} />)
}/>
} />
<Route path="/Integeneration"
render={
(props) => (<Integeneration {...this.props} {...props} {...this.state} />)
}/>
} />
<Route path="/problems"
render={
(props) => (<Developer {...this.props} {...props} {...this.state} />)
}/>
} />
<Route path="/question"
render={
(props) => (<Headplugselection {...this.props} {...props} {...this.state} />)
}/>
{/*<Route path="/wxcode/:identifier?" component={WXCode}*/}
{/* render={*/}
{/* (props)=>(<WXCode {...this.props} {...props} {...this.state}></WXCode>)*/}
{/* }*/}
{/*/>*/}
} />
<Route exact path="/"
// component={ShixunsHome}
render={
(props)=>(<ShixunsHome {...this.props} {...props} {...this.state}></ShixunsHome>)
(props) => (<ShixunsHome {...this.props} {...props} {...this.state}></ShixunsHome>)
}
/>
<Route component={Shixunnopage}/>
<Route component={Shixunnopage} />
</Switch>
</Router>
</MuiThemeProvider>
</ConfigProvider>
</Provider>
);
}
}
@ -972,4 +803,4 @@ moment.defineLocale('zh-cn', {
doy: 4 // The week that contains Jan 4th is the first week of the year.
}
});
export default SnackbarHOC()(App) ;
export default SnackbarHOC()(App);

@ -1,9 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});

@ -1,27 +1,26 @@
import React from "react";
import axios from 'axios';
import md5 from 'md5';
import { requestProxy } from "./indexEduplus2RequestProxy";
import { broadcastChannelOnmessage ,SetAppModel, isDev, queryString } from 'educoder';
import { broadcastChannelOnmessage, isDev, queryString } from './common/educoder';
import { notification } from 'antd';
import cookie from 'react-cookies';
import './index.css';
const $ = window.$;
const opens ="79e33abd4b6588941ab7622aed1e67e8";
const opens = "79e33abd4b6588941ab7622aed1e67e8";
let timestamp;
let checkSubmitFlg = false;
let message501=false;
let message501 = false;
broadcastChannelOnmessage('refreshPage', () => {
window.location.reload()
})
function locationurl(list){
function locationurl(list) {
if (window.location.port === "3007") {
} else {
window.location.href=list
window.location.href = list
}
}
@ -30,7 +29,7 @@ function locationurl(list){
// TODO 开发期多个身份切换
let debugType =""
let debugType = ""
if (isDev) {
const _search = window.location.search;
let parsed = {};
@ -53,30 +52,25 @@ if (isDev) {
function clearAllCookie() {
cookie.remove('_educoder_session', {path: '/'});
cookie.remove('autologin_trustie', {path: '/'});
cookie.remove('_educoder_session', { path: '/' });
cookie.remove('autologin_trustie', { path: '/' });
setpostcookie()
}
clearAllCookie();
function setpostcookie() {
const str =window.location.pathname;
// console.log(str.indexOf("/wxcode"))
let newdomain=".educoder.net"
if(str.indexOf("/wxcode") !== -1){
const str = window.location.pathname;
if (str.indexOf("/wxcode") !== -1) {
console.log("123")
cookie.remove('_educoder_session', {path: '/'});
cookie.remove('autologin_trustie', {path: '/'});
// console.log("开始重写cookis");
cookie.remove('_educoder_session', { path: '/' });
cookie.remove('autologin_trustie', { path: '/' });
const _params = window.location.search;
// console.log("1111");
if (_params) {
// console.log("22222");
let _search = _params.split('?')[1];
let _educoder_sessions= _search.split('&')[0].split('=');
cookie.save('_educoder_session',_educoder_sessions[1], { domain:'.educoder.net', path: '/'});
let autologin_trusties=_search.split('&')[1].split('=');
cookie.save('autologin_trustie',autologin_trusties[1], { domain:'.educoder.net', path: '/'});
let _educoder_sessions = _search.split('&')[0].split('=');
cookie.save('_educoder_session', _educoder_sessions[1], { domain: '.educoder.net', path: '/' });
let autologin_trusties = _search.split('&')[1].split('=');
cookie.save('autologin_trustie', autologin_trusties[1], { domain: '.educoder.net', path: '/' });
}
}
@ -84,31 +78,35 @@ function setpostcookie() {
setpostcookie();
function railsgettimes(proxy) {
function railsgettimes(proxy) {
clearAllCookie()
if(timestamp&&checkSubmitFlg===false){
$.ajax({url:proxy,async:false,success:function(data){
if(data.status===0){
timestamp=data.message;
if (timestamp && checkSubmitFlg === false) {
$.ajax({
url: proxy, async: false, success: function (data) {
if (data.status === 0) {
timestamp = data.message;
setpostcookie();
}
}})
checkSubmitFlg=true
window.setTimeout(()=>{
checkSubmitFlg=false;
}
})
checkSubmitFlg = true
window.setTimeout(() => {
checkSubmitFlg = false;
}, 2000);
}else if(checkSubmitFlg===false){
$.ajax({url:proxy,async:false,success:function(data){
if(data.status===0){
timestamp=data.message;
} else if (checkSubmitFlg === false) {
$.ajax({
url: proxy, async: false, success: function (data) {
if (data.status === 0) {
timestamp = data.message;
setpostcookie();
}
}})
checkSubmitFlg=true
window.setTimeout( ()=>{
checkSubmitFlg=false;
}
})
checkSubmitFlg = true
window.setTimeout(() => {
checkSubmitFlg = false;
}, 2000);
}
@ -131,8 +129,8 @@ export function initAxiosInterceptors(props) {
// proxy = "http://testbdweb.educoder.net"
// proxy = "https://testeduplus2.educoder.net"
//proxy="http://47.96.87.25:48080"
proxy="https://pre-newweb.educoder.net"
proxy="https://test-newweb.educoder.net"
proxy = "https://pre-newweb.educoder.net"
proxy = "https://test-newweb.educoder.net"
// proxy="https://test-jupyterweb.educoder.net"
// proxy="https://test-newweb.educoder.net"
// proxy="https://test-jupyterweb.educoder.net"
@ -143,7 +141,7 @@ export function initAxiosInterceptors(props) {
// 如果需要支持重复的请求考虑config里面自定义一个allowRepeat参考来控制
const requestMap = {};
window.setfalseInRequestMap = function(keyName) {
window.setfalseInRequestMap = function (keyName) {
requestMap[keyName] = false;
}
@ -164,55 +162,6 @@ export function initAxiosInterceptors(props) {
// proxy = 'http://localhost:3000'
// }
// ---------------------------------------------
// console.log("开始请求了");
// console.log(config.url);
// console.log(window.location.pathname);
//
// try {
// const str =window.location.pathname;
// if(str.indexOf("/wxcode") !== -1){
// // console.log("开始重写cookis");
// const _params = window.location.search;
// // console.log("1111");
// if (_params) {
// // console.log("22222");
// let _search = _params.split('?')[1];
// var _educoder_sessionmys="";
// var autologin_trusties="";
// _search.split('&').forEach(item => {
// const _arr = item.split('=');
// if(_arr[0]==='_educoder_session'){
// cookie.save('_educoder_session',_arr[1], { domain: '.educoder.net', path: '/'});
// _educoder_sessionmys=_arr[1];
// }else{
// cookie.save('autologin_trustie',_arr[1], { domain: '.educoder.net', path: '/'});
// autologin_trusties=_arr[1];
// }
// });
// try {
// const autlogins= `_educoder_session=${_educoder_sessionmys}; autologin_trustie=${autologin_trusties} `;
// config.params = {'Cookie': autlogins}
// config.headers['Cookie'] =autlogins;
// // console.log("设置了cookis");
// } catch (e) {
//
// }
// try {
// const autloginysls= `_educoder_session=${_educoder_sessionmys}; autologin_trustie=${autologin_trusties} `;
// config.params = {'autloginysls': autloginysls}
// config.headers['Cookie'] =autloginysls;
// // console.log("设置了cookis");
// }catch (e) {
//
// }
// }
// }
// }catch (e) {
//
// }
if (config.url.indexOf(proxy) != -1 || config.url.indexOf(':') != -1) {
return config
@ -222,19 +171,19 @@ export function initAxiosInterceptors(props) {
let url = `/api${config.url}`;
//qq登录去掉api
if(config.params&&config.params.redirect_uri!=undefined){
if(config.params.redirect_uri.indexOf('otherloginqq')!=-1){
if (config.params && config.params.redirect_uri != undefined) {
if (config.params.redirect_uri.indexOf('otherloginqq') != -1) {
url = `${config.url}`;
}
}
if(`${config[0]}`!=`true`){
let timestamp = Date.parse(new Date())/1000;
if (`${config[0]}` != `true`) {
let timestamp = Date.parse(new Date()) / 1000;
if (window.location.port === "3007") {
// let timestamp=railsgettimes(proxy);
// console.log(timestamp)
// `https://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp`
railsgettimes( `${proxy}/api/main/first_stamp.json`);
let newopens=md5(opens+timestamp)
railsgettimes(`${proxy}/api/main/first_stamp.json`);
let newopens = md5(opens + timestamp)
config.url = `${proxy}${url}`;
if (config.url.indexOf('?') == -1) {
config.url = `${config.url}?debug=${debugType}&randomcode=${timestamp}&client_key=${newopens}`;
@ -245,8 +194,8 @@ export function initAxiosInterceptors(props) {
// 加api前缀
// railsgettimes(`http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp`);
railsgettimes( `/api/main/first_stamp.json`);
let newopens=md5(opens+timestamp)
railsgettimes(`/api/main/first_stamp.json`);
let newopens = md5(opens + timestamp)
config.url = url;
if (config.url.indexOf('?') == -1) {
config.url = `${config.url}?randomcode=${timestamp}&client_key=${newopens}`;
@ -271,7 +220,7 @@ export function initAxiosInterceptors(props) {
if (config.url.indexOf('update_file') === -1) {
requestMap[config.url] = true;
window.setTimeout("setfalseInRequestMap('"+config.url+"')", 900)
window.setTimeout("setfalseInRequestMap('" + config.url + "')", 900)
}
// setTimeout("setfalseInRequestMap(" + config.url + ")", 1200)
return config;
@ -283,7 +232,7 @@ export function initAxiosInterceptors(props) {
axios.interceptors.response.use(function (response) {
// console.log(".............")
if(response===undefined){
if (response === undefined) {
return
}
const config = response.config
@ -296,10 +245,10 @@ export function initAxiosInterceptors(props) {
// message.info(response.data.message || '服务端返回status -1请联系管理员。');
// props.showSnackbar( response.data.message || '服务器异常,请联系管理员。' )
if (window.location.pathname.startsWith('/tasks/')) {
props.showSnackbar( response.data.message || '服务器异常,请联系管理员。' )
props.showSnackbar(response.data.message || '服务器异常,请联系管理员。')
} else {
notification.open({
message:"提示",
message: "提示",
description: response.data.message || '服务器异常,请联系管理员。',
style: {
zIndex: 99999999
@ -328,7 +277,7 @@ export function initAxiosInterceptors(props) {
// if(response.data.status === 401){
// console.log("401401401")
// }
if (response.data.status === 403||response.data.status === "403") {
if (response.data.status === 403 || response.data.status === "403") {
locationurl('/403');
}
@ -342,53 +291,27 @@ export function initAxiosInterceptors(props) {
}
if (response.data.status === 501) {
if(message501===false){
message501=true
if (message501 === false) {
message501 = true
notification.open({
message:"提示",
description:response.data.message || '访问异常,请求不合理',
message: "提示",
description: response.data.message || '访问异常,请求不合理',
style: {
zIndex: 99999999
}
})
}
window.setTimeout(function () {
message501=false
message501 = false
}, 2000);
}
// if (response.data.status === 402) {
// console.log(response.data.status);
// console.log(response.data);
// // locationurl(402);
// }
//
// if (response.data.status === 401) {
// console.log("161");
// console.log(config);
// return config;
// }
// if (response.data.status === 407) {
// 在app js 中解决 Trialapplication
// // </Trialapplication>
// ///在appjs
// notification.open({
// message:"提示",
// description: "账号未认证",
// });
// throw new axios.Cancel('Operation canceled by the user.');
// //
// }
requestMap[response.config.url] = false;
setpostcookie();
return response;
}, function (error) {
return Promise.reject(error);
});
// -----------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------
}

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import React, { Component } from 'react'
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { Link } from "react-router-dom"
class NotFoundPage extends Component {
render() {
@ -8,29 +8,28 @@ class NotFoundPage extends Component {
<div className="App">
404 Page
<br></br>
 
<Link to="/tasks/ixq5euhgrf7y">Index</Link>
| 
|
<Link to="/shixuns/uznmbg54/challenges">tpm challenges</Link>
| 
|
<Link to="/shixuns/uznmbg54/shixun_discuss">tpm discuss</Link>
| 
|
<Link to="/forums/categories/all">forums</Link>
 | 
|
<Link to="/comment">Comment</Link>
 | 
|
<Link to="/testMaterial">testMaterial</Link>
 | 
|
<Link to="/testCodeMirror">testCodeMirror</Link>
 | 
|
<Link to="/taskList">taskList</Link>
 | 
|
<Link to="/testRCComponent">testRCComponent</Link>
| 
|
<Link to="/tpforums">tpforums</Link>
| 
|
<Link to="/testUrlQuery">url-query test</Link>
</div>

File diff suppressed because it is too large Load Diff

@ -1,13 +1,13 @@
import React, { Component } from 'react';
import Snackbar from 'material-ui/Snackbar';
import Fade from 'material-ui/transitions/Fade';
import { notification } from 'antd'
import { notification, Alert } from 'antd'
export function SnackbarHOC(options = {}) {
return function wrap(WrappedComponent) {
return class Wrapper extends Component {
constructor(props) {
super(props);
this.showSnackbar = this.showSnackbar.bind(this)
this.handleSnackbarClose = this.handleSnackbarClose.bind(this)
this.state = {
snackbarText: '',
snackbarOpen: false,
@ -22,24 +22,6 @@ export function SnackbarHOC(options = {}) {
})
}
// 全局的snackbar this.props.showSnackbar调用即可
// showSnackbar(description, message = "提示",icon) {
// // this.setState({
// // snackbarOpen: true,
// // snackbarText: text,
// // snackbarVertical: vertical,
// // snackbarHorizontal: horizontal,
// // })
// const data = {
// message,
// description
// }
// if (icon) {
// data.icon = icon;
// }
// notification.open(data);
// }
showSnackbar(text, vertical, horizontal) {
this.setState({
snackbarOpen: true,
@ -60,27 +42,12 @@ export function SnackbarHOC(options = {}) {
notification.open(data);
}
render() {
const { snackbarOpen, snackbarText, snackbarHorizontal, snackbarVertical } = this.state;
const { snackbarOpen, snackbarText } = this.state
return (
<React.Fragment>
<Snackbar
className={"rootSnackbar"}
style={{zIndex:30000}}
open={this.state.snackbarOpen}
autoHideDuration={3000}
anchorOrigin={{ vertical: this.state.snackbarVertical || 'top'
, horizontal: this.state.snackbarHorizontal || 'center' }}
onClose={() => this.handleSnackbarClose()}
transition={Fade}
SnackbarContentProps={{
'aria-describedby': 'message-id',
}}
resumeHideDuration={2000}
message={<span id="message-id">{this.state.snackbarText}</span>}
/>
<WrappedComponent {...this.props} showSnackbar={ this.showSnackbar } showNotification= { this.showNotification } >
{snackbarOpen ? <Alert messagg={snackbarText} onClose={this.handleSnackbarClose} /> : null}
<WrappedComponent {...this.props} showSnackbar={this.showSnackbar} showNotification={this.showNotification} >
</WrappedComponent>
</React.Fragment>

@ -1,44 +1,14 @@
import { bytesToSize, getUrl, getUrl2 } from 'educoder';
const $ = window.$
import showdown from 'showdown'
export function isImageExtension(fileName) {
return fileName ? !!(fileName.match(/.(jpg|jpeg|png|gif)$/i)) : false
}
export function markdownToHTML(oldContent, selector) {
window.$('#md_div').html('')
// markdown to html
if (selector && oldContent && oldContent.startsWith('<p')) { // 普通html处理
window.$('#' + selector).addClass('renderAsHtml')
window.$('#' + selector).html(oldContent)
} else {
try {
$("#"+selector).html('')
// selector ||
var markdwonParser = window.editormd.markdownToHTML(selector || "md_div", {
markdown: oldContent, // .replace(/▁/g,"▁▁▁"),
emoji: true,
htmlDecode: "style,script,iframe", // you can filter tags decode
taskList: true,
tex: true, // 默认不解析
flowChart: true, // 默认不解析
sequenceDiagram: true // 默认不解析
});
} catch(e) {
console.error(e)
}
// selector = '.' + selector
if (selector) {
return;
}
const content = window.$('#md_div').html()
if (selector) {
window.$(selector).html(content)
}
return content
}
export function markdownToHTML(oldContent) {
var converter = new showdown.Converter()
return converter.makeHtml(oldContent);
}
function _doDownload(options) {
$.fileDownload(getUrl() + "/api" + options.url, {
@ -66,7 +36,7 @@ export function appendFileSizeToUploadFile(item) {
export function appendFileSizeToUploadFileAll(fileList) {
return fileList.map(item => {
if (item.name.indexOf(uploadNameSizeSeperator) == -1) {
return Object.assign({}, item, {name: `${item.name}${uploadNameSizeSeperator}${bytesToSize(item.size)}`})
return Object.assign({}, item, { name: `${item.name}${uploadNameSizeSeperator}${bytesToSize(item.size)}` })
}
return item
})
@ -76,4 +46,4 @@ export const uploadNameSizeSeperator = '  '
export const sortDirections = ["ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend",
"ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend",
"ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend",
"ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", ]
"ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend", "ascend", "descend",]

@ -6,7 +6,7 @@
* @LastEditors : tangjiang
* @LastEditTime : 2020-01-06 18:42:09
*/
import './index.scss';
import './index.less';
import React, { useState } from 'react';
import { Form, Button, Input } from 'antd';
import QuillForEditor from '../../quillForEditor';
@ -14,7 +14,7 @@ import QuillForEditor from '../../quillForEditor';
// import {formatDelta} from './util';
const FormItem = Form.Item;
function CommentForm (props) {
function CommentForm(props) {
const {
onCancel,
@ -57,7 +57,7 @@ function CommentForm (props) {
try {
// const _html = new QuillDeltaToHtmlConverter(content.ops, {}).convert();
// props.form.setFieldsValue({'comment': _html.replace(/<\/?[^>]*>/g, '')});
props.form.setFieldsValue({'comment': content});
props.form.setFieldsValue({ 'comment': content });
} catch (error) {
console.log(error);
}
@ -69,7 +69,7 @@ function CommentForm (props) {
if (!err) {
setShowQuill(false);
const content = ctx;
props.form.setFieldsValue({'comment': ''});
props.form.setFieldsValue({ 'comment': '' });
setCtx('');
// const _html = formatDelta(content.ops);
// console.log('保存的内容=====》》》》', content);
@ -95,7 +95,7 @@ function CommentForm (props) {
{
getFieldDecorator('comment', {
rules: [
{ required: true, message: '评论内容不能为空'}
{ required: true, message: '评论内容不能为空' }
],
})(
<Input
@ -112,7 +112,7 @@ function CommentForm (props) {
}
<QuillForEditor
imgAttrs={{width: '60px', height: '30px'}}
imgAttrs={{ width: '60px', height: '30px' }}
wrapStyle={{
height: showQuill ? 'auto' : '0px',
opacity: showQuill ? 1 : 0,
@ -130,7 +130,7 @@ function CommentForm (props) {
</FormItem>
<FormItem style={{ textAlign: 'right', display: showQuill ? 'block' : 'none' }}>
<Button onClick={handleCancle}>取消</Button>
<Button onClick={handleSubmit} type="primary" style={{ marginLeft: '10px'}}>发送</Button>
<Button onClick={handleSubmit} type="primary" style={{ marginLeft: '10px' }}>发送</Button>
</FormItem>
</Form>
);

@ -6,11 +6,11 @@
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 10:03:21
*/
import './index.scss';
import './index.less';
import React from 'react';
// import { Icon } from 'antd';
// import MyIcon from '../MyIcon';
function CommentIcon ({
function CommentIcon({
type, // 图标类型
count, // 评论数
iconClick,
@ -30,11 +30,11 @@ function CommentIcon ({
<span
style={props.style}
className={`comment_icon_count ${props.className}`}
onClick={ handleSpanClick }
onClick={handleSpanClick}
>
{/* <Icon className="comment_icon" type={type} style={{ color: iconColor }} theme={theme}/> */}
<span className={_classIcon} style={{ color: iconColor }}></span>
<span className={_className}>{ count }</span>
<span className={_className}>{count}</span>
</span>
)
}

@ -6,7 +6,7 @@
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 11:05:17
*/
import './index.scss';
import './index.less';
import 'quill/dist/quill.core.css'; // 核心样式
import 'quill/dist/quill.snow.css'; // 有工具栏
import 'quill/dist/quill.bubble.css'; // 无工具栏
@ -18,7 +18,7 @@ import { Icon } from 'antd';
import CommentForm from './CommentForm';
import QuillForEditor from '../../quillForEditor';
function CommentItem ({
function CommentItem({
isAdmin,
options,
confirm,
@ -57,7 +57,7 @@ function CommentItem ({
confirm({
title: '提示',
content: ('确定要删除该条回复吗?'),
onOk () {
onOk() {
console.log('点击了删除', id);
submitDeleteComment && submitDeleteComment(id);
}
@ -105,7 +105,8 @@ function CommentItem ({
value={_ctx}
showUploadImage={handleShowUploadImage}
/>
)};
)
};
// 加载更多
const handleOnLoadMore = (len) => {
@ -154,7 +155,7 @@ function CommentItem ({
<li className={_moreClass} onClick={() => handleOnLoadMore(len)}>
<p className="loadmore-txt">展开其余{lastTxt}条评论</p>
<p className="loadmore-icon">
<Icon type={!arrow ? 'down' : 'up'}/>
<Icon type={!arrow ? 'down' : 'up'} />
</p>
</li>
</ul>
@ -203,14 +204,14 @@ function CommentItem ({
<div className="comment_icon_area">
<CommentIcon
style={{ display: isAdmin ? 'inline-block' : 'none'}}
style={{ display: isAdmin ? 'inline-block' : 'none' }}
className='comment-icon-margin'
type={!hidden ? "xianshi" : 'yincang1'}
iconClick={() => handleShowOrHide(id, !hidden ? 1 : 0)}
/>
<CommentIcon
style={{ display: can_delete ? 'inline-block' : 'none'}}
style={{ display: can_delete ? 'inline-block' : 'none' }}
className='comment-icon-margin'
type={'shanchu'}
iconClick={() => deleteComment(id)}
@ -224,7 +225,7 @@ function CommentItem ({
/>
{/* 点赞 */}
<CommentIcon
iconColor={ user_praise ? '#5091FF' : '' }
iconColor={user_praise ? '#5091FF' : ''}
className='comment-icon-margin'
theme={user_praise ? 'filled' : ''}
type="dianzan"
@ -234,7 +235,7 @@ function CommentItem ({
</div>
<div
style={{ display: showQuill ? 'block' : 'none'}}
style={{ display: showQuill ? 'block' : 'none' }}
className="comment_item_quill">
<CommentForm
onCancel={handleClickCancel}
@ -243,10 +244,10 @@ function CommentItem ({
</div>
{/* 显示上传的图片信息 */}
<div className="show_upload_image" style={{ display: url ? 'block' : 'none'}}>
<Icon type="close" className="image_close" onClick={handleClose}/>
<div className="show_upload_image" style={{ display: url ? 'block' : 'none' }}>
<Icon type="close" className="image_close" onClick={handleClose} />
<div className="image_info">
<img className="image" src={url} alt=""/>
<img className="image" src={url} alt="" />
</div>
</div>
</div>
@ -254,4 +255,4 @@ function CommentItem ({
);
}
export default CNotificationHOC() (CommentItem);
export default CNotificationHOC()(CommentItem);

@ -6,11 +6,11 @@
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-24 18:08:07
*/
import './index.scss';
import './index.less';
import React from 'react';
import CommentItem from './CommentItem';
import { Empty } from 'antd';
function CommentList (props) {
function CommentList(props) {
const {
isAdmin,
commentLists, // 评论列表
@ -20,7 +20,7 @@ function CommentList (props) {
showOrHideComment
} = props;
const {comments = []} = commentLists;
const { comments = [] } = commentLists;
const renderLi = () => {
if (comments.length > 0) {

@ -1,87 +1,98 @@
$bdColor: rgba(244,244,244,1);
$bgColor: rgba(250,250,250,1);
$lh14: 14px;
$lh22: 22px;
$fz14: 14px;
$fz12: 12px;
$ml: 20px;
.comment_list_wrapper{
@bdColor: rgba(244, 244, 244, 1);
@bgColor: rgba(250, 250, 250, 1);
@lh14: 14px;
@lh22: 22px;
@fz14: 14px;
@fz12: 12px;
@ml: 20px;
.comment_list_wrapper {
box-sizing: border-box;
// border-top: 1px solid $bdColor;
.empty_comment{
// border-top: 1px solid @bdColor;
.empty_comment {
display: flex;
height: calc(100vh - 200px);
width: 100%;
justify-content: center;
align-items: center;
}
.comment_item_show{
.comment_item_show {
display: block;
}
.comment_item_hide{
.comment_item_hide {
display: none;
}
.comment_item_area{
.comment_item_area {
display: flex;
padding: 20px 0;
box-sizing: border-box;
border-bottom: 1px solid $bdColor;
border-bottom: 1px solid @bdColor;
.comment_child_item_area:hover{
.item-close{
.comment_child_item_area:hover {
.item-close {
display: inline-block;
}
}
.flex-image{
.flex-image {
width: 48px;
height: 48px;
border-radius: 50%;
}
.item-desc{
.item-desc {
flex: 1;
// margin-left: $ml;
// margin-left: @ml;
margin-left: 5px;
}
.item-header{
font-size: $fz14;
line-height: $lh14;
.item-header {
font-size: @fz14;
line-height: @lh14;
color: #333;
margin-left: 15px;
.item-time{
font-size: $fz12;
line-height: $lh14;
margin-left: $ml;
.item-time {
font-size: @fz12;
line-height: @lh14;
margin-left: @ml;
}
.item-close{
.item-close {
display: none;
cursor: pointer;
float: right;
}
.item-close.hide{
.item-close.hide {
display: none;
}
}
.item-ctx{
.item-ctx {
position: relative;
line-height: $lh22;
font-size: $fz12;
line-height: @lh22;
font-size: @fz12;
color: #333;
margin-top: 10px;
vertical-align: top;
}
.comment_icon_area{
.comment_icon_area {
display: flex;
justify-content: flex-end;
margin-top: 10px;
.comment-icon-margin{
.comment-icon-margin {
margin-left: 20px;
}
.comment-icon-margin-10{
.comment-icon-margin-10 {
margin-left: 10px;
}
}
@ -89,23 +100,24 @@ $ml: 20px;
// .comment_item_quill{
// // margin-top: 10px;
// }
.show_upload_image{
.show_upload_image {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 1000;
&::before{
&::before {
position: absolute;
height: 100%;
width:100%;
width: 100%;
content: '';
background: #000;
opacity: .7;
}
.image_info{
.image_info {
display: flex;
position: absolute;
width: 80%;
@ -114,14 +126,15 @@ $ml: 20px;
top: 10%;
justify-content: center;
align-items: center;
// background: green;
.image{
.image {
display: block;
width: 100%;
}
}
.image_close{
.image_close {
position: absolute;
right: 20px;
top: 20px;
@ -130,40 +143,47 @@ $ml: 20px;
}
}
}
.comment_icon_count{
.comment_icon_count {
cursor: pointer;
font-size: 12px;
line-height: 1.5;
.comment_icon{
.comment_icon {
color: #333;
}
.comment_count{
.comment_count {
color: #999999;
margin-left: 10px;
transition: color .3s;
}
.comment_count_none{
.comment_count_none {
margin-left: 0;
}
&:hover{
&:hover {
.comment_icon,
.comment_count{
.comment_count {
color: #5091FF;
}
}
}
.comment_item_append_list{
.comment_item_append_list {
display: none;
position: relative;
background-color: $bgColor;
background-color: @bgColor;
border-radius: 5px;
padding: 0 15px 10px;
margin: 15px 0;
&.active{
&.active {
display: block;
}
&::before {
position: absolute;
left: 15px;
@ -173,53 +193,57 @@ $ml: 20px;
content: '';
// border: 5px solid transparent;
border: 10px solid transparent;
border-bottom-color: $bgColor;
border-bottom-color: @bgColor;
}
.comment_item_loadmore{
.comment_item_loadmore {
display: none;
padding-top: 10px;
cursor: pointer;
.loadmore-txt,
.loadmore-icon{
.loadmore-icon {
color: #999;
text-align: center;
font-size: $fz12;
font-size: @fz12;
}
&.show{
&.show {
display: block;
}
}
}
.icon_font_size_14{
.icon_font_size_14 {
font-size: 14px !important;
}
}
.comment_form_area,
.comment_form_bottom_area{
.comment_form_bottom_area {
width: 100%;
}
.comment_form_area{
.comment_form_area {
position: relative;
background: #fff;
// top: 10px;
.ant-form-explain{
.ant-form-explain {
padding-left: 0px;
}
.show_input{
.show_input {
margin-top: 10px;
}
}
.comment_form_bottom_area{
.comment_form_bottom_area {
position: relative;
background: #fff;
top: 10px;
&.active{
&.active {
position: absolute;
background: #fff;
left: 0px;

@ -1,26 +1,28 @@
//import { from } from '_array-flatten@2.1.2@array-flatten';
export {
getImageUrl as getImageUrl, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode
} from './UrlTool';
// export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil';
export { getImageUrl as getImageUrl,getmyUrl as getmyUrl, getRandomNumber as getRandomNumber,getUrl as getUrl, publicSearchs as publicSearchs,getRandomcode as getRandomcode,getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl,getUploadActionUrltwo as getUploadActionUrltwo ,getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST ,htmlEncode as htmlEncode ,getupload_git_file as getupload_git_file} from './UrlTool';
export {setmiyah as setmiyah} from './Component';
export { setmiyah as setmiyah } from './Component';
export { default as queryString } from './UrlTool2';
export { SnackbarHOC as SnackbarHOC } from './SnackbarHOC';
export { trigger as trigger, on as on, off as off
, broadcastChannelPostMessage, broadcastChannelOnmessage } from './EventUtil';
export {
trigger as trigger, on as on, off as off
, broadcastChannelPostMessage, broadcastChannelOnmessage
} from './EventUtil';
export { updatePageParams as updatePageParams } from './RouterUtil';
export { bytesToSize as bytesToSize } from './UnitUtil';
export { markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension,
downloadFile, sortDirections } from './TextUtil'
export { handleDateString, getNextHalfHourOfMoment,formatDuring } from './DateUtil'
export {
markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension,
downloadFile, sortDirections
} from './TextUtil'
export { handleDateString, getNextHalfHourOfMoment, formatDuring } from './DateUtil'
export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil'
@ -30,8 +32,10 @@ export { toStore as toStore, fromStore as fromStore } from './Store'
export { trace_collapse, trace, debug, info, warn, error, trace_c, debug_c, info_c, warn_c, error_c } from './LogUtil'
export { EDU_ADMIN, EDU_BUSINESS, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER
, EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL} from './Const'
export {
EDU_ADMIN, EDU_BUSINESS, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER
, EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL
} from './Const'
export { default as AttachmentList } from './components/attachment/AttachmentList'
@ -73,5 +77,5 @@ export { CNotificationHOC as CNotificationHOC } from '../modules/courses/common/
export { default as ModalWrapper } from '../modules/courses/common/ModalWrapper'
export { default as NoneData } from '../modules/courses/coursesPublic/NoneData'
export {default as WordNumberTextarea} from '../modules/modals/WordNumberTextarea'
export { default as WordNumberTextarea } from '../modules/modals/WordNumberTextarea'

@ -6,7 +6,7 @@
* @LastEditors : tangjiang
* @LastEditTime : 2020-02-05 11:23:03
*/
import './index.scss';
import './index.less';
import 'quill/dist/quill.core.css'; // 核心样式
import 'quill/dist/quill.snow.css'; // 有工具栏
import 'quill/dist/quill.bubble.css'; // 无工具栏
@ -23,7 +23,7 @@ const Size = Quill.import('attributors/style/size');
const Font = Quill.import('formats/font');
// const Color = Quill.import('attributes/style/color');
Size.whitelist = ['12px', '14px', '16px', '18px', '20px', false];
Font.whitelist = ['SimSun', 'SimHei','Microsoft-YaHei','KaiTi','FangSong','Arial','Times-New-Roman','sans-serif'];
Font.whitelist = ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial', 'Times-New-Roman', 'sans-serif'];
window.Quill = Quill;
window.katex = katex;
@ -37,7 +37,7 @@ Quill.register({
// Quill.register(Color);
function QuillForEditor ({
function QuillForEditor({
placeholder,
readOnly,
autoFocus = false,
@ -55,11 +55,11 @@ function QuillForEditor ({
// toolbar 默认值
const defaultConfig = [
'bold', 'italic', 'underline',
{size: ['12px', '14px', '16px', '18px', '20px']},
{align: []}, {list: 'ordered'}, {list: 'bullet'}, // 列表
{script: 'sub'}, {script: 'super'},
{ size: ['12px', '14px', '16px', '18px', '20px'] },
{ align: [] }, { list: 'ordered' }, { list: 'bullet' }, // 列表
{ script: 'sub' }, { script: 'super' },
{ 'color': [] }, { 'background': [] },
{header: [1,2,3,4,5,false]},
{ header: [1, 2, 3, 4, 5, false] },
'blockquote', 'code-block',
'link', 'image', 'video',
'formula',
@ -102,7 +102,7 @@ function QuillForEditor ({
* index: 删除元素的位置
* length: 删除元素的个数
*/
const {index, length} = range;
const { index, length } = range;
const _start = length === 0 ? index - 1 : index;
const _length = length || 1;
let delCtx = this.quill.getText(_start, _length); // 删除的元素
@ -214,7 +214,7 @@ function QuillForEditor ({
const ops = value.ops || [];
ops.forEach((item, i) => {
if (item.insert['image']) {
item.insert['image'] = Object.assign({}, item.insert['image'], {style: { cursor: 'pointer' }, onclick: (url) => showUploadImage(url)});
item.insert['image'] = Object.assign({}, item.insert['image'], { style: { cursor: 'pointer' }, onclick: (url) => showUploadImage(url) });
}
});
}

@ -0,0 +1,26 @@
import React from 'react'
export default class ErrorBoundary extends React.Component {
constructor(props) {
super(props)
this.state = { hasError: false }
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true }
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.log(error, errorInfo)
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>
}
return this.props.children
}
}

@ -0,0 +1,5 @@
import React from 'react'
export default () => {
return <div className="loading">loading ...</div>
}

@ -0,0 +1,21 @@
import React from 'react'
import { createPortal } from 'react-dom'
export default class Dialog extends React.Component {
constructor(props) {
super(props)
const doc = window.document
this.node = doc.createElement('div')
doc.body.appendChild(this.node)
}
render() {
const { children } = this.props
return createPortal(children, this.node)
}
componentWillUnmount() {
window.document.body.removeChild(this.node);
}
}

@ -2,19 +2,17 @@ import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
import Snackbar from 'material-ui/Snackbar';
import Fade from 'material-ui/transitions/Fade';
import Snackbar from '@material-ui/core/Snackbar';
import update from 'immutability-helper'
import Dialog, {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from 'material-ui/Dialog';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import Button from 'material-ui/Button';
import Button from '@material-ui/core/Button';
import EvaluateSuccessEffectDisplay from './EvaluateSuccessEffectDisplay'
@ -31,9 +29,11 @@ import _ from 'lodash'
*/
import TPIContext from './TPIContext'
import { EDU_ADMIN, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER
, EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL, EDU_BUSINESS, CNotificationHOC ,getRandomNumber} from 'educoder'
import { MuiThemeProvider, createMuiTheme, withStyles } from 'material-ui/styles';
import {
EDU_ADMIN, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER
, EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL, EDU_BUSINESS, CNotificationHOC, getRandomNumber
} from 'educoder'
import { MuiThemeProvider, createMuiTheme, withStyles } from '@material-ui/core/styles';
import MUIDialogStyleUtil from '../modules/page/component/MUIDialogStyleUtil'
const styles = MUIDialogStyleUtil.getTwoButtonStyle()
@ -109,7 +109,7 @@ class TPIContextProvider extends Component {
}
onShowUpdateDialog() {
this.setState({showUpdateDialog: true})
this.setState({ showUpdateDialog: true })
}
// updateNowSuccess true 立即更新成功
// TODO updateDialogClose方法名不对 改为updateDialogCallback
@ -145,7 +145,7 @@ class TPIContextProvider extends Component {
window.__fetchAllFlag = false;
this.fetchAll(stageId);
this.costTimeInterval = window.setInterval(()=> {
this.costTimeInterval = window.setInterval(() => {
const { game } = this.state;
if (!game || game.status === 2) { // 已完成的任务不需要计时
return;
@ -153,14 +153,14 @@ class TPIContextProvider extends Component {
if (game.cost_time || game.cost_time === 0) {
// game.cost_time += 1;
this.setState({
game: update(game, {cost_time: { $set: (game.cost_time+1) }})
game: update(game, { cost_time: { $set: (game.cost_time + 1) } })
})
}
}, 1000)
// 页面离开时存下用户的任务耗时
window.$(window).unload( ()=>{
window.$(window).unload(() => {
this._updateCostTime();
});
}
@ -176,7 +176,7 @@ class TPIContextProvider extends Component {
testPath = 'http://test-newweb.educoder.net'
}
// var url = `${testPath}/api/v1/games/${ game.identifier }/cost_time`
var url = `${testPath}/api/tasks/${ game.identifier }/cost_time${getRandomNumber()}`
var url = `${testPath}/api/tasks/${game.identifier}/cost_time${getRandomNumber()}`
window.$.ajax({
type: 'get',
url: url,
@ -194,7 +194,7 @@ class TPIContextProvider extends Component {
// 随便给个分以免重新评测时又出现评星组件注意目前game.star没有显示在界面上如果有则不能这么做
// game.star = 6;
this.setState({
game: update(game, {star: { $set: 6 }}),
game: update(game, { star: { $set: 6 } }),
currentGamePassed: !!passed
})
}
@ -253,7 +253,8 @@ pop_box_new(htmlvalue, 480, 182);
const { praise_count, praise } = response.data;
// challenge.praise_count = praise_tread_count;
// challenge.user_praise = praise;
this.setState({ challenge: update(challenge,
this.setState({
challenge: update(challenge,
{
praise_count: { $set: praise_count },
user_praise: { $set: praise },
@ -272,7 +273,7 @@ pop_box_new(htmlvalue, 480, 182);
// challenge = Object.assign({}, challenge)
// challenge.pathIndex = index;
this.setState({
challenge: update(challenge, {pathIndex: { $set: index }}),
challenge: update(challenge, { pathIndex: { $set: index } }),
}, () => {
callback && callback()
})
@ -290,15 +291,16 @@ pop_box_new(htmlvalue, 480, 182);
challenge.path = path;
const newChallenge = this.handleChallengePath(challenge);
this.setState({ challenge: newChallenge,
myshixun: update(myshixun, {system_tip: { $set: false }}),
this.setState({
challenge: newChallenge,
myshixun: update(myshixun, { system_tip: { $set: false } }),
})
}
handleChallengePath(challenge) {
if (challenge.path && typeof challenge.path === "string") { // 多path的处理
let path = challenge.path.split('');
_.remove(path, (item)=> !item)
_.remove(path, (item) => !item)
if (path.length > 1) {
challenge.path = path;
challenge.multiPath = true;
@ -376,10 +378,10 @@ pop_box_new(htmlvalue, 480, 182);
} else { // 选择题
// 选择题题干markdown初始化
const $ = window.$
window.setTimeout(()=>{
window.setTimeout(() => {
var lens = $("#choiceRepositoryView textarea").length;
for(var i = 1; i <= lens; i++){
for (var i = 1; i <= lens; i++) {
window.editormd.markdownToHTML("choose_subject_" + i, {
htmlDecode: "style,script,iframe", // you can filter tags decode
taskList: true,
@ -502,7 +504,7 @@ pop_box_new(htmlvalue, 480, 182);
fetchAll(stageId, noTimeout) {
if (window.__fetchAllFlag == true ) {
if (window.__fetchAllFlag == true) {
console.log('TPIContextProvider call fetchAll repeatly!')
return;
}
@ -575,7 +577,7 @@ pop_box_new(htmlvalue, 480, 182);
if (resData.final_score) {
var game = this.state.game;
this.setState({
game: update(game, {final_score: { $set: resData.final_score }}),
game: update(game, { final_score: { $set: resData.final_score } }),
grade: resData.grade
})
} else {
@ -589,7 +591,7 @@ pop_box_new(htmlvalue, 480, 182);
this.setState({
game: (this.state.game.status == 2 ? update(this.state.game, {
isPassThrough: { $set: true },
}) : this.state.game) ,
}) : this.state.game),
currentGamePassed: false
})
}
@ -625,7 +627,8 @@ pop_box_new(htmlvalue, 480, 182);
window.clearTimeout(this.showWebDisplayButtonTimeout)
}
this.showWebDisplayButtonTimeout = window.setTimeout(() => {
this.setState({ challenge: update(challenge,
this.setState({
challenge: update(challenge,
{
showWebDisplayButton: { $set: false },
})
@ -657,7 +660,7 @@ pop_box_new(htmlvalue, 480, 182);
language_display(data) {
const { game, tomcat_url } = this.state;
const challenge = Object.assign({}, this.state.challenge)
if(challenge.isWeb && data.port != -1) {
if (challenge.isWeb && data.port != -1) {
// var $result = $("#php_display");
challenge.showWebDisplayButton = true; // ActionView处是否出现查看效果按钮
this.initDisplayInterval()
@ -675,7 +678,7 @@ pop_box_new(htmlvalue, 480, 182);
// });
// challenge.showLanguagePictrue = true;
// }
else if(data.picture != 0){
else if (data.picture != 0) {
// 对应服务端erb文件为 _picture_display.html.erb
// $.ajax({
// url: "/users/picture_show?game_id="+data.picture,
@ -710,7 +713,7 @@ pop_box_new(htmlvalue, 480, 182);
, had_test_count, had_passed_testsests_error_count, had_passed_testsests_hidden_count
, had_passed_testsests_public_count, final_score, gold, experience, latest_output, status
, had_done, score, tag_count, power, record, next_game, grade, picture,
sets_error_count, last_compile_output, record_consume_time} = response;
sets_error_count, last_compile_output, record_consume_time } = response;
const { game } = this.state;
@ -812,7 +815,7 @@ pop_box_new(htmlvalue, 480, 182);
this.setState({
output_sets: output_sets,
grade: this.state.grade + deltaScore,
game : update(game, {test_sets_view: { $set: true }}),
game: update(game, { test_sets_view: { $set: true } }),
testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0)
})
this.handleGdialogClose();
@ -917,14 +920,14 @@ pop_box_new(htmlvalue, 480, 182);
>
<DialogTitle id="alert-dialog-title">{"提示"}</DialogTitle>
<DialogContent id="dialog-content">
<DialogContentText id="alert-dialog-description" style={{textAlign: 'center'}}>
<DialogContentText id="alert-dialog-description" style={{ textAlign: 'center' }}>
{this.state.gDialogContentText}
</DialogContentText>
</DialogContent>
{/* mb20 加了有样式问题 */}
<DialogActions className={""} id="dialog-actions">
{ this.isSingleButton ? <div className="task-popup-submit clearfix"
style={{ textAlign: 'center', 'margin-bottom': '14px'}}>
{this.isSingleButton ? <div className="task-popup-submit clearfix"
style={{ textAlign: 'center', 'margin-bottom': '14px' }}>
<a className="task-btn task-btn-orange"
onClick={this.handleGdialogClose}
>知道啦</a>
@ -935,10 +938,10 @@ pop_box_new(htmlvalue, 480, 182);
关闭
</Button>
<Button variant="raised" className={`${classes.button} ${classes.borderRadiusNone}`}
onClick={() => this.onGdialogOkBtnClick() } color="primary" autoFocus>
{ this.okButtonText ? this.okButtonText : '确定' }
onClick={() => this.onGdialogOkBtnClick()} color="primary" autoFocus>
{this.okButtonText ? this.okButtonText : '确定'}
</Button>
</React.Fragment> }
</React.Fragment>}
{this.moreButtonsRender && this.moreButtonsRender()}
</DialogActions>
</Dialog>
@ -947,10 +950,11 @@ pop_box_new(htmlvalue, 480, 182);
className={"rootSnackbar"}
open={this.state.snackbarOpen}
autoHideDuration={3000}
anchorOrigin={{ vertical: this.state.snackbarVertical || 'top'
, horizontal: this.state.snackbarHorizontal || 'center' }}
anchorOrigin={{
vertical: this.state.snackbarVertical || 'top'
, horizontal: this.state.snackbarHorizontal || 'center'
}}
onClose={() => this.handleSnackbarClose()}
transition={Fade}
SnackbarContentProps={{
'aria-describedby': 'message-id',
}}
@ -963,7 +967,7 @@ pop_box_new(htmlvalue, 480, 182);
}
}
export default CNotificationHOC() (withStyles(styles) (TPIContextProvider));
export default CNotificationHOC()(withStyles(styles)(TPIContextProvider));

@ -0,0 +1,40 @@
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
.page--header {
z-index: 101 !important;
}
.ant-popover-buttons {
text-align: center !important;
}
/* ie11兼容性问题 评测通过图片被遮挡*/
.page--body {
z-index: 1;
}
/* 隐藏newMessage提示按钮 */
#shixun_comment_block .buttons > p:last-child {
display: none !important;
}
.ant-message{
z-index: 20000;
}
/*.ant-modal-header{*/
/*border-radius: 10px;*/
/*}*/
.ant-upload-list-item-info .anticon-loading, .ant-upload-list-item-info .anticon-paper-clip{
color: #29bd8b !important;
}
.anticon anticon-paper-clip{
color: #29bd8b !important;
}
.MuiModal-root-15{
z-index: 1000 !important;
}

@ -7,6 +7,7 @@ body {
.page--header {
z-index: 101 !important;
}
.ant-popover-buttons {
text-align: center !important;
}
@ -17,24 +18,121 @@ body {
z-index: 1;
}
/* 隐藏newMessage提示按钮 */
#shixun_comment_block .buttons > p:last-child {
display: none !important;
#root,
.app {
width: 100%;
height: 100%;
}
p,
h2,
h3,
h4 {
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
/* md
codermirror maybeUpdateLineNumberWidth
*/
.editormd .CodeMirror-linenumbers {
padding: 0;
}
.editormd-html-preview hr,
.editormd-preview-container hr {
/* 颜色加深 */
border-top: 1px solid #ccc;
}
/* 重置掉antd的一些样式 */
html,
body {
-webkit-font-smoothing: auto !important;
}
.ant-progress-textyes {
color: #52c41a;
}
.ant-progress-textno {
color: #f5222d;
}
/* md多空格 */
.markdown-body p {
white-space: pre-wrap;
font-size: 16px !important
}
.markdown-body>p {
line-height: 25px;
}
/* https://www.educoder.net/courses/2346/group_homeworks/34405/question */
.renderAsHtml.markdown-body p {
white-space: inherit;
}
/* resize */
.editormd .CodeMirror {
border-right: none !important;
}
.editormd-preview {
border-left: 1px solid rgb(221, 221, 221);
/* 某些情况下被cm盖住了 */
z-index: 99;
}
/* 图片点击放大的场景,隐藏图片链接 */
.editormd-image-click-expand .editormd-image-dialog {
height: 234px !important;
}
.editormd-image-click-expand .editormd-image-dialog .image-link {
display: none;
}
.ant-message{
z-index: 20000;
/* 解决鼠标框选时,左边第一列没高亮的问题 */
.CodeMirror .CodeMirror-lines pre.CodeMirror-line,
.CodeMirror .CodeMirror-lines pre.CodeMirror-line-like {
padding: 0 12px;
}
/*.ant-modal-header{*/
/*border-radius: 10px;*/
/*}*/
.ant-upload-list-item-info .anticon-loading, .ant-upload-list-item-info .anticon-paper-clip{
color: #29bd8b !important;
/* antd扩展 */
.formItemInline.ant-form-item {
display: flex;
}
.formItemInline .ant-form-item-control-wrapper {
flex: 1;
}
/* AutoComplete placeholder 不显示的问题 */
.ant-select-auto-complete.ant-select .ant-select-selection__placeholder {
z-index: 2;
}
.anticon anticon-paper-clip{
color: #29bd8b !important;
/* 兼容性 */
/* 火狐有滚动条时高度问题 */
@-moz-document url-prefix() {
.newContainers {
min-height: calc(100% - 60px) !important;
}
}
/* material ui 给body加了个6px padding */
body {
padding-right: 0px !important;
}
.MuiModal-root-15{
z-index: 1000 !important;
.indexHOC {
position: relative;
}

@ -1,46 +1,20 @@
import React from 'react';
import ReactDOM from 'react-dom';
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import * as serviceWorker from './serviceWorker'
import './index.css';
import './indexPlus.css';
import App from './App';
import { configureUrlQuery } from 'react-url-query'
// 加之前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';
import history from './history'
// link the history used in our app to url-query so it can update the URL with it.
configureUrlQuery({ history });
// ----------------------------------------------------------------------------------- 请求配置
configureUrlQuery({ history })
window.__useKindEditor = false;
ReactDOM.render(<App />, document.getElementById('root'))
const render = (Component) => {
ReactDOM.render(
<AppContainer {...this.props} {...this.state}>
<Component {...this.props} {...this.state}/>
</AppContainer>,
document.getElementById('root')
);
}
// ReactDOM.render(
// ,
// document.getElementById('root'));
// registerServiceWorker();
render(App);
if (module.hot) {
module.hot.accept('./App', () => { render(App) });
}
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister()

@ -0,0 +1,7 @@
<svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<g fill="#61DAFB">
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<circle cx="420.9" cy="296.5" r="45.7"/>
<path d="M520.5 78.1z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -1,4 +1,4 @@
<svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<g fill="#61DAFB">
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<circle cx="420.9" cy="296.5" r="45.7"/>

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -1,31 +1,30 @@
import React, { Component } from 'react';
import {getImageUrl} from 'educoder';
import { Modal} from 'antd';
import axios from 'axios';
import { getImageUrl } from 'educoder';
import { Modal } from 'antd';
import '../modules/user/account/common.css';
import './gotoqqgroup.css'
class GotoQQgroup extends Component {
constructor(props) {
super(props);
this.state={
this.state = {
}
}
modalCancel=()=>{
modalCancel = () => {
try {
this.props.setgoshowqqgtounp(false);
}catch (e) {
} catch (e) {
}
}
setDownload=()=>{
setDownload = () => {
//立即联系
try {
this.props.setgoshowqqgtounp(false);
}catch (e) {
} catch (e) {
}
}
@ -33,7 +32,7 @@ class GotoQQgroup extends Component {
render() {
return(
return (
<Modal
keyboard={false}
closable={false}
@ -41,16 +40,16 @@ class GotoQQgroup extends Component {
destroyOnClose={true}
title="提示"
centered={true}
visible={this.props.goshowqqgtounp===undefined?false:this.props.goshowqqgtounp}
visible={this.props.goshowqqgtounp === undefined ? false : this.props.goshowqqgtounp}
width="530px"
>
<div className="educouddiv intermediatecenter verticallayout">
<div className="tabeltext-alignleft mt10"><p>您可以在QQ服务群向管理员申请获得继续操作的权限</p></div>
<img width={"200px"} className="mt10" src={getImageUrl("images/educoder/qqqun20191230.png")}/>
<img width={"200px"} className="mt10" src={getImageUrl("images/educoder/qqqun20191230.png")} />
<div className="tabeltext-alignleft mt10"><p>群号612934990</p></div>
<div className="clearfix mt30 edu-txt-center">
<a className="task-btn mr30" onClick={()=>this.modalCancel()}>取消</a>
<a className="task-btn mr30" onClick={() => this.modalCancel()}>取消</a>
<a className="task-btn task-btn-orange" target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=2f2043d88c1bd61d182b98bf1e061c6185e23055bec832c07d8148fe11c5a6cd">立即联系</a>
</div>
</div>

@ -1,37 +1,28 @@
import React, { Component } from 'react';
import Tooltip from 'material-ui/Tooltip';
import Tooltip from '@material-ui/core/Tooltip';
import './Comment.css'
import messageImg from '../../images/tpi/message.svg'
import messagegreyImg from '../../images/tpi/messagegrey.svg'
const $ = window.$;
function pasteListener(event) {
if (event.clipboardData.types[0] === 'Files' ) {
if (event.clipboardData.types[0] === 'Files') {
event.preventDefault();
// event.stopPropagation();
}
}
/*
*/
class CommentInput extends Component {
componentDidMount() {
const { challenge } = this.props;
}
componentWillReceiveProps(newProps, newContext) {
// TODO 暂没有切实训的场景
if (newProps.challenge && newProps.challenge.shixun_id
&& (!this.props.challenge.shixun_id || newProps.challenge.shixun_id != this.props.challenge.shixun_id)) {
setTimeout(()=>{
setTimeout(() => {
window.sd_create_editor_from_shixun_data(newProps.challenge.shixun_id, null, "100%", "Shixun");
if ( $.browser.mozilla ) {
if ($.browser.mozilla) {
setTimeout(() => {
const _body = $('.ke-edit-iframe')[0].contentWindow.document.body;
_body.removeEventListener('paste', pasteListener)
@ -45,54 +36,46 @@ class CommentInput extends Component {
}
render() {
const { createNewComment, editedComment, commentOnChange, challenge, shixun, loading, praisePlus, gotNewReply, showNewReply} = this.props;
/*
onclick="game_praise('<%= @game_challenge.id %>', '<%= @game_challenge.class %>')"
onclick="game_tread('<%= @game_challenge.id %>')"
style={{display: 'none'}}
*/
const { createNewComment, editedComment, commentOnChange, challenge, shixun, loading, praisePlus, gotNewReply, showNewReply } = this.props;
return (
<li className="comment-input fl" id="shixun_comment_block">
{ !challenge.shixun_id ? '' :
<div nhname={`new_message_${challenge.shixun_id}`} className="fr" style={{ width: '99%'}}>
{!challenge.shixun_id ? '' :
<div nhname={`new_message_${challenge.shixun_id}`} className="fr" style={{ width: '99%' }}>
<form acceptCharset="UTF-8" action="/discusses?challenge_id=118&dis_id=61&dis_type=Shixun" className="df" data-remote="true" id="new_comment_form" method="post">
<div className="fl" style={{flex: 1,marginTop:'7px'}} id="editor_panel">
<div className="fl" style={{ flex: 1, marginTop: '7px' }} id="editor_panel">
<div nhname={`toolbar_container_${challenge.shixun_id}`}></div>
{/*有问题或有建议,请直接给我留言吧!*/}
<textarea id={`comment_news_${challenge.shixun_id}`}
nhname={`new_message_textarea_${challenge.shixun_id}`} name="content"
value={ editedComment } onChange={ commentOnChange } className="none">
value={editedComment} onChange={commentOnChange} className="none">
</textarea>
</div>
<div className="tips"
style={{ 'float': 'left', 'marginTop': '6px', 'fontSize': '12px', 'color': '#ff6800'}}>
style={{ 'float': 'left', 'marginTop': '6px', 'fontSize': '12px', 'color': '#ff6800' }}>
请勿粘贴答案否则将造成账号禁用等后果
</div>
<div className="fr buttons" style={{ minWidth:'25px', height: '32px' }}>
<div className="fr buttons" style={{ minWidth: '25px', height: '32px' }}>
<a id={`new_message_submit_btn_${challenge.shixun_id}`} href="javascript:void(0)"
style={{display: 'none'}} onClick={ createNewComment } className="commentsbtn task-btn task-btn-blue fr">
style={{ display: 'none' }} onClick={createNewComment} className="commentsbtn task-btn task-btn-blue fr">
发送
</a>
<p className="fr ml10" style={{minWidth:'25px'}} >
<Tooltip title={ challenge.user_praise ? "取消点赞" : "点赞"}>
<p className="fr ml10" style={{ minWidth: '25px' }} >
<Tooltip title={challenge.user_praise ? "取消点赞" : "点赞"}>
<span id="game_praise_tread" className="color-grey mr20" onClick={praisePlus}>
<i className={`mr3 ${ challenge.user_praise ? "iconfont icon-dianzan color-orange03" : "iconfont icon-dianzan-xian" } `} alt="赞" ></i>
{ challenge.praise_count ?
<i className={`mr3 ${challenge.user_praise ? "iconfont icon-dianzan color-orange03" : "iconfont icon-dianzan-xian"} `} alt="赞" ></i>
{challenge.praise_count ?
<span className="font-16" id="game_praise_count">{challenge.praise_count}</span> : ''}
</span>
</Tooltip>
</p>
<p className="fr ml10" style={{minWidth:'25px'}} >
{ gotNewReply ?
<p className="fr ml10" style={{ minWidth: '25px' }} >
{gotNewReply ?
<React.Fragment>
<i className={`replyIcon newReplyIcon iconfont icon-tpixiaoxitixing`} onClick={showNewReply}></i>
<span className="dot blink"></span>
</React.Fragment>
:
<Tooltip title={ "暂无新消息" }>
<Tooltip title={"暂无新消息"}>
<i className={`replyIcon iconfont icon-tpixiaoxitixing`}></i>
</Tooltip>
}

@ -1,29 +1,23 @@
import React, { Component } from 'react';
import Dialog, {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from 'material-ui/Dialog';
import Button from 'material-ui/Button';
import Tooltip from 'material-ui/Tooltip';
import Pagination from 'rc-pagination';
import 'rc-pagination/assets/index.css';
import { Dialog } from '@material-ui/core';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import Button from '@material-ui/core/Button';
import { getImageUrl, toPath } from 'educoder';
import Tooltip from '@material-ui/core/Tooltip';
import Input, { InputLabel } from 'material-ui/Input';
import { FormControl, FormHelperText } from 'material-ui/Form';
import { getImageUrl } from 'educoder';
import CommentItemKEEditor from './CommentItemKEEditor';
import CommentItemMDEditor from './CommentItemMDEditor';
import './Comment.css'
import Modals from '../modals/Modals'
import { InputNumber } from 'antd'
import { InputNumber, Pagination } from 'antd'
/*
-------------------------- 样式相关
@ -104,10 +98,10 @@ class Comments extends Component {
$(document).off("onReply");
}
componentDidMount() {
setTimeout(()=>{
setTimeout(() => {
const $ = window.$;
// 绑定后会自动off 加timeout试试
$(document).on("onReply", (e, args)=>{
$(document).on("onReply", (e, args) => {
const { commentContent, id, editor } = args;
this.props.replyComment(commentContent, id, editor)
@ -126,15 +120,15 @@ class Comments extends Component {
var id = comment.id
var reply_message_el = `#reply_message_${id}`
var reply_iconup_el = `#reply_iconup_${id}`
if($(reply_message_el).html() == "") {
if ($(reply_message_el).html() == "") {
$(".reply_to_message").html("");
$(reply_message_el).html(`<div className=\"orig_reply_box borderBottomNone reply_to_message\" id=\"reply_to_message_${id}\">\n <div class=\"homepagePostReplyPortrait mr15 imageFuzzy fl\" id=\"reply_image_${id}\"><a href=\"${user.user_url}\" target=\"_blank\" alt=\"用户头像\"><img alt=\"0?1442652658\" height=\"33\" src=\"${_origin}/images/${user.image_url}\" width=\"33\" /><\/a><\/div>\n <div class=\"orig_textarea fl\" style=\"margin-bottom: 0px\">\n <div nhname=\'new_message_${id}\'>\n <form accept-charset=\"UTF-8\" action=\"/discusses?challenge_id=118&amp;dis_id=61&amp;dis_type=Shixun\" data-remote=\"true\" id=\"new_comment_form\" method=\"post\"><div style=\"margin:0;padding:0;display:inline\"><input name=\"utf8\" type=\"hidden\" value=\"&#x2713;\" /><input name=\"authenticity_token\" type=\"hidden\" value=\"HJTbMpfI8LKUpwghfkvgB2SaMmcIVyVdAezyKmzJ7FU=\" /><\/div>\n <input type=\"hidden\" id=\"dis_reply_id\" name=\"reply_id\" value=\"${id}\">\n <div nhname=\'toolbar_container_${id}\'><\/div>\n <textarea placeholder=\"有问题或有建议,请直接给我留言吧!\" id=\"comment_news_${id}\" style=\"display: none\" nhname=\'new_message_textarea_${id}\' name=\"content\"><\/textarea>\n <a id=\"new_message_submit_btn_${id}\" href=\"javascript:void(0)\" onclick=\"this.style.display=\'none\'\" class=\"mt10 task-btn task-btn-orange fr\">${this.props.buttonText || '发送'}<\/a>\n <div class=\"cl\"><\/div>\n <p nhname=\'contentmsg_${id}\'><\/p>\n<\/form> <\/div>\n <div class=\"cl\"><\/div>\n <\/div>\n <div class=\"cl\"><\/div>\n<\/div>\n`); //" ide语法识别
$(reply_iconup_el).show();
$(function(){
window.sd_create_editor_from_data(id ,null,"100%", "Discuss");
$(function () {
window.sd_create_editor_from_data(id, null, "100%", "Discuss");
});
}else {
} else {
if ($(reply_message_el).is(':visible')) {
$(reply_message_el).hide();
} else {
@ -161,7 +155,7 @@ class Comments extends Component {
return ''
}
const { user } = this.props;
let childCommentsElement = comment.children.map((item, index) =>{
let childCommentsElement = comment.children.map((item, index) => {
let _content = this.parseCommentContent(item.content);
return (
@ -175,11 +169,11 @@ class Comments extends Component {
{/* { item.position ? <span className="fl color-light-green font-14 ml15">[第{item.position}关]</span> : ""} */}
{
item.reward ?
<Tooltip title={ `已奖励金币${item.reward}` } disableFocusListener={true}>
<a href="javascript:void(0);" style={{ marginLeft: '20px', cursor: 'default'}}
className={`rewarded color-grey-8 font-12 fl ${ item.admin === true ? '': 'normalUser'}`}
<Tooltip title={`已奖励金币${item.reward}`} disableFocusListener={true}>
<a href="javascript:void(0);" style={{ marginLeft: '20px', cursor: 'default' }}
className={`rewarded color-grey-8 font-12 fl ${item.admin === true ? '' : 'normalUser'}`}
>
<i className="iconfont icon-gift mr5 color-orange fl" style={{display: 'inline'}}></i><span className="fl">{item.reward}</span>
<i className="iconfont icon-gift mr5 color-orange fl" style={{ display: 'inline' }}></i><span className="fl">{item.reward}</span>
</a>
</Tooltip> : ''
}
@ -190,26 +184,26 @@ class Comments extends Component {
</span>
{this.props.showRewardButton != false && comment.admin === true ?
<a href="javascript:void(0);" className="color-grey-8" onClick={() => this.showGoldRewardDialog(comment, item) }>
<Tooltip title={ "给TA奖励金币" } disableFocusListener={true}>
<a href="javascript:void(0);" className="color-grey-8" onClick={() => this.showGoldRewardDialog(comment, item)}>
<Tooltip title={"给TA奖励金币"} disableFocusListener={true}>
<i className="iconfont icon-jiangli fl"></i>
</Tooltip>
</a>
:""}
: ""}
{/*子回复还没hidden字段*/}
{false && comment.admin === true ?
<Tooltip title={ item.hidden ? "取消隐藏" : "隐藏评论" }>
<a href="javascript:void(0);" className="color-grey-8" onClick={() => this.onCommentBtnClick(comment, item, item.hidden ? 'hiddenCancel' : 'hidden') }>
<Tooltip title={item.hidden ? "取消隐藏" : "隐藏评论"}>
<a href="javascript:void(0);" className="color-grey-8" onClick={() => this.onCommentBtnClick(comment, item, item.hidden ? 'hiddenCancel' : 'hidden')}>
<i className={`fa ${item.hidden ? 'fa-eye' : 'fa-eye-slash'} mr5`}></i>
</a>
</Tooltip>
:""}
: ""}
{/* 新版user_id不准获取方式不对 */}
{ comment.admin === true || item.can_delete || item.user_id === user.user_id || item.user_login == user.login ?
<a href="javascript:void(0);" className="color-grey-8" id="delete_reply_118_952" onClick={() => this.onCommentBtnClick(comment, item, 'delete') }>
<Tooltip title={ "删除" } disableFocusListener={true}>
{comment.admin === true || item.can_delete || item.user_id === user.user_id || item.user_login == user.login ?
<a href="javascript:void(0);" className="color-grey-8" id="delete_reply_118_952" onClick={() => this.onCommentBtnClick(comment, item, 'delete')}>
<Tooltip title={"删除"} disableFocusListener={true}>
<i className="iconfont icon-shanchu mr5"></i>
</Tooltip>
</a>
@ -242,7 +236,7 @@ class Comments extends Component {
<div className="comment_content clearfix" id={`reply_content_${item.id}`}>
<div className="color-grey-3" id={`reply_content_${item.id}`}>
<div className={"break_word_comments markdown-body"} dangerouslySetInnerHTML={{__html: _content}}></div>
<div className={"break_word_comments markdown-body"} dangerouslySetInnerHTML={{ __html: _content }}></div>
<div className="cl"></div>
</div>
</div>
@ -291,13 +285,13 @@ class Comments extends Component {
<div className="comment_item_cont df clearfix" key={index}>
<div className="J_Comment_Face fl">
<a href={`${_origin}/users/${item.user_login}`} target="_blank">
<img alt="用户头像" height="50" src={getImageUrl(`images/${item.image_url}`)} width="50"/>
<img alt="用户头像" height="50" src={getImageUrl(`images/${item.image_url}`)} width="50" />
</a>
</div>
<div className="t_content fl">
<div className="J_Comment_Reply">
<div className="comment_orig_content" style={{ margin:"0px" }}>
<div className="comment_orig_content" style={{ margin: "0px" }}>
<div className="J_Comment_Info clearfix mt3">
@ -306,9 +300,9 @@ class Comments extends Component {
{item.username}
</a>
<span className="t_area fl">{item.time}</span>
{ item.position && <span className="fl color-light-green font-14 ml15">[{item.position}]</span> }
{ item.game_url ?
<Tooltip title={ `点击查看TA的代码页面` } disableFocusListener={true}>
{item.position && <span className="fl color-light-green font-14 ml15">[{item.position}]</span>}
{item.game_url ?
<Tooltip title={`点击查看TA的代码页面`} disableFocusListener={true}>
<a href={item.game_url} target="_blank" className="fl font-14 ml15"
style={{ color: "#4CACFF", cursor: "pointer" }}
>查看</a>
@ -316,9 +310,9 @@ class Comments extends Component {
{
item.reward ?
<Tooltip title={ `已奖励金币${item.reward}` } disableFocusListener={true}>
<a href="javascript:void(0);" style={{ marginLeft: '20px', cursor: 'default'}}
className={`rewarded color-grey-8 font-12 fl ${ item.admin === true ? '': 'normalUser'}`}
<Tooltip title={`已奖励金币${item.reward}`} disableFocusListener={true}>
<a href="javascript:void(0);" style={{ marginLeft: '20px', cursor: 'default' }}
className={`rewarded color-grey-8 font-12 fl ${item.admin === true ? '' : 'normalUser'}`}
>
<i className="iconfont icon-gift mr5 color-orange fl"></i><span className="fl">{item.reward}</span>
</a>
@ -346,17 +340,17 @@ class Comments extends Component {
|| !this.props.onlySuperAdminCouldHide && item.admin === false && (item.manager === false || item.manager == undefined))
? <p className="color-orange font-16">违规评论已被屏蔽</p>
: */}
<div className={"break_word_comments markdown-body"} dangerouslySetInnerHTML={{__html: _content}}></div>
<div className={"break_word_comments markdown-body"} dangerouslySetInnerHTML={{ __html: _content }}></div>
{/* } */}
<div className="cl"></div>
</div>
</div>
<div className="childrenCommentsView">
{(item && item.children && item.children.length) ? <div className="trangle"></div>: ''}
{(item && item.children && item.children.length) ? <div className="trangle"></div> : ''}
{this.renderChildenComments(item)}
{ item.isAllChildrenLoaded != true && item.children && this.props.isChildCommentPagination == true && item.child_message_count > 5?
<Tooltip title={ "点击查看更多回复" } disableFocusListener={true}>
<div className="loadMoreChildComments" onClick={() => {this.props.loadMoreChildComments && this.props.loadMoreChildComments(item)}}>
{item.isAllChildrenLoaded != true && item.children && this.props.isChildCommentPagination == true && item.child_message_count > 5 ?
<Tooltip title={"点击查看更多回复"} disableFocusListener={true}>
<div className="loadMoreChildComments" onClick={() => { this.props.loadMoreChildComments && this.props.loadMoreChildComments(item) }}>
<i className="iconfont icon-xiajiantou"></i>
</div>
</Tooltip>
@ -369,36 +363,36 @@ class Comments extends Component {
{/* && !item.reward */}
{this.props.showRewardButton != false && item.admin === true ?
<a href="javascript:void(0);" className="color-grey-8 fl mt2" onClick={() => this.showGoldRewardDialog(item) }>
<Tooltip title={ "给TA奖励金币" } disableFocusListener={true}>
<a href="javascript:void(0);" className="color-grey-8 fl mt2" onClick={() => this.showGoldRewardDialog(item)}>
<Tooltip title={"给TA奖励金币"} disableFocusListener={true}>
<i className="iconfont icon-jiangli mr5 fl"></i>
</Tooltip>
</a>
:""}
: ""}
{ this.props.showHiddenButton == true
{this.props.showHiddenButton == true
&& (this.props.onlySuperAdminCouldHide && item.isSuperAdmin || !this.props.onlySuperAdminCouldHide && item.admin === true) ?
<Tooltip title={ item.hidden ? "取消隐藏" : "隐藏评论" } disableFocusListener={true}>
<a href="javascript:void(0);" className="color-grey-8 fl mt1" onClick={() => this.onCommentBtnClick(item, '', item.hidden ? 'hiddenCancel' : 'hidden') }>
<Tooltip title={item.hidden ? "取消隐藏" : "隐藏评论"} disableFocusListener={true}>
<a href="javascript:void(0);" className="color-grey-8 fl mt1" onClick={() => this.onCommentBtnClick(item, '', item.hidden ? 'hiddenCancel' : 'hidden')}>
<i className={` ${item.hidden ? 'iconfont icon-yincangbiyan' : 'fa fa-eye'} mr5`}></i>
</a>
</Tooltip>
:""}
: ""}
{ item.admin && ( !item.children || item.children.length === 0 )?
<a href="javascript:void(0);" className="color-grey-8" onClick={() => this.onCommentBtnClick(item, '', 'delete') }>
<Tooltip title={ "删除" } disableFocusListener={true}>
{item.admin && (!item.children || item.children.length === 0) ?
<a href="javascript:void(0);" className="color-grey-8" onClick={() => this.onCommentBtnClick(item, '', 'delete')}>
<Tooltip title={"删除"} disableFocusListener={true}>
<i className="iconfont icon-shanchu mr5"></i>
</Tooltip>
</a> : '' }
</a> : ''}
{/* <span className="ml5 mr5 color-grey-8">|</span>*/}
{(this.props.showReply == undefined || this.props.showReply == true) && <a href={`javascript:void(0)`} className="color-grey-8"
onClick={() => this.initReply(item) } >
<Tooltip title={ "回复" }>
onClick={() => this.initReply(item)} >
<Tooltip title={"回复"}>
<i className="iconfont icon-huifu1 mr5"></i>
</Tooltip>
</a>}
@ -406,17 +400,17 @@ class Comments extends Component {
{/* <span className="ml5 mr5 color-grey-8">|</span>*/}
<span className="reply_praise_count_952">
<Tooltip title={ item.user_praise ? "取消点赞" : "点赞" }>
<a href={`javascript:void(0)`} className={`fr mr5 ${item.user_praise ? 'color-orange03' : 'color-grey-8'}`} onClick={()=>commentPraise(item.id)}>
<i className={ item.user_praise ? "iconfont icon-dianzan mr3" : "iconfont icon-dianzan-xian mr3" }></i>
<Tooltip title={item.user_praise ? "取消点赞" : "点赞"}>
<a href={`javascript:void(0)`} className={`fr mr5 ${item.user_praise ? 'color-orange03' : 'color-grey-8'}`} onClick={() => commentPraise(item.id)}>
<i className={item.user_praise ? "iconfont icon-dianzan mr3" : "iconfont icon-dianzan-xian mr3"}></i>
<span className="fr font-14" style={{ marginTop: '1px'}}>{item.praise_count?item.praise_count:''}</span>
<span className="fr font-14" style={{ marginTop: '1px' }}>{item.praise_count ? item.praise_count : ''}</span>
</a>
</Tooltip>
</span>
</p>
{/* __useKindEditor暂时没用到了TODO 可以去掉 */}
{ window.__useKindEditor ? <CommentItemKEEditor showReplyEditorFlag={showReplyEditorFlag}
{window.__useKindEditor ? <CommentItemKEEditor showReplyEditorFlag={showReplyEditorFlag}
currentReplyComment={currentReplyComment}
item={item}
user={user}
@ -454,7 +448,7 @@ class Comments extends Component {
onCommentBtnClick(comment, childComment, dialogType) {
this.comment = comment;
this.childComment = childComment;
this.setState({dialogOpen: true, dialogType: dialogType})
this.setState({ dialogOpen: true, dialogType: dialogType })
}
handleDialogClose() {
this.setState({
@ -467,18 +461,18 @@ class Comments extends Component {
const { dialogType } = this.state;
if (dialogType === 'delete') {
deleteComment(this.comment, this.childComment ? this.childComment.id : '')
} else if (dialogType === 'hidden' || dialogType === 'hiddenCancel' ) {
} else if (dialogType === 'hidden' || dialogType === 'hiddenCancel') {
hiddenComment(this.comment, this.childComment ? this.childComment.id : '')
}
this.setState({dialogOpen: false})
this.setState({ dialogOpen: false })
}
showGoldRewardDialog(comment, childComment) {
if (comment.admin === true) {
this.comment = comment;
this.childComment = childComment;
this.setState({goldRewardDialogOpen: true})
this.setState({ goldRewardDialogOpen: true })
}
}
handleGoldRewardDialogClose() {
@ -490,11 +484,11 @@ class Comments extends Component {
console.log('onGoldRewardDialogOkBtnClick')
const { goldRewardInput } = this.state;
// || goldRewardInput.indexOf('-') !== -1
if (!goldRewardInput || goldRewardInput === '0' ) {
this.setState({ goldRewardInputError: true})
if (!goldRewardInput || goldRewardInput === '0') {
this.setState({ goldRewardInputError: true })
return;
} else {
this.setState({goldRewardDialogOpen: false})
this.setState({ goldRewardDialogOpen: false })
this.props.rewardCode(this.comment, this.childComment, goldRewardInput)
}
}
@ -510,13 +504,13 @@ class Comments extends Component {
const { deleteComment, onPaginationChange, comment_count_without_reply, currentPage, comments, usingAntdModal } = this.props;
const { dialogOpen, goldRewardDialogOpen, dialogType, goldRewardInputError } = this.state;
const goldRewardInputErrorObj = goldRewardInputError ? {'error': 'error'} : {}
const goldRewardInputErrorObj = goldRewardInputError ? { 'error': 'error' } : {}
return (
<div className="fit -scroll" style={{ 'overflow-x': 'hidden'}}>
<div className="fit -scroll" style={{ 'overflow-x': 'hidden' }}>
{ usingAntdModal ? <Modals
{usingAntdModal ? <Modals
modalsType={dialogOpen}
modalsTopval={
dialogType === 'delete' ? '确定要删除该条回复吗?'
@ -535,7 +529,7 @@ class Comments extends Component {
>
<DialogTitle id="alert-dialog-title">{"提示"}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description" style={{textAlign: 'center'}}>
<DialogContentText id="alert-dialog-description" style={{ textAlign: 'center' }}>
{
dialogType === 'delete' ? '确定要删除该条回复吗?'
: dialogType === 'hidden' ? '确定要隐藏该条回复吗?'
@ -548,7 +542,7 @@ class Comments extends Component {
取消
</Button>
<Button variant="raised"
onClick={() => this.onDialogOkBtnClick() } color="primary" autoFocus>
onClick={() => this.onDialogOkBtnClick()} color="primary" autoFocus>
确定
</Button>
</DialogActions>
@ -564,7 +558,7 @@ class Comments extends Component {
<DialogContent>
<InputNumber placeholder="请输入奖励的金币数量" id="goldReward" type="number" value={this.state.goldRewardInput}
onChange={(e) => this.onGoldRewardInputChange(e)} width={228} style={{ width: '228px'}} />
onChange={(e) => this.onGoldRewardInputChange(e)} width={228} style={{ width: '228px' }} />
{/* <FormControl { ...goldRewardInputErrorObj } aria-describedby="name-error-text">
<InputLabel htmlFor="goldReward">请输入奖励的金币数量</InputLabel>
@ -579,7 +573,7 @@ class Comments extends Component {
取消
</Button>
<Button variant="raised"
onClick={() => this.onGoldRewardDialogOkBtnClick() } color="primary" autoFocus>
onClick={() => this.onGoldRewardDialogOkBtnClick()} color="primary" autoFocus>
确定
</Button>
</DialogActions>
@ -592,12 +586,12 @@ class Comments extends Component {
{this.renderComments()}
</div>
{ (comment_count_without_reply > 10 ) ?
{(comment_count_without_reply > 10) ?
<div className="paginationSection">
<Pagination showQuickJumper onChange={onPaginationChange} current={currentPage} total={comment_count_without_reply} />
</div>
: '' }
{ (comment_count_without_reply == 0) ? <div>
: ''}
{(comment_count_without_reply == 0) ? <div>
<div className="edu-tab-con-box clearfix edu-txt-center">
<img className="edu-nodata-img mb20"
@ -605,7 +599,7 @@ class Comments extends Component {
<p className="edu-nodata-p mb20">暂时还没有相关数据哦</p>
</div>
</div>
: '' }
: ''}
</div>
</div>

@ -1,5 +1,4 @@
import React from 'react'
import ReactDOM from 'react-dom'
import axios from 'axios'
import { notification } from 'antd'
import update from 'immutability-helper'
@ -74,7 +73,7 @@ export function commentHOC(WrappedComponent) {
login: "p24891375"
name: "杨俊男"
user_url: "/users/p24891375"
*/
*/
handleComments(comments, responseData) {
comments.forEach(element => {
if (element.children) {
@ -98,7 +97,7 @@ export function commentHOC(WrappedComponent) {
const { challenge, shixun, match } = this.props;
// const url = `/api/v1/shixuns/${shixun.id}/shixun_discusses?page=${page-1}&container_type=Shixun`
const url =
`/discusses.json?page=${page-1}&container_identifier=${shixun && shixun.identifier ?
`/discusses.json?page=${page - 1}&container_identifier=${shixun && shixun.identifier ?
shixun.identifier : match.params.shixunId}&container_type=Shixun`
this.setState({
@ -108,7 +107,7 @@ export function commentHOC(WrappedComponent) {
// test
// if (true) {
if (false) {
var data = {"children_list":[{"id":1165,"content":"\u7535\u8111\u6ca1\u6709pi\u554a","time":"4\u5929\u524d","position":2,"user_id":31542,"reward":null,"image_url":"avatars/User/b","username":"\u8d75\u94f6\u7fd4","user_login":"p81572036","shixun_id":61,"hidden":false,"manager":false,"praise_count":0,"user_praise":false,"admin":false,"children":null},{"id":1142,"content":"\u6700\u540e\u4e00\u9898\u4e09\u5929\u6253\u9c7c\uff0c\u4e24\u5929\u6652\u7f51\uff0c\u4e0d\u5e94\u8be5\u662f1.01*1.01*1.01*0.99*0.99\uff0c\u800c\u4e0d\u662f\u52a0\u5417\uff1f","time":"4\u5929\u524d","position":1,"user_id":33714,"reward":null,"image_url":"avatars/User/b","username":"\u843d\u5c18","user_login":"p52769048","shixun_id":61,"hidden":false,"manager":false,"praise_count":0,"user_praise":false,"admin":false,"children":[{"content":"\u672c\u5173\u5e76\u6ca1\u6709\u5199\u5230\u201c<span style=\"color:#333333;font-family:&quot;background-color:#FFFFFF;\">1.01*1.01*1.01*0.99*0.99</span>\u201d\uff0c\u4e0d\u77e5\u9053\u4f55\u6765\u6b64\u95ee\uff1f","time":"4\u5929\u524d","position":1,"reward":null,"image_url":"avatars/User/1","username":"Coder","user_id":1,"user_login":"innov","can_delete":false,"id":1144}]},{"id":1112,"content":"\u8fd9\u4e2a\u5b9e\u8bad\u5f88\u8d5e\uff01","time":"10\u5929\u524d","position":2,"user_id":12,"reward":null,"image_url":"avatars/User/12","username":"\u9ec4\u4e95\u6cc9","user_login":"Hjqreturn","shixun_id":61,"hidden":false,"manager":false,"praise_count":1,"user_praise":false,"admin":false,"children":null},{"id":1057,"content":"\u4e0d\u9519","time":"20\u5929\u524d","position":2,"user_id":30403,"reward":null,"image_url":"avatars/User/b","username":"Jimmy","user_login":"p69243850","shixun_id":61,"hidden":false,"manager":false,"praise_count":1,"user_praise":false,"admin":false,"children":null},{"id":975,"content":"q","time":"1\u4e2a\u6708\u524d","position":2,"user_id":30403,"reward":null,"image_url":"avatars/User/b","username":"Jimmy","user_login":"p69243850","shixun_id":61,"hidden":false,"manager":false,"praise_count":1,"user_praise":false,"admin":false,"children":[{"content":"\u4e0b\u6b21\u518d\u53d1\u65e0\u610f\u4e49\u7684\u5185\u5bb9\uff0c\u5c06\u88ab\u6263\u91d1\u5e01\u54e6","time":"1\u4e2a\u6708\u524d","position":2,"reward":null,"image_url":"avatars/User/1","username":"Coder","user_id":1,"user_login":"innov","can_delete":false,"id":980}]},{"id":974,"content":"k","time":"1\u4e2a\u6708\u524d","position":2,"user_id":30403,"reward":null,"image_url":"avatars/User/b","username":"Jimmy","user_login":"p69243850","shixun_id":61,"hidden":false,"manager":false,"praise_count":0,"user_praise":false,"admin":false,"children":[{"content":"\u4e0b\u6b21\u518d\u53d1\u65e0\u610f\u4e49\u7684\u5185\u5bb9\uff0c\u5c06\u88ab\u6263\u91d1\u5e01\u54e6","time":"1\u4e2a\u6708\u524d","position":2,"reward":null,"image_url":"avatars/User/1","username":"Coder","user_id":1,"user_login":"innov","can_delete":false,"id":981}]},{"id":859,"content":"\u5f88\u68d2\uff01\uff01\uff01","time":"1\u4e2a\u6708\u524d","position":4,"user_id":1,"reward":null,"image_url":"avatars/User/1","username":"Coder","user_login":"innov","shixun_id":61,"hidden":false,"manager":false,"praise_count":0,"user_praise":false,"admin":false,"children":null},{"id":802,"content":"\u4e0d\u9519\uff01","time":"2\u4e2a\u6708\u524d","position":1,"user_id":30403,"reward":null,"image_url":"avatars/User/b","username":"Jimmy","user_login":"p69243850","shixun_id":61,"hidden":false,"manager":false,"praise_count":1,"user_praise":false,"admin":false,"children":null},{"id":619,"content":"\u770b\u6765\u8001\u5e08\u5bf9\u9f50\u7528\u7684\u90fd\u662f\u7a7a\u683c","time":"5\u4e2a\u6708\u524d","position":3,"user_id":29145,"reward":null,"image_url":"avatars/User/b","username":"yang","user_login":"m02945638","shixun_id":61,"hidden":false,"manager":false,"praise_count":1,"user_praise":false,"admin":false,"children":null},{"id":553,"content":"<p>\r\n\t666\r\n</p>\r\n<p>\r\n\t<br />\r\n</p>","time":"6\u4e2a\u6708\u524d","position":4,"user_id":26838,"reward":null,"image_url":"avatars/User/b","username":"\u5189\u529b","user_login":"m54013296","shixun_id":61,"hidden":false,"manager":false,"praise_count":0,"user_praise":false,"admin":false,"children":null}],"disscuss_count":183}
var data = { "children_list": [{ "id": 1165, "content": "\u7535\u8111\u6ca1\u6709pi\u554a", "time": "4\u5929\u524d", "position": 2, "user_id": 31542, "reward": null, "image_url": "avatars/User/b", "username": "\u8d75\u94f6\u7fd4", "user_login": "p81572036", "shixun_id": 61, "hidden": false, "manager": false, "praise_count": 0, "user_praise": false, "admin": false, "children": null }, { "id": 1142, "content": "\u6700\u540e\u4e00\u9898\u4e09\u5929\u6253\u9c7c\uff0c\u4e24\u5929\u6652\u7f51\uff0c\u4e0d\u5e94\u8be5\u662f1.01*1.01*1.01*0.99*0.99\uff0c\u800c\u4e0d\u662f\u52a0\u5417\uff1f", "time": "4\u5929\u524d", "position": 1, "user_id": 33714, "reward": null, "image_url": "avatars/User/b", "username": "\u843d\u5c18", "user_login": "p52769048", "shixun_id": 61, "hidden": false, "manager": false, "praise_count": 0, "user_praise": false, "admin": false, "children": [{ "content": "\u672c\u5173\u5e76\u6ca1\u6709\u5199\u5230\u201c<span style=\"color:#333333;font-family:&quot;background-color:#FFFFFF;\">1.01*1.01*1.01*0.99*0.99</span>\u201d\uff0c\u4e0d\u77e5\u9053\u4f55\u6765\u6b64\u95ee\uff1f", "time": "4\u5929\u524d", "position": 1, "reward": null, "image_url": "avatars/User/1", "username": "Coder", "user_id": 1, "user_login": "innov", "can_delete": false, "id": 1144 }] }, { "id": 1112, "content": "\u8fd9\u4e2a\u5b9e\u8bad\u5f88\u8d5e\uff01", "time": "10\u5929\u524d", "position": 2, "user_id": 12, "reward": null, "image_url": "avatars/User/12", "username": "\u9ec4\u4e95\u6cc9", "user_login": "Hjqreturn", "shixun_id": 61, "hidden": false, "manager": false, "praise_count": 1, "user_praise": false, "admin": false, "children": null }, { "id": 1057, "content": "\u4e0d\u9519", "time": "20\u5929\u524d", "position": 2, "user_id": 30403, "reward": null, "image_url": "avatars/User/b", "username": "Jimmy", "user_login": "p69243850", "shixun_id": 61, "hidden": false, "manager": false, "praise_count": 1, "user_praise": false, "admin": false, "children": null }, { "id": 975, "content": "q", "time": "1\u4e2a\u6708\u524d", "position": 2, "user_id": 30403, "reward": null, "image_url": "avatars/User/b", "username": "Jimmy", "user_login": "p69243850", "shixun_id": 61, "hidden": false, "manager": false, "praise_count": 1, "user_praise": false, "admin": false, "children": [{ "content": "\u4e0b\u6b21\u518d\u53d1\u65e0\u610f\u4e49\u7684\u5185\u5bb9\uff0c\u5c06\u88ab\u6263\u91d1\u5e01\u54e6", "time": "1\u4e2a\u6708\u524d", "position": 2, "reward": null, "image_url": "avatars/User/1", "username": "Coder", "user_id": 1, "user_login": "innov", "can_delete": false, "id": 980 }] }, { "id": 974, "content": "k", "time": "1\u4e2a\u6708\u524d", "position": 2, "user_id": 30403, "reward": null, "image_url": "avatars/User/b", "username": "Jimmy", "user_login": "p69243850", "shixun_id": 61, "hidden": false, "manager": false, "praise_count": 0, "user_praise": false, "admin": false, "children": [{ "content": "\u4e0b\u6b21\u518d\u53d1\u65e0\u610f\u4e49\u7684\u5185\u5bb9\uff0c\u5c06\u88ab\u6263\u91d1\u5e01\u54e6", "time": "1\u4e2a\u6708\u524d", "position": 2, "reward": null, "image_url": "avatars/User/1", "username": "Coder", "user_id": 1, "user_login": "innov", "can_delete": false, "id": 981 }] }, { "id": 859, "content": "\u5f88\u68d2\uff01\uff01\uff01", "time": "1\u4e2a\u6708\u524d", "position": 4, "user_id": 1, "reward": null, "image_url": "avatars/User/1", "username": "Coder", "user_login": "innov", "shixun_id": 61, "hidden": false, "manager": false, "praise_count": 0, "user_praise": false, "admin": false, "children": null }, { "id": 802, "content": "\u4e0d\u9519\uff01", "time": "2\u4e2a\u6708\u524d", "position": 1, "user_id": 30403, "reward": null, "image_url": "avatars/User/b", "username": "Jimmy", "user_login": "p69243850", "shixun_id": 61, "hidden": false, "manager": false, "praise_count": 1, "user_praise": false, "admin": false, "children": null }, { "id": 619, "content": "\u770b\u6765\u8001\u5e08\u5bf9\u9f50\u7528\u7684\u90fd\u662f\u7a7a\u683c", "time": "5\u4e2a\u6708\u524d", "position": 3, "user_id": 29145, "reward": null, "image_url": "avatars/User/b", "username": "yang", "user_login": "m02945638", "shixun_id": 61, "hidden": false, "manager": false, "praise_count": 1, "user_praise": false, "admin": false, "children": null }, { "id": 553, "content": "<p>\r\n\t666\r\n</p>\r\n<p>\r\n\t<br />\r\n</p>", "time": "6\u4e2a\u6708\u524d", "position": 4, "user_id": 26838, "reward": null, "image_url": "avatars/User/b", "username": "\u5189\u529b", "user_login": "m54013296", "shixun_id": 61, "hidden": false, "manager": false, "praise_count": 0, "user_praise": false, "admin": false, "children": null }], "disscuss_count": 183 }
this.setState({
comments: data.children_list,
@ -135,7 +134,7 @@ export function commentHOC(WrappedComponent) {
currentPage: page,
loadingComments: false,
}, ()=>{
}, () => {
// keditor代码美化
window.prettyPrint()
})
@ -172,10 +171,10 @@ export function commentHOC(WrappedComponent) {
// const url = `/api/v1/discusses`
const url = `/discusses.json`
if(content != undefined){
if (content != undefined) {
var beforeImage = content.split("<img");
var afterImage = content.split("/>");
if(beforeImage[0] == "" && afterImage[1] == ""){
if (beforeImage[0] == "" && afterImage[1] == "") {
window.notice_box('不支持纯图片评论<br/>请在评论中增加文字信息');
return;
}
@ -184,7 +183,7 @@ export function commentHOC(WrappedComponent) {
$("#new_message_submit_btn_" + this.props.challenge.shixun_id).hide();
if (content) { // 去掉尾部的回车换行
content = content.replace(/(\n<p>\n\t<br \/>\n<\/p>)*$/g,'');
content = content.replace(/(\n<p>\n\t<br \/>\n<\/p>)*$/g, '');
}
axios.post(url, {
@ -220,7 +219,7 @@ export function commentHOC(WrappedComponent) {
} else {
comments = arg_comments;
}
for(let i = 0; i < comments.length; i++) {
for (let i = 0; i < comments.length; i++) {
if (id === comments[i].id) {
return i;
}
@ -237,7 +236,7 @@ export function commentHOC(WrappedComponent) {
// const url = `/api/v1/discusses/${id}/reply`
const url = `/discusses/${id}/reply.json`
if (commentContent) {
commentContent = commentContent.replace(/(\n<p>\n\t<br \/>\n<\/p>)*$/g,'');
commentContent = commentContent.replace(/(\n<p>\n\t<br \/>\n<\/p>)*$/g, '');
}
if (!user.login && user.user_url) {
const loginAr = user.user_url.split('/')
@ -259,13 +258,13 @@ export function commentHOC(WrappedComponent) {
var commentIndex = this._findCommentById(id);
let comment = comments[commentIndex]
comment = Object.assign({}, comment)
if (!comment.children ) {
if (!comment.children) {
comment.children = []
} else {
comment.children = comment.children.slice(0);
}
// TODO userName iamge_url
comment.children.push( {
comment.children.push({
"can_delete": true,
"content": commentContent,
@ -298,7 +297,7 @@ export function commentHOC(WrappedComponent) {
this.setState({
// runTesting: false,
comments: comments
}, ()=>{
}, () => {
// keditor代码美化
editor.html && window.prettyPrint()
})
@ -373,7 +372,7 @@ export function commentHOC(WrappedComponent) {
// https://stackoverflow.com/questions/29527385/removing-element-from-array-in-component-state
if (!childCommentId) {
this.setState((prevState) => ({
comments: update(prevState.comments, {$splice: [[commentIndex, 1]]})
comments: update(prevState.comments, { $splice: [[commentIndex, 1]] })
}))
if (this.state.comments.length <= 5) {
@ -383,7 +382,7 @@ export function commentHOC(WrappedComponent) {
let comments = this.state.comments;
let newComments = Object.assign({}, comments)
let childCommentIndex = this._findCommentById(childCommentId, newComments[commentIndex].children);
newComments[commentIndex].children = update(newComments[commentIndex].children, {$splice: [[childCommentIndex, 1]]})
newComments[commentIndex].children = update(newComments[commentIndex].children, { $splice: [[childCommentIndex, 1]] })
this.setState({ newComments })
}
}
@ -551,12 +550,12 @@ export function commentHOC(WrappedComponent) {
componentDidMount() {
// commentsDelegateParent #game_left_contents #tab_con_4
$(".commentsDelegateParent")
.delegate(".J_Comment_Reply .comment_content img, .J_Comment_Reply .childrenCommentsView img","click", (event) => {
.delegate(".J_Comment_Reply .comment_content img, .J_Comment_Reply .childrenCommentsView img", "click", (event) => {
const imageSrc = event.target.src
// 非回复里的头像图片; 非emoticons
if (imageSrc.indexOf('/images/avatars/User') === -1 &&
imageSrc.indexOf('kindeditor/plugins/emoticons') === -1 ) {
imageSrc.indexOf('kindeditor/plugins/emoticons') === -1) {
this.setState({
showImage: true,
imageSrc,
@ -596,7 +595,7 @@ export function commentHOC(WrappedComponent) {
hiddenComment={this.hiddenComment}
rewardCode={this.rewardCode}
onPaginationChange={this.onPaginationChange}
showNotification= { this.showNotification }
showNotification={this.showNotification}
newMessage={this.newMessage}
showNewReply={this.showNewReply}
></WrappedComponent>

@ -1,17 +1,12 @@
import React, { Component } from 'react';
import Dialog, {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from 'material-ui/Dialog';
import Button from 'material-ui/Button';
import { FormControl, FormHelperText } from 'material-ui/Form';
import Input, { InputLabel } from 'material-ui/Input';
import { InputNumber } from 'antd'
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
import Dialog from '@material-ui/core/Dialog';
import Button from '@material-ui/core/Button';
import { InputNumber } from 'antd'
class RewardDialog extends Component {
constructor(props) {
@ -29,7 +24,7 @@ class RewardDialog extends Component {
if (comment.admin === true) {
this.comment = comment;
this.childComment = childComment;
this.setState({goldRewardDialogOpen: true})
this.setState({ goldRewardDialogOpen: true })
}
}
@ -44,7 +39,7 @@ class RewardDialog extends Component {
// this.setState({ goldRewardInputError: true})
return;
} else {
this.props.setRewardDialogVisible( false )
this.props.setRewardDialogVisible(false)
this.props.rewardCode(goldRewardInput)
}
}
@ -54,13 +49,13 @@ class RewardDialog extends Component {
if (Number.isNaN(number)) {
return;
}
this.setState({ goldRewardInput: number , goldRewardInputError: false });
this.setState({ goldRewardInput: number, goldRewardInputError: false });
}
render() {
const { goldRewardDialogOpen } = this.props;
const { goldRewardInputError } = this.state;
const goldRewardInputErrorObj = goldRewardInputError ? {'error': 'error'} : {}
const goldRewardInputErrorObj = goldRewardInputError ? { 'error': 'error' } : {}
return (
<Dialog
@ -77,23 +72,15 @@ class RewardDialog extends Component {
<DialogTitle id="alert-dialog-title">{"奖励设置"}</DialogTitle>
<DialogContent>
{/* <FormControl { ...goldRewardInputErrorObj } aria-describedby="name-error-text"> */}
{/* <InputLabel htmlFor="goldReward"></InputLabel>
<Input id="goldReward" type="number" value={this.state.goldRewardInput} onChange={(e) => this.onGoldRewardInputChange(e)} />
{ goldRewardInputError ? <FormHelperText id="name-error-text">奖励金币不能为空或负数</FormHelperText> : ''} */}
<InputNumber placeholder="请输入奖励的金币数量" id="goldReward" type="number" value={this.state.goldRewardInput}
onChange={(e) => this.onGoldRewardInputChange(e)} width={228} style={{ width: '228px'}} />
{/* </FormControl> */}
{/*<DialogContentText id="alert-dialog-description" style={{textAlign: 'center'}}> </DialogContentText>*/}
onChange={(e) => this.onGoldRewardInputChange(e)} width={228} style={{ width: '228px' }} />
</DialogContent>
<DialogActions>
<Button onClick={this.handleGoldRewardDialogClose} color="primary">
取消
</Button>
<Button variant="raised"
onClick={() => this.onGoldRewardDialogOkBtnClick() } color="primary" autoFocus>
onClick={() => this.onGoldRewardDialogOkBtnClick()} color="primary" autoFocus>
确定
</Button>
</DialogActions>

@ -1,11 +1,4 @@
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'
@ -13,9 +6,6 @@ import moment from 'moment'
import Comments from '../../comment/Comments'
import update from 'immutability-helper'
import RewardDialog from '../../common/RewardDialog';
import {ImageLayerOfCommentHOC} from '../../page/layers/ImageLayerOfCommentHOC'
import MemoDetailMDEditor from '../../forums/MemoDetailMDEditor'
import { RouteHOC } from './common.js'
@ -24,12 +14,14 @@ import '../../forums/RightSection.css'
import './TopicDetail.css'
import '../common/courseMessage.css'
import { Pagination, Tooltip } from 'antd'
import { bytesToSize, ConditionToolTip, markdownToHTML, MarkdownToHtml , setImagesUrl } from 'educoder'
import { MarkdownToHtml, setImagesUrl } from 'educoder'
import SendToCourseModal from '../coursesPublic/modal/SendToCourseModal'
import CBreadcrumb from '../common/CBreadcrumb'
import { generateComments, generateChildComments, _findById, handleContentBeforeCreateNew, addNewComment
, addSecondLevelComment, NEED_TO_WRITE_CONTENT, handleContentBeforeCreateSecondLevelComment
, handleDeleteComment, handleCommentPraise, handleHiddenComment } from '../common/CommentsHelper'
import {
generateComments, generateChildComments, _findById, handleContentBeforeCreateNew, addNewComment
, addSecondLevelComment, handleContentBeforeCreateSecondLevelComment
, handleDeleteComment, handleCommentPraise, handleHiddenComment
} from '../common/CommentsHelper'
const $ = window.$
const REPLY_PAGE_COUNT = 10
@ -57,11 +49,11 @@ class TopicDetail extends Component {
pageCount: 1,
comments: [],
goldRewardDialogOpen: false,
author:undefined
author: undefined
}
}
componentDidMount() {
window.$("html,body").animate({"scrollTop":0})
window.$("html,body").animate({ "scrollTop": 0 })
const topicId = this.props.match.params.topicId
const bid = this.props.match.params.boardId
@ -70,7 +62,7 @@ class TopicDetail extends Component {
this.setState({
memoLoading: true
})
axios.get(memoUrl,{
axios.get(memoUrl, {
})
.then((response) => {
@ -86,8 +78,8 @@ class TopicDetail extends Component {
memo: Object.assign({}, {
...response.data.data,
replies_count: response.data.data.total_replies_count
}, {...this.state.memo}),
author:response.data.data.author
}, { ...this.state.memo }),
author: response.data.data.author
}, () => {
})
@ -126,8 +118,8 @@ class TopicDetail extends Component {
$('body>#root').on('onMemoDelete', (event) => {
// const val = $('body>#root').data('onMemoDelete')
const val = window.onMemoDelete ;
this.onMemoDelete( JSON.parse(decodeURIComponent(val)) )
const val = window.onMemoDelete;
this.onMemoDelete(JSON.parse(decodeURIComponent(val)))
})
@ -145,7 +137,8 @@ class TopicDetail extends Component {
onMemoDelete(memo) {
const deleteUrl = `/commons/delete.json`;
// 获取memo list
axios.delete(deleteUrl, { data: {
axios.delete(deleteUrl, {
data: {
object_id: memo.id,
object_type: 'message'
}
@ -156,7 +149,7 @@ class TopicDetail extends Component {
this.props.showNotification('删除成功');
const props = Object.assign({}, this.props, {})
this.props.toListPage( Object.assign({}, this.props.match.params, {'coursesId': this.state.memo.course_id} ) )
this.props.toListPage(Object.assign({}, this.props.match.params, { 'coursesId': this.state.memo.course_id }))
} else if (status === -1) {
this.props.showNotification('帖子已被删除');
@ -173,7 +166,7 @@ class TopicDetail extends Component {
if (this.state.memo && this.state.memo.content && prevState.memoLoading === true && this.state.memoLoading === false) {
// md渲染content等xhr执行完即memoLoading变化memo.content更新后初始化md
setTimeout(()=>{
setTimeout(() => {
// var shixunDescr = window.editormd.markdownToHTML("memo_content_editorMd", {
// htmlDecode: "style,script,iframe", // you can filter tags decode
// taskList: true,
@ -186,7 +179,7 @@ class TopicDetail extends Component {
}
clickPraise(){
clickPraise() {
const { memo } = this.state;
// const url = `/api/v1/discusses/${memo.id}/plus`;
const url = memo.user_praise ? '/praise_tread/unlike.json' : `/praise_tread/like.json`;
@ -212,7 +205,7 @@ class TopicDetail extends Component {
newMemo.praises_count = newMemo.user_praise ? newMemo.praises_count - 1 : newMemo.praises_count + 1
newMemo.total_praises_count = newMemo.user_praise ? newMemo.total_praises_count - 1 : newMemo.total_praises_count + 1
newMemo.user_praise = !newMemo.user_praise
this.setState({memo : newMemo })
this.setState({ memo: newMemo })
}).catch((error) => {
console.log(error)
})
@ -245,7 +238,7 @@ class TopicDetail extends Component {
</a>
{/* {fileName && <ConditionToolTip title={fileName} condition={fileName.length > 30 }> </ConditionToolTip>} */}
<a href={item.url} title={fileName.length > 30 ? fileName : ''}
className="mr12 color9B9B overflowHidden1" length="58" style={{maxWidth: '480px'}}>
className="mr12 color9B9B overflowHidden1" length="58" style={{ maxWidth: '480px' }}>
{fileName}
</a>
@ -285,7 +278,7 @@ class TopicDetail extends Component {
fetchReplies = () => {
const topicId = this.props.match.params.topicId
const url = `/messages/${topicId}/reply_list.json?page=${this.state.pageCount}&page_size=${REPLY_PAGE_COUNT}`
axios.get(url,{
axios.get(url, {
})
.then((response) => {
const { replies, liked, total_replies_count, total_count } = response.data.data
@ -317,7 +310,7 @@ class TopicDetail extends Component {
// return;
// }
if (this.state.memo.id === id ) { // 回复帖子
if (this.state.memo.id === id) { // 回复帖子
this.createNewComment(commentContent, id, editor);
return;
}
@ -350,7 +343,7 @@ class TopicDetail extends Component {
this.setState({
// runTesting: false,
comments: addSecondLevelComment(comments, parentComment, commentIndex, newId, commentContent, user, editor)
}, ()=>{
}, () => {
// keditor代码美化
editor.html && window.prettyPrint()
})
@ -440,7 +433,7 @@ class TopicDetail extends Component {
*/
loadMoreChildComments = (parent) => {
const url = `/messages/${parent.id}/reply_list.json?page=1&page_size=500`
axios.get(url,{
axios.get(url, {
})
.then((response) => {
const { replies, liked, total_replies_count } = response.data.data
@ -477,7 +470,7 @@ class TopicDetail extends Component {
.then((response) => {
const status = response.data.status
if (status === 0) {
this.props.showNotification( memo.sticky ? '取消置顶成功' : '置顶成功');
this.props.showNotification(memo.sticky ? '取消置顶成功' : '置顶成功');
memo.sticky = memo.sticky ? false : true
this.setState({
memo: Object.assign({}, memo)
@ -515,8 +508,8 @@ class TopicDetail extends Component {
render() {
const { match, history } = this.props
const { recommend_shixun, current_user,author_info } = this.props;
const { memo, comments, hasMoreComments, goldRewardDialogOpen, pageCount, total_count , author } = this.state;
const { recommend_shixun, current_user, author_info } = this.props;
const { memo, comments, hasMoreComments, goldRewardDialogOpen, pageCount, total_count, author } = this.state;
const messageId = match.params.topicId
if (this.state.memoLoading || !current_user) {
return <div className="edu-back-white" id="forum_index_list"></div>
@ -525,11 +518,11 @@ class TopicDetail extends Component {
const isCurrentUserTheAuthor = current_user.login == memo.author.login
const isAdmin = this.props.isAdmin()
// TODO 图片上传地址
const courseId=this.props.match.params.coursesId;
const courseId = this.props.match.params.coursesId;
const boardId = this.props.match.params.boardId;
const isCourseEnd = this.props.isCourseEnd();
document.title=this.props.coursedata&&this.props.coursedata.name;
document.title = this.props.coursedata && this.props.coursedata.name;
return (
<div className="edu-back-white edu-class-container edu-position course-message topicDetail" id="yslforum_index_list"> {/* fl with100 */}
<style>{`
@ -551,9 +544,9 @@ class TopicDetail extends Component {
}
`}</style>
<CBreadcrumb className={'independent'} items={[
{ to: current_user&&current_user.first_category_url, name: this.props.coursedata.name},
{ to: current_user && current_user.first_category_url, name: this.props.coursedata.name },
{ to: `/courses/${courseId}/boards/${boardId}`, name: memo.board_name },
{ name: '帖子详情'}
{ name: '帖子详情' }
]}></CBreadcrumb>
<SendToCourseModal
@ -564,37 +557,37 @@ class TopicDetail extends Component {
></SendToCourseModal>
<div className="clearfix">
<div id="forum_list" className="forum_table mh650">
<div className="padding30 bor-bottom-greyE" style={{paddingBottom: '20px'}}>
<div className="padding30 bor-bottom-greyE" style={{ paddingBottom: '20px' }}>
<div className="font-16 cdefault clearfix pr pr35">
<span className="noteDetailTitle">{memo.subject}</span>
{ !!memo.sticky && <span className="btn-cir btn-cir-red ml10"
style={{position: 'relative', bottom: '4px'}}>置顶</span>}
{ !!memo.reward && <span className="color-orange font-14 ml15"
{!!memo.sticky && <span className="btn-cir btn-cir-red ml10"
style={{ position: 'relative', bottom: '4px' }}>置顶</span>}
{!!memo.reward && <span className="color-orange font-14 ml15"
data-tip-down={`获得平台奖励金币:${memo.reward}`} >
<i className="iconfont icon-gift mr5"></i>{memo.reward}
</span> }
</span>}
{/* || current_user.user_id === author_info.user_id */}
{ current_user && (isAdmin || isCurrentUserTheAuthor) &&
<div className="edu-position-hidebox" style={{position: 'absolute', right: '2px',top:'4px'}}>
{current_user && (isAdmin || isCurrentUserTheAuthor) &&
<div className="edu-position-hidebox" style={{ position: 'absolute', right: '2px', top: '4px' }}>
<a href="javascript:void(0);"><i className="fa fa-bars font-16"></i></a>
<ul className="edu-position-hide undis">
{ ( isCurrentUserTheAuthor || isAdmin ) &&
{(isCurrentUserTheAuthor || isAdmin) &&
<li><a
onClick={() => this.props.toEditPage( Object.assign({}, this.props.match.params, {'coursesId': this.state.memo.course_id}) ) }
onClick={() => this.props.toEditPage(Object.assign({}, this.props.match.params, { 'coursesId': this.state.memo.course_id }))}
>&nbsp;&nbsp;</a></li>}
{ isAdmin &&
( memo.sticky == true ?
{isAdmin &&
(memo.sticky == true ?
<li><a href="javascript:void(0);" onClick={() => this.setTop(memo)}>取消置顶</a></li>
:
<li><a href="javascript:void(0);" onClick={() => this.setTop(memo)}>&nbsp;&nbsp;</a></li> )
<li><a href="javascript:void(0);" onClick={() => this.setTop(memo)}>&nbsp;&nbsp;</a></li>)
}
{ isAdmin &&
{isAdmin &&
<li><a href="javascript:void(0);" onClick={() => this.refs.sendToCourseModal.setVisible(true)}>&nbsp;&nbsp;</a></li>
}
{ ( isCurrentUserTheAuthor || isAdmin ) && <li>
{(isCurrentUserTheAuthor || isAdmin) && <li>
<a href="javascript:void(0)" onClick={() =>
window.delete_confirm_box_2_react(`onMemoDelete`, '您确定要删除吗?' , memo)}>
window.delete_confirm_box_2_react(`onMemoDelete`, '您确定要删除吗?', memo)}>
&nbsp;&nbsp;</a>
</li>
@ -605,31 +598,31 @@ class TopicDetail extends Component {
</div>
<div className="df mt20">
<img src={setImagesUrl(`/images/${author && author.image_url}`)} className="radius mr10 mt2" width="40px" height="40px"/>
<img src={setImagesUrl(`/images/${author && author.image_url}`)} className="radius mr10 mt2" width="40px" height="40px" />
<div className="flex1">
<div className="color-grey-9 lineh-20">
<span class="color-grey-3 mr20 fl" style={{"fontWeight":"400"}}>{author && author.name}</span>
<span class="color-grey-3 mr20 fl" style={{ "fontWeight": "400" }}>{author && author.name}</span>
<span className="fl">{moment(memo.created_on).fromNow()} 发布</span>
</div>
<div className="color-grey-9 clearfix">
<span className="fl" style={{marginTop: '4px'}}>
<span className="fl" style={{ marginTop: '4px' }}>
{/* { current_user.admin && <Tooltip title={ "" }>
<span className="noteDetailNum rightline cdefault" style={{padding: '0 4px', cursor: 'pointer'}}>
<i className="iconfont icon-jiangli mr5" onClick={this.showRewardDialog}></i>
</span>
</Tooltip> } */}
<Tooltip title={"浏览数"}>
<span className={`noteDetailNum `} style={{paddingLeft: '0px'}}>
<span className={`noteDetailNum `} style={{ paddingLeft: '0px' }}>
<i className="iconfont icon-liulanyan mr5"></i>
<span style={{ top: "1px", position: "relative" }}>{memo.visits || '1'}</span>
</span>
</Tooltip>
{ !!memo.total_replies_count &&
{!!memo.total_replies_count &&
<Tooltip title={"回复数"}>
<a href="javascript:void(0)" className="noteDetailNum">
<i className="iconfont icon-huifu1 mr5" onClick={this.showCommentInput}></i>
<span style={{ top: "2px", position: "relative" }}>{ memo.total_replies_count }</span>
<span style={{ top: "2px", position: "relative" }}>{memo.total_replies_count}</span>
</a>
</Tooltip>
}
@ -637,15 +630,15 @@ class TopicDetail extends Component {
<Tooltip title={"点赞数"}>
<span className={`noteDetailNum `} style={{}}>
<i className="iconfont icon-dianzan-xian mr5"></i>
<span style={{ top: "2px", position: "relative" }}>{ memo.total_praises_count }</span>
<span style={{ top: "2px", position: "relative" }}>{memo.total_praises_count}</span>
</span>
</Tooltip>
}
</span>
<div className="fr">
{/* || current_user.user_id === author_info.user_id */}
<a className={`task-hide fr return_btn color-grey-6 ${ current_user && (isAdmin
) ? '': 'no_mr'} `} onClick={() => this.props.toListPage(Object.assign({}, this.props.match.params, {'coursesId': this.state.memo.course_id})) } >
<a className={`task-hide fr return_btn color-grey-6 ${current_user && (isAdmin
) ? '' : 'no_mr'} `} onClick={() => this.props.toListPage(Object.assign({}, this.props.match.params, { 'coursesId': this.state.memo.course_id }))} >
返回
</a>
</div>
@ -655,7 +648,7 @@ class TopicDetail extends Component {
</div>
<div className="padding30 memoContent new_li" style={{ paddingBottom: '10px'}}>
<div className="padding30 memoContent new_li" style={{ paddingBottom: '10px' }}>
{/* <MarkdownToHtml content={memo.content}></MarkdownToHtml> */}
{memo.is_md == true ?
<MarkdownToHtml content={memo.content}></MarkdownToHtml>
@ -663,18 +656,18 @@ class TopicDetail extends Component {
<div dangerouslySetInnerHTML={{ __html: memo.content }}></div>
}
</div>
<div className="padding30 bor-bottom-greyE" style={{paddingTop: '2px'}}>
<div className="padding30 bor-bottom-greyE" style={{ paddingTop: '2px' }}>
<div className="mt10 mb20">
{/* ${memo.user_praise ? '' : ''} */}
<Tooltip title={`${memo.liked ? '取消点赞' : '点赞'}`}>
<p className={`noteDetailPoint ${memo.user_praise ? 'Pointed' : ''}`} onClick={()=>{this.clickPraise()}} >
<i className="iconfont icon-dianzan"></i><br/>
<p className={`noteDetailPoint ${memo.user_praise ? 'Pointed' : ''}`} onClick={() => { this.clickPraise() }} >
<i className="iconfont icon-dianzan"></i><br />
<span>{memo.praises_count}</span>
</p>
</Tooltip>
</div>
{ memo.attachments && !!memo.attachments.length &&
{memo.attachments && !!memo.attachments.length &&
<div>
{this.renderAttachment()}
</div>
@ -721,9 +714,9 @@ class TopicDetail extends Component {
</div>
<div className="memoMore" style={{'margin-top': '20px'}}>
{ total_count > REPLY_PAGE_COUNT &&
<Pagination showQuickJumper onChange={this.onPaginationChange} current={pageCount} total={total_count} pageSize={10}/>
<div className="memoMore" style={{ 'margin-top': '20px' }}>
{total_count > REPLY_PAGE_COUNT &&
<Pagination showQuickJumper onChange={this.onPaginationChange} current={pageCount} total={total_count} pageSize={10} />
}
{!isCourseEnd && <div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>}
</div>
@ -736,4 +729,4 @@ class TopicDetail extends Component {
}
}
export default ImageLayerOfCommentHOC() ( RouteHOC()(TopicDetail) );
export default ImageLayerOfCommentHOC()(RouteHOC()(TopicDetail));

@ -1,30 +1,25 @@
import React,{ Component } from "react";
import { Input, InputNumber, Form, Button, Checkbox, Upload, Icon, message, Modal } from "antd";
import React, { Component } from "react";
import { Modal } from "antd";
import axios from 'axios'
import '../css/busyWork.css'
import '../css/Courses.css'
import { WordsBtn, getUrl, ConditionToolTip, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll
, getUploadActionUrl } from 'educoder'
import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
import { appendFileSizeToUploadFileAll } from 'educoder'
import CBreadcrumb from '../common/CBreadcrumb'
import NewWorkForm from './NewWorkForm'
const confirm = Modal.confirm;
const $ = window.$
const MAX_TITLE_LENGTH = 60;
class NewWork extends Component{
constructor(props){
class NewWork extends Component {
constructor(props) {
super(props);
this.contentMdRef = React.createRef();
this.answerMdRef = React.createRef();
this.state={
this.state = {
category: {},
course_name: ''
}
}
componentDidMount () {
let {typeId, coursesId, pageType, workId}=this.props.match.params;
componentDidMount() {
let { typeId, coursesId, pageType, workId } = this.props.match.params;
const isEdit = pageType === "edit"
this.isEdit = isEdit;
if (isEdit) {
@ -123,7 +118,7 @@ class NewWork extends Component{
}
onAttachmentRemove = (file, stateName) => {
if(!file.percent || file.percent == 100){
if (!file.percent || file.percent == 100) {
this.props.confirm({
content: '是否确认删除?',
@ -141,39 +136,41 @@ class NewWork extends Component{
}
render(){
let {typeId,coursesId,pageType}=this.props.match.params;
render() {
let { typeId, coursesId, pageType } = this.props.match.params;
const isGroup = this.props.isGroup()
const moduleName = !isGroup? "普通作业":"分组作业";
const moduleName = !isGroup ? "普通作业" : "分组作业";
const moduleEngName = this.props.getModuleName()
let{
let {
course_name, category
}=this.state
} = this.state
const { current_user } = this.props
const courseId = this.state.course_id || coursesId ;
const courseId = this.state.course_id || coursesId;
const isEdit = this.isEdit;
const common = {
onCancel:this.onCancel,
onCancel: this.onCancel,
isGroup: this.props.isGroup,
doNew: this.doNew,
doEdit: this.doEdit,
}
document.title=this.state.course_name && this.state.course_name
return(
document.title = this.state.course_name && this.state.course_name
return (
<div className="newMain">
<div className="educontent mt20 mb50">
<CBreadcrumb items={[
{ to: current_user && current_user.first_category_url, name: this.state.course_name},
{ to: `/courses/${courseId}/${moduleEngName}/${category && category.category_id ? category.category_id : ''}`
, name: category && category.category_name },
{ name: `${ this.isEdit ? '编辑' : '新建'}` }
{ to: current_user && current_user.first_category_url, name: this.state.course_name },
{
to: `/courses/${courseId}/${moduleEngName}/${category && category.category_id ? category.category_id : ''}`
, name: category && category.category_name
},
{ name: `${this.isEdit ? '编辑' : '新建'}` }
]}></CBreadcrumb>
<p className="clearfix mt20 mb20">
<span className="fl font-24 color-grey-3">{this.isEdit ?"编辑":"新建"}{ moduleName }</span>
<span className="fl font-24 color-grey-3">{this.isEdit ? "编辑" : "新建"}{moduleName}</span>
<a href="javascript:void(0)" className="color-grey-6 fr font-16 mr2"
onClick={() => this.props.history.goBack()}>
返回
@ -195,7 +192,7 @@ class NewWork extends Component{
{...this.props}
{...this.state}
{...common}
wrappedComponentRef={(ref) => {this.newWorkFormRef = ref}}
wrappedComponentRef={(ref) => { this.newWorkFormRef = ref }}
></NewWorkForm>
</div>
</div>

@ -1,10 +1,9 @@
import React,{ Component } from "react";
import { WordsBtn } from "educoder";
import React, { Component } from "react";
import { Checkbox } from 'antd'
const CheckboxGroup = Checkbox.Group;
class CheckAllGroup extends Component{
constructor(props){
class CheckAllGroup extends Component {
constructor(props) {
super(props);
this.state = {
checkAll: true,
@ -33,11 +32,10 @@ class CheckAllGroup extends Component{
})
this.props.onChange && this.props.onChange(checkedValues, true);
}
console.log(checkedValues, arguments)
}
render() {
let { label, options, checkboxGroupStyle }=this.props;
let { label, options, checkboxGroupStyle } = this.props;
const { checkAll, checkedValues } = this.state;
return (
<li className="clearfix">
@ -50,9 +48,9 @@ class CheckAllGroup extends Component{
<span className="fl mr25">
<a href="javascript:void(0);" id="comment_no_limit" className={`pl10 pr10 ${checkAll ? 'check_on' : ''}`} onClick={this.onCheckAll}>全部</a>
</span>
<div className="fl groupList" style={{maxWidth:"990px"}}>
<div className="fl groupList" style={{ maxWidth: "990px" }}>
{
options.length > 1 && <CheckboxGroup options={options} onChange={this.onChange} value={checkedValues} style={checkboxGroupStyle}/>
options.length > 1 && <CheckboxGroup options={options} onChange={this.onChange} value={checkedValues} style={checkboxGroupStyle} />
}
</div>
</li>

@ -1,118 +1,114 @@
import React, { Component } from 'react';
import {getImageUrl} from 'educoder';
import { getImageUrl } from 'educoder';
import CoursesHomeCard from "./CoursesHomeCard.js"
import axios from 'axios';
import {Input,Tooltip} from 'antd';
import { Input, Pagination } from 'antd';
import LoadingSpin from '../../../common/LoadingSpin';
import UpgradeModals from '../../modals/UpgradeModals';
import './css/CoursesHome.css';
import Pagination from '@icedesign/base/lib/pagination';
import '@icedesign/base/lib/pagination/style.js';
const Search = Input.Search;
class CoursesHome extends Component{
class CoursesHome extends Component {
constructor(props) {
super(props)
this.state = {
limit:16,
page:1,
order:"created_at",
coursesHomelist:undefined,
search:"",
limit: 16,
page: 1,
order: "created_at",
coursesHomelist: undefined,
search: "",
}
}
//切换列表状态
changeStatus=(value)=>{
changeStatus = (value) => {
this.setState({
order:value,
page:1,
coursesHomelist:undefined
order: value,
page: 1,
coursesHomelist: undefined
})
this.searchcourses(16,1,value,"")
this.searchcourses(16, 1, value, "")
}
//搜索输入
inputSearchValue=(e)=>{
inputSearchValue = (e) => {
this.setState({
search:e.target.value,
page:1
search: e.target.value,
page: 1
})
}
//搜索
searchValue=(e)=>{
let { search ,order}=this.state;
searchValue = (e) => {
let { search, order } = this.state;
this.setState({
order:order,
page:1
order: order,
page: 1
})
this.searchcourses(16,1,order,search)
this.searchcourses(16, 1, order, search)
}
componentDidMount(){
document.title="翻转课堂";
const upsystem=`/users/system_update.json`;
axios.get(upsystem).then((response)=>{
let updata=response.data;
componentDidMount() {
document.title = "翻转课堂";
const upsystem = `/users/system_update.json`;
axios.get(upsystem).then((response) => {
let updata = response.data;
this.setState({
updata:updata
updata: updata
})
}).catch((error)=>{
}).catch((error) => {
console.log(error);
})
this.searchcourses(16,1,"all","")
this.searchcourses(16, 1, "all", "")
}
onChange=(pageNumber)=> {
onChange = (pageNumber) => {
this.setState({
page:pageNumber
page: pageNumber
})
let {limit,order,search}=this.state;
let { limit, order, search } = this.state;
this.searchcourses(limit,pageNumber,order,search)
this.searchcourses(limit, pageNumber, order, search)
}
searchcourses=(limit,page,order,search)=>{
let url="/courses.json";
axios.get(url,{
searchcourses = (limit, page, order, search) => {
let url = "/courses.json";
axios.get(url, {
params: {
limit:limit,
page:page,
order:order,
search:search
limit: limit,
page: page,
order: order,
search: search
}
}).then((result)=>{
if(result.data.status===401){
}).then((result) => {
if (result.data.status === 401) {
}else{
} else {
this.setState({
coursesHomelist:result.data
coursesHomelist: result.data
})
}
}).catch((error)=>{
}).catch((error) => {
console.log(error);
})
}
getUser=(url,type)=>{
if(this.props.checkIfLogin()===false){
getUser = (url, type) => {
if (this.props.checkIfLogin() === false) {
this.props.showLoginDialog()
return
}
if(this.props.checkIfProfileCompleted()===false){
if (this.props.checkIfProfileCompleted() === false) {
this.props.showProfileCompleteDialog()
return
}
if(url !== undefined || url!==""){
if (url !== undefined || url !== "") {
this.props.history.push(url);
}
@ -120,11 +116,10 @@ class CoursesHome extends Component{
}
render() {
let { order,search,page,coursesHomelist }=this.state;
//console.log(this.props)
let { order, search, page, coursesHomelist } = this.state;
return (
<div>
{this.state.updata===undefined?"":<UpgradeModals
{this.state.updata === undefined ? "" : <UpgradeModals
{...this.state}
/>}
<div className="newMain clearfix">
@ -134,7 +129,7 @@ class CoursesHome extends Component{
.courses-head{
width: 100%;
height: 300px;
background-image: url(${getImageUrl(this.props.mygetHelmetapi && this.props.mygetHelmetapi.course_banner_url === null ?`images/educoder/courses/courses.jpg`:this.props.mygetHelmetapi&&this.props.mygetHelmetapi.course_banner_url)});
background-image: url(${getImageUrl(this.props.mygetHelmetapi && this.props.mygetHelmetapi.course_banner_url === null ? `images/educoder/courses/courses.jpg` : this.props.mygetHelmetapi && this.props.mygetHelmetapi.course_banner_url)});
background-color: #081C4B;
background-position: center;
background-repeat: no-repeat;
@ -151,42 +146,27 @@ class CoursesHome extends Component{
</div>
<div className="mt20 educontent mb20 clearfix">
{/*<a className={ order == "all" ? "fl mr20 font-16 bestChoose active" : "fl mr20 font-16 bestChoose"}*/}
{/*onClick={ () => this.changeStatus("all")}>全部</a>*/}
{/*<a className={ order == "mine" ? "fl mr20 font-16 bestChoose active" : "fl mr20 font-16 bestChoose"}*/}
{/*onClick={ () => this.changeStatus("mine")}>我的</a>*/}
<a className={ order == "created_at" ? "fl mr20 font-16 bestChoose active" : "fl mr20 font-16 bestChoose"}
onClick={ () => this.changeStatus("created_at")}>最新</a>
<a className={ order == "visits" ? "fl mr20 font-16 bestChoose active" : "fl mr20 font-16 bestChoose"}
onClick={ () => this.changeStatus("visits")}>最热</a>
{this.props.user&&this.props.user.user_identity==="学生"?"":<span className={ "fr font-16 bestChoose color-blue" } onClick={(url)=>this.getUser("/courses/new")}>+新建翻转课堂</span>}
{/*<div className="fr mr5 search-new">*/}
{/*/!* <Search*/}
{/*placeholder="课堂名称/教师姓名/学校名称"*/}
{/*id="subject_search_input"*/}
{/*value={search}*/}
{/*onInput={this.inputSearchValue}*/}
{/*onSearch={this.searchValue}*/}
{/*autoComplete="off"*/}
{/*></Search> *!/*/}
{/*</div>*/}
<a className={order == "created_at" ? "fl mr20 font-16 bestChoose active" : "fl mr20 font-16 bestChoose"}
onClick={() => this.changeStatus("created_at")}>最新</a>
<a className={order == "visits" ? "fl mr20 font-16 bestChoose active" : "fl mr20 font-16 bestChoose"}
onClick={() => this.changeStatus("visits")}>最热</a>
{this.props.user && this.props.user.user_identity === "学生" ? "" : <span className={"fr font-16 bestChoose color-blue"} onClick={(url) => this.getUser("/courses/new")}>+新建翻转课堂</span>}
</div>
{coursesHomelist===undefined?<LoadingSpin/>:<CoursesHomeCard {...this.props} {...this.state}
{coursesHomelist === undefined ? <LoadingSpin /> : <CoursesHomeCard {...this.props} {...this.state}
coursesHomelist={coursesHomelist}></CoursesHomeCard>}
{coursesHomelist===undefined?"":coursesHomelist.courses.length===0?<div className="edu-tab-con-box clearfix edu-txt-center mb50">
<img className="edu-nodata-img mb20" src={getImageUrl("images/educoder/nodata.png")}/>
{coursesHomelist === undefined ? "" : coursesHomelist.courses.length === 0 ? <div className="edu-tab-con-box clearfix edu-txt-center mb50">
<img className="edu-nodata-img mb20" src={getImageUrl("images/educoder/nodata.png")} />
<p className="edu-nodata-p mb20">暂时还没有相关数据哦</p>
</div>:""}
</div> : ""}
{
coursesHomelist===undefined?"":coursesHomelist.courses_count > 16?
coursesHomelist === undefined ? "" : coursesHomelist.courses_count > 16 ?
<div className="educontent mb80 edu-txt-center mt10">
<Pagination current={page} total={ coursesHomelist.courses_count || 1299 } type="mini" pageSize={16} onChange={this.onChange} />
</div>:""
<Pagination current={page} total={coursesHomelist.courses_count || 1299} type="mini" pageSize={16} onChange={this.onChange} />
</div> : ""
}
</div>

@ -1,67 +1,64 @@
import React,{ Component } from "react";
import { Modal,Checkbox,Select,Input,Tooltip,Spin,Icon} from "antd";
import axios from'axios';
// import Loading from '@icedesign/base/lib/loading';
// import '@icedesign/base/lib/loading/style.js';
import React, { Component } from "react";
import { Modal, Checkbox, Select, Input, Tooltip, Spin, Icon } from "antd";
import axios from 'axios';
const Option = Select.Option;
const Search = Input.Search;
class ShixunModal extends Component{
constructor(props){
class ShixunModal extends Component {
constructor(props) {
super(props);
this.state={
Searchvalue:undefined,
type:'all',
category_id:0,
page:1,
shixunmodallist:undefined,
hometypepvisible:false,
newshixunmodallist:undefined,
this.state = {
Searchvalue: undefined,
type: 'all',
category_id: 0,
page: 1,
shixunmodallist: undefined,
hometypepvisible: false,
newshixunmodallist: undefined,
}
}
componentDidMount() {
this.setState({
hometypepvisible:true,
hometypepvisible: true,
})
let coursesId=this.props.match.params.coursesId;
let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json";
let coursesId = this.props.match.params.coursesId;
let url = this.props.shixunsUrl || "/courses/" + coursesId + "/homework_commons/shixuns.json";
axios.get(url).then((result)=>{
if(result.status===200){
if(result.data.message===undefined){
axios.get(url).then((result) => {
if (result.status === 200) {
if (result.data.message === undefined) {
this.setState({
shixunmodallist:result.data,
hometypepvisible:false,
newshixunmodallist:result.data.shixun_list,
shixunmodallist: result.data,
hometypepvisible: false,
newshixunmodallist: result.data.shixun_list,
})
}
}
}).catch((error)=>{
}).catch((error) => {
console.log(error);
})
}
setupdatalist=(search,type,loading,page)=>{
let{newshixunmodallist}=this.state;
let newshixunmodallists=[]
if(page>1){
newshixunmodallists=newshixunmodallist;
setupdatalist = (search, type, loading, page) => {
let { newshixunmodallist } = this.state;
let newshixunmodallists = []
if (page > 1) {
newshixunmodallists = newshixunmodallist;
}
this.setState({
hometypepvisible:loading
hometypepvisible: loading
})
let coursesId=this.props.match.params.coursesId;
let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json";
let coursesId = this.props.match.params.coursesId;
let url = this.props.shixunsUrl || "/courses/" + coursesId + "/homework_commons/shixuns.json";
axios.get(url, {
params: {
search: search,
type:type,
page:page
type: type,
page: page
}
}).then((result)=>{
if(result.status===200){
if(result.data.message===undefined){
}).then((result) => {
if (result.status === 200) {
if (result.data.message === undefined) {
let shixun_list = result.data.shixun_list;
for (var i = 0; i < shixun_list.length; i++) {
newshixunmodallists.push(shixun_list[i])
@ -76,20 +73,20 @@ class ShixunModal extends Component{
}
}
}).catch((error)=>{
}).catch((error) => {
console.log(error);
})
}
//勾选实训
shixunhomeworkedit=(list)=>{
let newpatheditarry=[];
shixunhomeworkedit = (list) => {
let newpatheditarry = [];
if (this.props.singleChoose == true) {
if (list.length > 0) {
newpatheditarry.push(list[list.length - 1])
}
} else {
for(var i=0; i<list.length;i++){
for (var i = 0; i < list.length; i++) {
newpatheditarry.push(list[i])
}
}
@ -100,18 +97,18 @@ class ShixunModal extends Component{
this.props.funpatheditarry(newpatheditarry)
}
contentViewScrolledit=(e)=>{
const {shixunmodallist}=this.state;
contentViewScrolledit = (e) => {
const { shixunmodallist } = this.state;
//滑动到底判断
let newscrollTop=parseInt(e.currentTarget.scrollTop);
let allclientHeight=e.currentTarget.clientHeight+newscrollTop;
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) {
if (e.currentTarget.scrollHeight - allclientHeight === 0 || e.currentTarget.scrollHeight - allclientHeight === 1 || e.currentTarget.scrollHeight - allclientHeight === -1) {
if (shixunmodallist.shixun_list.length === 0) {
return;
} else {
let {Searchvalue, type, page} = this.state;
let { Searchvalue, type, page } = this.state;
let newpage = page + 1
this.setupdatalist(Searchvalue, type, true, newpage)
}
@ -119,51 +116,51 @@ class ShixunModal extends Component{
}
//搜索
SenttotheValue=(e)=>{
SenttotheValue = (e) => {
this.setState({
Searchvalue:e.target.value
Searchvalue: e.target.value
})
}
SenttotheSearch=(value)=>{
let{type}=this.state;
SenttotheSearch = (value) => {
let { type } = this.state;
this.setState({
page:1,
page: 1,
})
this.props.funpatheditarry([])
this.setupdatalist(value,type,true,1)
this.setupdatalist(value, type, true, 1)
}
//tag
changeTag=(types)=>{
let {Searchvalue}=this.state;
changeTag = (types) => {
let { Searchvalue } = this.state;
this.setState({
type:types,
page:1,
newshixunmodallist:undefined
type: types,
page: 1,
newshixunmodallist: undefined
})
this.props.funpatheditarry([])
this.setupdatalist(Searchvalue,types,true,1)
this.setupdatalist(Searchvalue, types, true, 1)
}
hidecouseShixunModal=()=>{
hidecouseShixunModal = () => {
this.props.hidecouseShixunModal()
}
savecouseShixunModal=()=>{
savecouseShixunModal = () => {
this.setState({
hometypepvisible:true
hometypepvisible: true
})
let {coursesId,patheditarry,datas}=this.props;
let { coursesId, patheditarry, datas } = this.props;
if(patheditarry.length===0){
if (patheditarry.length === 0) {
this.setState({
shixunmodelchke:true,
chekicmessage:"请先选择实训",
hometypepvisible:false
shixunmodelchke: true,
chekicmessage: "请先选择实训",
hometypepvisible: false
})
return
@ -172,27 +169,27 @@ class ShixunModal extends Component{
if (this.props.chooseShixun) {
this.props.chooseShixun(patheditarry)
this.setState({
hometypepvisible:false
hometypepvisible: false
})
return;
}
let url="/courses/"+coursesId+"/homework_commons/create_shixun_homework.json";
let url = "/courses/" + coursesId + "/homework_commons/create_shixun_homework.json";
axios.post(url, {
category_id:this.props.category_id===null||this.props.category_id===undefined?undefined:parseInt(this.props.category_id),
shixun_ids:patheditarry,
category_id: this.props.category_id === null || this.props.category_id === undefined ? undefined : parseInt(this.props.category_id),
shixun_ids: patheditarry,
}
).then((response) => {
if(response.data.status===-1){
if (response.data.status === -1) {
// this.props.showNotification(response.data.message)
}else{
} else {
// this.props.courseshomeworkstart(response.data.category_id,response.data.homework_ids)
this.props.homeworkupdatalists(this.props.Coursename,this.props.page,this.props.order);
this.props.homeworkupdatalists(this.props.Coursename, this.props.page, this.props.order);
this.props.hidecouseShixunModal()
}
this.setState({
hometypepvisible:false
hometypepvisible: false
})
// category_id: 3
// homework_ids: (5) [9171, 9172, 9173, 9174, 9175]
@ -201,17 +198,17 @@ class ShixunModal extends Component{
})
}
selectCloseList=(value)=>{
selectCloseList = (value) => {
this.setState({
category_id:value
category_id: value
})
}
render(){
let {Searchvalue,type,hometypepvisible,shixunmodallist,newshixunmodallist,}=this.state;
let {visible,patheditarry}=this.props;
render() {
let { Searchvalue, type, hometypepvisible, shixunmodallist, newshixunmodallist, } = this.state;
let { visible, patheditarry } = this.props;
const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />;
// console.log(patheditarry)
return(
return (
<div>
<Modal
@ -282,24 +279,24 @@ class ShixunModal extends Component{
<div className="clearfix mb10 shixun_work_div newshixun_tab_div cdefault" id="shixun_tab_div">
<li className="fl mr5 mt5">
<a onClick={()=>this.changeTag("all")} className={ type==="all" ? "active edu-filter-cir-grey font-12":"edu-filter-cir-grey font-12"}>全部</a>
<a onClick={() => this.changeTag("all")} className={type === "all" ? "active edu-filter-cir-grey font-12" : "edu-filter-cir-grey font-12"}>全部</a>
</li>
{
shixunmodallist && shixunmodallist.tags.map((item,key)=>{
return(
shixunmodallist && shixunmodallist.tags.map((item, key) => {
return (
<li className="fl mr5 mt5" key={key}>
<a onClick={()=>this.changeTag(item.tag_id)} className={ parseInt(type) === parseInt(item.tag_id) ? "active edu-filter-cir-grey font-12":"edu-filter-cir-grey font-12"}>{item.tag_name}</a>
<a onClick={() => this.changeTag(item.tag_id)} className={parseInt(type) === parseInt(item.tag_id) ? "active edu-filter-cir-grey font-12" : "edu-filter-cir-grey font-12"}>{item.tag_name}</a>
</li>
)
})
}
</div>
<div className="clearfix mb10" id="shixun_search_form_div" style={{height:"30px"}}>
<div className="clearfix mb10" id="shixun_search_form_div" style={{ height: "30px" }}>
<span className="fl color-grey-9 font-16 mt3">
<span></span>
<span className="color-orange-tip">{shixunmodallist === undefined ? "":shixunmodallist.shixuns_count}</span>
<span className="color-orange-tip">{shixunmodallist === undefined ? "" : shixunmodallist.shixuns_count}</span>
<span>个实训</span>
</span>
<div className="fr search-new">
@ -308,7 +305,7 @@ class ShixunModal extends Component{
value={Searchvalue}
onInput={this.SenttotheValue}
onSearch={(value) => this.SenttotheSearch(value)}
style={{width: '115%'}}
style={{ width: '115%' }}
/>
</div>
</div>
@ -360,31 +357,31 @@ class ShixunModal extends Component{
{/*<Loading visible={hometypepvisible} shape="dot-circle" className="newnext-loading" color='#4AC7FF'>*/}
<Checkbox.Group style={{ width: '100%' }} value={patheditarry} onChange={this.shixunhomeworkedit}>
{
newshixunmodallist === undefined ? "":newshixunmodallist.length===0?
newshixunmodallist === undefined ? "" : newshixunmodallist.length === 0 ?
<div className="alltask edu-back-white">
<div className="edu-tab-con-box clearfix edu-txt-center">
<img className="edu-nodata-img mb20" src="/images/educoder/nodata.png" />
<p className="edu-nodata-p mb20">暂时还没有相关数据哦</p></div>
</div>:newshixunmodallist.map((item,key)=>{
return(
</div> : newshixunmodallist.map((item, key) => {
return (
<div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE" key={key}>
<li className="fl with40 edu-txt-left task-hide paddingl5 newtaskhide">
<Checkbox
id={"shixun_input_"+item.shixun_id}
id={"shixun_input_" + item.shixun_id}
value={item.shixun_id}
key={item.shixun_id}
className=" task-hide edu-txt-left newtaskhide"
style={{"width":"280px"}}
style={{ "width": "280px" }}
name="shixun_homework[]"
>
<span style={{"textAlign":"left","color":"#05101A"}} className="task-hide color-grey-name">{item.shixun_name}</span>
<span style={{ "textAlign": "left", "color": "#05101A" }} className="task-hide color-grey-name">{item.shixun_name}</span>
</Checkbox>
</li>
<li className="fl with25 edu-txt-left task-hide paddingl5">{item.school}</li>
<li className="fl with11 paddingl10">{item.myshixuns_count}</li>
<li className="fl with11 color-orange-tip paddingl10 pl12">{item.level}</li>
<Tooltip title="新窗口查看详情">
<li className="fl with11"><a className="color-blue" href={"/shixuns/"+item.identifier+"/challenges"} target="_blank">详情</a></li>
<li className="fl with11"><a className="color-blue" href={"/shixuns/" + item.identifier + "/challenges"} target="_blank">详情</a></li>
</Tooltip>
</div>
)
@ -395,7 +392,7 @@ class ShixunModal extends Component{
</div>
</div>
</Spin>
<span className={this.state.shixunmodelchke===true?"color-red":"none"}>{this.state.chekicmessage}</span>
<span className={this.state.shixunmodelchke === true ? "color-red" : "none"}>{this.state.chekicmessage}</span>
<div className="mt20 marginauto clearfix edu-txt-center">
<a className="pop_close task-btn mr30 margin-tp26" onClick={this.hidecouseShixunModal}>取消</a>
<a className="task-btn task-btn-orange margin-tp26" id="submit_send_shixun" onClick={this.savecouseShixunModal}>确定</a>

@ -1,201 +1,145 @@
import React,{ Component } from "react";
import {InputNumber,Table} from "antd";
import TPMMDEditor from '../../../../modules/tpm/challengesnew/TPMMDEditor'
import {Link} from 'react-router-dom';
import {UnControlled as CodeMirror} from 'react-codemirror2';
import React, { Component } from "react";
import { InputNumber, Table } from "antd";
import { Link } from 'react-router-dom';
import { UnControlled as CodeMirror } from 'react-codemirror2';
import axios from 'axios'
import update from 'immutability-helper'
import {markdownToHTML} from 'educoder'
import { markdownToHTML } from 'educoder'
import ShixunAnswerDetail from './shixunAnswerDetail'
const $ = window.$;
class shixunAnswer extends Component{
constructor(props){
class shixunAnswer extends Component {
constructor(props) {
super(props);
this.state={
scoreList:[],
data:[],
challenge:[],
dataCopy:[]
this.state = {
scoreList: [],
data: [],
challenge: [],
dataCopy: []
}
}
componentDidUpdate =(prevState)=>{
if(this.props.questionType && !prevState.questionType && prevState.questionType !=this.props.questionType ){
componentDidUpdate = (prevState) => {
if (this.props.questionType && !prevState.questionType && prevState.questionType != this.props.questionType) {
this.showInfo();
}
}
componentDidMount =()=>{
componentDidMount = () => {
this.showInfo();
}
showInfo=()=>{
let data =[];
// let details=[{
// "shixun_challenge_id": 16,
// "stage_list": {
// "position": 1,
// "name": "链表节点的初始化",
// "evaluate_count": 0,
// "finished_time": 0,
// "time_consuming": 0,
// "myself_experience": 0,
// "experience": 0,
// "user_score": 0,
// "game_score": 15
// },
// "shixun_detail": [{
// "position": 1,
// "game_identifier": "kpb4fygmeo8h",
// "path": "src/step1/charIO.cpp",
// "st": 0,
// "name": "重要的事情说三遍",
// "outputs": [
// {
// "position": 1,
// "output_detail": "compile successfully"
// }
// ],
// "passed_code": "// 包含标准输入输出函数库\n#include <stdio.h>\n\n// 定义main函数\nint main()\n{\n // 请在此添加‘重要的事情说三遍’的代码\n /********** Begin *********/\n char x = getchar();\n putchar(x);\n putchar(x);\n putchar(x);\n putchar('!');\n\n /********** End **********/\n return 0;\n}\n"
// }]
// },{
// "shixun_challenge_id": 16,
// "stage_list": {
// "position": 1,
// "name": "重要的事情说三遍",
// "evaluate_count": 1,
// "finished_time": "2017-10-25 08:54",
// "time_consuming": "29天 18小时 15分钟 50秒",
// "myself_experience": 100,
// "experience": 100,
// "user_score": 5,
// "game_score": 5
// },
// "shixun_detail": [{
// "position": 2,
// "game_identifier": "kpb4fygmeo8h",
// "path": "src/step1/charIO.cpp",
// "st": 0,
// "name": "重要的事情说三遍",
// "outputs": [
// {
// "position": 1,
// "output_detail": "compile successfully"
// }
// ],
// "passed_code": "// 包含标准输入输出函数库\n#include <stdio.h>\n\n// 定义main函数\nint main()\n{\n // 请在此添加‘重要的事情说三遍’的代码\n /********** Begin *********/\n char x = getchar();\n putchar(x);\n putchar(x);\n putchar(x);\n putchar('!');\n\n /********** End **********/\n return 0;\n}\n"
// }]
// }];
let challenge=[];
showInfo = () => {
let data = [];
let challenge = [];
let details = this.props.questionType.shixun_details;
if(details){
for(var i=0;i<details.length;i++){
for(var j=0;j<details[i].stage_list.length;j++){
if (details) {
for (var i = 0; i < details.length; i++) {
for (var j = 0; j < details[i].stage_list.length; j++) {
data.push({
part:details[i].stage_list[j].position,
shixunName:details[i].stage_list[j].name,
testCount:details[i].stage_list[j].evaluate_count,
endTime:details[i].stage_list[j].finished_time,
needTime:details[i].stage_list[j].time_consuming,
my_exp:details[i].stage_list[j].myself_experience,
total_exp:details[i].stage_list[j].experience,
my_score:details[i].stage_list[j].user_score,
total_score:details[i].stage_list[j].game_score,
input_score:details[i].stage_list[j].user_score,
operation:details[i].shixun_detail && details[i].shixun_detail[0].game_identifier,
id:details[i].shixun_challenge_id
part: details[i].stage_list[j].position,
shixunName: details[i].stage_list[j].name,
testCount: details[i].stage_list[j].evaluate_count,
endTime: details[i].stage_list[j].finished_time,
needTime: details[i].stage_list[j].time_consuming,
my_exp: details[i].stage_list[j].myself_experience,
total_exp: details[i].stage_list[j].experience,
my_score: details[i].stage_list[j].user_score,
total_score: details[i].stage_list[j].game_score,
input_score: details[i].stage_list[j].user_score,
operation: details[i].shixun_detail && details[i].shixun_detail[0].game_identifier,
id: details[i].shixun_challenge_id
})
}
if(details[i].shixun_detail){
if (details[i].shixun_detail) {
challenge.push(details[i].shixun_detail);
}
}
}
this.setState({
data:data,
dataCopy:data,
challenge:challenge
data: data,
dataCopy: data,
challenge: challenge
})
// console.log(challenge);
}
changeThis=(value,index)=>{
changeThis = (value, index) => {
this.setState(
(prevState) => ({
data : update(prevState.data, {[index]: { input_score: {$set: value} }})
data: update(prevState.data, { [index]: { input_score: { $set: value } } })
})
)
}
changeThisScore=(e,c_id,key)=>{
let url=`/exercise_questions/${this.props.questionType.question_id}/adjust_score.json`
changeThisScore = (e, c_id, key) => {
let url = `/exercise_questions/${this.props.questionType.question_id}/adjust_score.json`
const list = Object.assign({}, this.state.dataCopy[key])
// console.log("111111111111111111111111");
// console.log(this.props);
// 调分值为0且和第一次的数据相同则不修改
if(parseInt(e.target.value)==parseInt(list.my_score)){
if (parseInt(e.target.value) == parseInt(list.my_score)) {
return;
}
axios.post((url),{
score:e.target.value,
user_id:this.props.id,
shixun_challenge_id:c_id
}).then((result)=>{
if(result){
axios.post((url), {
score: e.target.value,
user_id: this.props.id,
shixun_challenge_id: c_id
}).then((result) => {
if (result) {
this.props.showNotification('调分成功');
this.setState(
(prevState) => ({
data : update(prevState.data, {[key]: { my_score: {$set: e.target.value} }}),
dataCopy : update(prevState.dataCopy, {[key]: { my_score: {$set: e.target.value} }})
data: update(prevState.data, { [key]: { my_score: { $set: e.target.value } } }),
dataCopy: update(prevState.dataCopy, { [key]: { my_score: { $set: e.target.value } } })
})
)
console.log(this.state.dataCopy)
}
}).catch((error)=>{
}).catch((error) => {
console.log(error);
})
}
scrollToAnchor=(index)=>{
let name="challenge_"+index;
scrollToAnchor = (index) => {
let name = "challenge_" + index;
if (index) {
// let anchorElement = document.getElementById(name);
// if(anchorElement) { anchorElement.scrollIntoView(); }
$("html").animate({ scrollTop: $("#challenge_"+index).offset().top - 150 })
$("html").animate({ scrollTop: $("#challenge_" + index).offset().top - 150 })
}
}
render(){
render() {
let {
questionType ,
questionType,
exercise,
user_exercise_status,
}=this.props
} = this.props
let {
data,
challenge,
scoreList,
}=this.state
let isAdmin= this.props.isAdmin();
} = this.state
let isAdmin = this.props.isAdmin();
let isStudent = this.props.isStudent();
// 表格
let columns = [{
title: '关卡',
dataIndex: 'part',
key: 'part',
className:"edu-txt-center"
className: "edu-txt-center"
}, {
title: '任务名称',
dataIndex: 'shixunName',
key: 'shixunName',
className:"edu-txt-left with22 ",
render:(shixunName,item,index)=>{
return(
<span className="overflowHidden1" style={{maxWidth: '400px'}}
className: "edu-txt-left with22 ",
render: (shixunName, item, index) => {
return (
<span className="overflowHidden1" style={{ maxWidth: '400px' }}
title={shixunName && shixunName.length > 25 ? shixunName : ''}
>{shixunName}</span>
)
@ -204,59 +148,59 @@ class shixunAnswer extends Component{
title: '评测次数',
dataIndex: 'testCount',
key: 'testCount',
className:"edu-txt-center",
render:(testCount,item,index)=>{
return(
<span>{ item.testCount ? item.testCount : <span className="color-grey-9">--</span> }</span>
className: "edu-txt-center",
render: (testCount, item, index) => {
return (
<span>{item.testCount ? item.testCount : <span className="color-grey-9">--</span>}</span>
)
}
}, {
title: '完成时间',
key: 'endTime',
dataIndex: 'endTime',
className:"edu-txt-center",
render:(endTime,item,index)=>{
return(
<span>{ item.endTime ? item.endTime : <span className="color-grey-9">--</span> }</span>
className: "edu-txt-center",
render: (endTime, item, index) => {
return (
<span>{item.endTime ? item.endTime : <span className="color-grey-9">--</span>}</span>
)
}
}, {
title: '耗时',
dataIndex: 'needTime',
key: 'needTime',
className:"edu-txt-center",
render:(needTime,item,index)=>{
return(
<span>{ item.needTime ? item.needTime : <span className="color-grey-9">--</span> }</span>
className: "edu-txt-center",
render: (needTime, item, index) => {
return (
<span>{item.needTime ? item.needTime : <span className="color-grey-9">--</span>}</span>
)
}
}, {
title: '经验值',
dataIndex: 'exp',
key: 'exp',
className:"edu-txt-center",
render:(exp,item,index)=>{
return(
className: "edu-txt-center",
render: (exp, item, index) => {
return (
<span><span className="color-green">{item.my_exp}</span>/{item.total_exp}</span>
)
}
},{
}, {
title: '得分/满分',
dataIndex: 'score',
key: 'score',
className: (isAdmin || ( isStudent && exercise && exercise.exercise_status == 3 )) ? "edu-txt-center":"edu-txt-center none",
render:(score,item,index)=>{
return(
className: (isAdmin || (isStudent && exercise && exercise.exercise_status == 3)) ? "edu-txt-center" : "edu-txt-center none",
render: (score, item, index) => {
return (
<span><span className="color-orange-tip">{item.my_score}</span>/{item.total_score}</span>
)
}
},{
title: isAdmin ? <span><i className="color-red mr5">*</i></span>: '',
}, {
title: isAdmin ? <span><i className="color-red mr5">*</i></span> : '',
dataIndex: 'operation',
key: 'operation',
className: isAdmin ? "edu-txt-left" : "edu-txt-center",
render:(operation,item,index)=>{
return(
render: (operation, item, index) => {
return (
<span>
{
this.props.isAdmin() ?
@ -266,25 +210,25 @@ class shixunAnswer extends Component{
step={0.1}
precision={1}
value={item.input_score}
style={{width:"60px",marginLeft:"5px"}}
style={{ width: "60px", marginLeft: "5px" }}
placeholder="请输入分数"
onChange={(value)=>{this.changeThis(value,index)}}
onBlur={(value)=>this.changeThisScore(value,item.id,index)}
onChange={(value) => { this.changeThis(value, index) }}
onBlur={(value) => this.changeThisScore(value, item.id, index)}
className="greyInput"
></InputNumber>
:""
: ""
}
{
item.operation ?
<a className={isAdmin ? "color-blue mt5 fr":"color-blue"} href='javascript:void(0)' onClick={()=>this.scrollToAnchor(`${questionType.question_id}${index+1}`)}>查看</a>
<a className={isAdmin ? "color-blue mt5 fr" : "color-blue"} href='javascript:void(0)' onClick={() => this.scrollToAnchor(`${questionType.question_id}${index + 1}`)}>查看</a>
:
<span className={isAdmin ? "color-grey-9 mt5 fr":"color-grey-9"} >--</span>
<span className={isAdmin ? "color-grey-9 mt5 fr" : "color-grey-9"} >--</span>
}
</span>
)
}
}];
return(
return (
<div>
<style>
{`
@ -296,27 +240,27 @@ class shixunAnswer extends Component{
}
`}
</style>
{ exercise && ((exercise.student_commit_status && exercise.student_commit_status != 0) || (exercise.user_exercise_status && exercise.user_exercise_status !=0) ) ?
{exercise && ((exercise.student_commit_status && exercise.student_commit_status != 0) || (exercise.user_exercise_status && exercise.user_exercise_status != 0)) ?
<div>
<p className="padding20-30 font-16 color-grey-6 pl30">阶段成绩</p>
<div className={challenge && challenge.length > 0 ? "pl30 pr30 resetTableStyle":"pl30 pr30 resetTableStyle stageTable"}>
{ data && data.length>0 ? <Table columns={columns} dataSource={data} pagination={false}></Table> : "" }
<div className={challenge && challenge.length > 0 ? "pl30 pr30 resetTableStyle" : "pl30 pr30 resetTableStyle stageTable"}>
{data && data.length > 0 ? <Table columns={columns} dataSource={data} pagination={false}></Table> : ""}
</div>
{
challenge && challenge.length > 0 &&
<div>
<p className="mt20 pr30 font-16 color-grey-6 pl30">实训详情</p>
{
challenge.map((item,key)=>{
return(
<div className="pl30 pr30 mt20" id={`challenge_${questionType.question_id}${key+1}`}>
challenge.map((item, key) => {
return (
<div className="pl30 pr30 mt20" id={`challenge_${questionType.question_id}${key + 1}`}>
<p className="clearfix mb20">
<span className="panel-inner-icon mr15 fl mt3 backgroud4CACFF">
<i className="fa fa-code font-16 color_white"></i>
</span>
<span className="fl mt3 font-16">
<span className="font-bd mr15">{item[0].position}</span>
<Link to={ "/tasks/" + item[0].game_identifier } style={{"cursor":"pointer"}}>
<Link to={"/tasks/" + item[0].game_identifier} style={{ "cursor": "pointer" }}>
<span className={"font-16"}>{item[0].name}</span>
</Link>
</span>
@ -325,7 +269,7 @@ class shixunAnswer extends Component{
{...this.props} {...this.state} challenge={item[0].outputs}
></ShixunAnswerDetail>
{ item[0].st===0 ? <div className="font-16 color-dark-21">
{item[0].st === 0 ? <div className="font-16 color-dark-21">
<div className="bor-grey-e mt15">
<p className="clearfix pt5 pb5 pl15 pr15 back-f6-grey codebox">
<span className="fl">最近通过的代码</span>
@ -353,7 +297,7 @@ class shixunAnswer extends Component{
</li>
</div>
</div>
</div>:""}
</div> : ""}
</div>
)
})
@ -364,12 +308,12 @@ class shixunAnswer extends Component{
:
<div className="pl30 pr30">
{
isStudent && <p className="color-grey-9 mt20 mb20 markdown-body" dangerouslySetInnerHTML={{__html: markdownToHTML(questionType.question_title)}}></p>
isStudent && <p className="color-grey-9 mt20 mb20 markdown-body" dangerouslySetInnerHTML={{ __html: markdownToHTML(questionType.question_title) }}></p>
}
{
questionType && questionType.shixun && questionType.shixun.map((item,key)=>{
return(
questionType && questionType.shixun && questionType.shixun.map((item, key) => {
return (
<p key={key} className="font-16 color-grey-6 mb5">
<span className="mr20">{item.challenge_position} {item.challenge_name}</span>
<span>{item.challenge_score}</span>

@ -1,7 +1,7 @@
import React,{ Component } from "react";
import {Form,Checkbox,DatePicker,Button,Input,Select,Tooltip} from "antd";
import React, { Component } from "react";
import { Form, Checkbox, DatePicker, Button, Tooltip } from "antd";
import { handleDateString,ConditionToolTip } from 'educoder';
import { handleDateString } from 'educoder';
import PollDetailTabForthRules from './PollDetailTabForthRules'
import HomeworkModal from "../coursesPublic/HomeworkModal";
@ -14,10 +14,6 @@ import moment from 'moment'
import locale from 'antd/lib/date-picker/locale/zh_CN';
import axios from 'axios'
import Modals from '../../modals/Modals'
import { mapProps } from "recompose";
const Search=Input.Search;
const Option=Select.Option;
function range(start, end) {
const result = [];
@ -38,156 +34,156 @@ function disabledDate(current) {
return current && current < moment().endOf('day').subtract(1, 'days');
}
const dataformat="YYYY-MM-DD HH:mm";
const dataformat = "YYYY-MM-DD HH:mm";
class PollDetailTabForth extends Component{
constructor(props){
class PollDetailTabForth extends Component {
constructor(props) {
super(props);
this.state={
modalname:undefined,
modaltype:undefined,
visible:false,
Topval:undefined,
Topvalright:undefined,
Botvalleft:undefined,
Botval:undefined,
starttime:undefined,
endtime:undefined,
Cancelname:undefined,
Savesname:undefined,
Cancel:undefined,
Saves:undefined,
chooseId:undefined,
publishCourse:undefined,
flagPageEdit:undefined,
unitSetting:true,
flagPublic:false,
flagRealName:undefined,
course_group:undefined,
end_time:undefined,
publish_time:undefined,
unit_p_tip:undefined,
unit_e_tip:undefined,
rules:undefined,
p_flag:undefined,
e_flag:undefined,
polls:undefined,
un_change_unified:false,
un_change_end:false,
this.state = {
modalname: undefined,
modaltype: undefined,
visible: false,
Topval: undefined,
Topvalright: undefined,
Botvalleft: undefined,
Botval: undefined,
starttime: undefined,
endtime: undefined,
Cancelname: undefined,
Savesname: undefined,
Cancel: undefined,
Saves: undefined,
chooseId: undefined,
publishCourse: undefined,
flagPageEdit: undefined,
unitSetting: true,
flagPublic: false,
flagRealName: undefined,
course_group: undefined,
end_time: undefined,
publish_time: undefined,
unit_p_tip: undefined,
unit_e_tip: undefined,
rules: undefined,
p_flag: undefined,
e_flag: undefined,
polls: undefined,
un_change_unified: false,
un_change_end: false,
//公用提示弹框相关
modalsType:false,
modalsTopval:"",
loadtype:false,
modalSave:undefined,
firstSetting:true
modalsType: false,
modalsTopval: "",
loadtype: false,
modalSave: undefined,
firstSetting: true
}
}
//加载
componentDidMount=()=>{
componentDidMount = () => {
this.getSettingInfo();
//window.addEventListener('click', this.handleClick);
if(this.props.pollDetail!=undefined){
if (this.props.pollDetail != undefined) {
this.editSetting();
}
if(this.props.isAdmin() === false){
if (this.props.isAdmin() === false) {
this.cancelEdit()
}
try {
this.props.triggerRef(this);
}catch (e) {
} catch (e) {
}
}
componentDidUpdate = (prevProps) => {
if(prevProps.pollDetail!= this.props.pollDetail){
if (prevProps.pollDetail != this.props.pollDetail) {
this.editSetting();
}
}
handleClick=(e)=>{
handleClick = (e) => {
console.log(e);
}
// 已有设置数据的查询
getSettingInfo=(type)=>{
if(type!=1){
getSettingInfo = (type) => {
if (type != 1) {
this.props.newgetPollInfo();
}
let pollId=this.props.match.params.pollId;
let url=`/polls/${pollId}/poll_setting.json`;
axios.get(url).then((result)=>{
if(result){
let pollId = this.props.match.params.pollId;
let url = `/polls/${pollId}/poll_setting.json`;
axios.get(url).then((result) => {
if (result) {
this.setState({
polls:result.data.poll,
unitSetting:result.data.poll.unified_setting,
flagPublic:result.data.poll.show_result,
flagRealName:result.data.poll.un_anonymous,
course_group:result.data.course_groups,
publish_time:result.data.poll.publish_time,
end_time:result.data.poll.end_time,
firstSetting:result.data.published_course_groups.length==0 && result.data.poll.publish_time == null && result.data.poll.end_time==null,
polls: result.data.poll,
unitSetting: result.data.poll.unified_setting,
flagPublic: result.data.poll.show_result,
flagRealName: result.data.poll.un_anonymous,
course_group: result.data.course_groups,
publish_time: result.data.poll.publish_time,
end_time: result.data.poll.end_time,
firstSetting: result.data.published_course_groups.length == 0 && result.data.poll.publish_time == null && result.data.poll.end_time == null,
})
// 统一设置时如果已发布则不能修改统一设置和发布时间,已截止不能修改结束时间
if(result.data.poll.unified_setting == true && moment(result.data.poll.publish_time) <= moment()){
if (result.data.poll.unified_setting == true && moment(result.data.poll.publish_time) <= moment()) {
this.setState({
un_change_unified:true
un_change_unified: true
})
}
if(result.data.poll.unified_setting == true && moment(result.data.poll.end_time) <= moment()){
if (result.data.poll.unified_setting == true && moment(result.data.poll.end_time) <= moment()) {
this.setState({
un_change_end:true
un_change_end: true
})
}
let publish_count = 0;
let group=result.data.published_course_groups;
if(group.length==0){
let list= [{
course_group_id:[],
course_group_name:[],
publish_time:undefined,
end_time:undefined,
publish_flag:"",
end_flag:"",
class_flag:"",
course_search:"",
poll_status:0,
p_timeflag:false,
e_timeflag:false
let group = result.data.published_course_groups;
if (group.length == 0) {
let list = [{
course_group_id: [],
course_group_name: [],
publish_time: undefined,
end_time: undefined,
publish_flag: "",
end_flag: "",
class_flag: "",
course_search: "",
poll_status: 0,
p_timeflag: false,
e_timeflag: false
}]
this.setState({
rules:list
rules: list
})
}else{
let array=[];
for(var i=0;i<group.length;i++){
} else {
let array = [];
for (var i = 0; i < group.length; i++) {
array.push({
course_group_id:group[i].course_group_id,
course_group_name:group[i].course_group_name,
publish_time:group[i].course_publish_time,
end_time:group[i].course_end_time,
publish_flag:"",
end_flag:"",
class_flag:"",
course_search:"",
poll_status:result.data.poll.polls_status,
p_timeflag:moment(group[i].course_publish_time) <= moment() ,
e_timeflag:moment(group[i].course_end_time) <= moment()
})
if(moment(group[i].course_publish_time) <= moment()){
course_group_id: group[i].course_group_id,
course_group_name: group[i].course_group_name,
publish_time: group[i].course_publish_time,
end_time: group[i].course_end_time,
publish_flag: "",
end_flag: "",
class_flag: "",
course_search: "",
poll_status: result.data.poll.polls_status,
p_timeflag: moment(group[i].course_publish_time) <= moment(),
e_timeflag: moment(group[i].course_end_time) <= moment()
})
if (moment(group[i].course_publish_time) <= moment()) {
publish_count++;
}
}
this.setState({
rules:array,
rules: array,
un_change_unified: publish_count > 0
})
}
}
}).catch((error)=>{
}).catch((error) => {
console.log(error);
})
}
@ -198,181 +194,181 @@ class PollDetailTabForth extends Component{
e.preventDefault();
this.props.form.validateFieldsAndScroll((err, values) => {
if(!err){
if (!err) {
// 第一次进行问卷设置或者勾选了统一设置
let{unitSetting}=this.state
if(unitSetting==true){
let { unitSetting } = this.state
if (unitSetting == true) {
console.log("统一设置");
this.UnifiedSetting();
}else{
} else {
console.log("非统一设置");
this.NotUnifiedSetting();
}
}
})
}
UnifiedSetting=()=>{
let { unit_e_tip , unit_p_tip , publish_time , end_time ,course_group }=this.state
if( this.state.un_change_unified == false){
if ( !publish_time ){
UnifiedSetting = () => {
let { unit_e_tip, unit_p_tip, publish_time, end_time, course_group } = this.state
if (this.state.un_change_unified == false) {
if (!publish_time) {
this.setState({
unit_p_tip:"请选择发布时间"
unit_p_tip: "请选择发布时间"
})
return;
}else if( moment(publish_time,dataformat) < moment() ){
} else if (moment(publish_time, dataformat) < moment()) {
this.setState({
unit_p_tip:"发布时间不能小于当前时间"
unit_p_tip: "发布时间不能小于当前时间"
})
return;
}else{
} else {
this.setState({
unit_p_tip:""
unit_p_tip: ""
})
}
}
if(this.state.un_change_end == false){
if(!end_time){
if (this.state.un_change_end == false) {
if (!end_time) {
this.setState({
unit_e_tip:"请输入截止时间"
unit_e_tip: "请输入截止时间"
})
return;
}else if(moment(end_time,dataformat) <= moment(publish_time,dataformat)){
} else if (moment(end_time, dataformat) <= moment(publish_time, dataformat)) {
this.setState({
unit_e_tip:"截止时间不能小于发布时间"
unit_e_tip: "截止时间不能小于发布时间"
})
return;
}else if(moment(end_time,dataformat)<=moment()){
} else if (moment(end_time, dataformat) <= moment()) {
this.setState({
unit_e_tip:"截止时间不能小于当前时间"
unit_e_tip: "截止时间不能小于当前时间"
})
return;
}else{
} else {
this.setState({
unit_e_tip:""
unit_e_tip: ""
})
}
}
this.commitSetting((result)=>{
if(result.status==200){
this.commitSetting((result) => {
if (result.status == 200) {
this.props.showNotification(`${result.data.message}`);
this.getSettingInfo(1);
this.setState({
flagPageEdit:false
flagPageEdit: false
})
}
})
}
// 非统一设置提交
NotUnifiedSetting=()=>{
NotUnifiedSetting = () => {
const result = this.refs.pollDetailTabForthRules.notUnifiedSettingCheck(this.state.rules);
this.setState({
rules: result.rules
})
if(result.validate==false){
if (result.validate == false) {
return;
}
this.commitSetting((result)=>{
if(result.status==200){
this.commitSetting((result) => {
if (result.status == 200) {
this.props.showNotification(`${result.data.message}`);
this.getSettingInfo(1);
this.setState({
flagPageEdit:false
flagPageEdit: false
})
}
});
}
//暂不发布
homeworkhide=()=>{
homeworkhide = () => {
this.setState({
modalname:undefined,
modaltype:undefined,
visible:false,
Topval:undefined,
Topvalright:undefined,
Botvalleft:undefined,
Botval:undefined,
starttime:undefined,
endtime:undefined,
Cancelname:undefined,
Savesname:undefined,
Cancel:undefined,
Saves:undefined,
StudentList_value:undefined,
addname:undefined,
addnametype:false,
addnametab:undefined,
publish_time:undefined
modalname: undefined,
modaltype: undefined,
visible: false,
Topval: undefined,
Topvalright: undefined,
Botvalleft: undefined,
Botval: undefined,
starttime: undefined,
endtime: undefined,
Cancelname: undefined,
Savesname: undefined,
Cancel: undefined,
Saves: undefined,
StudentList_value: undefined,
addname: undefined,
addnametype: false,
addnametab: undefined,
publish_time: undefined
})
}
// 确定立即发布(只要保存设置就可以)
homeworkstartend=()=>{
let {chooseId}=this.state;
let pollId=this.props.match.params.pollId;
let coursesId=this.props.match.params.coursesId;
homeworkstartend = () => {
let { chooseId } = this.state;
let pollId = this.props.match.params.pollId;
let coursesId = this.props.match.params.coursesId;
console.log(chooseId);
this.commitSetting((result)=>{
if(result.status==200){
let url=`/courses/${coursesId}/polls/publish.json`;
axios.post((url),{
check_ids:[pollId],
group_ids:chooseId
}).then((Response)=>{
if(Response.status == 200){
this.commitSetting((result) => {
if (result.status == 200) {
let url = `/courses/${coursesId}/polls/publish.json`;
axios.post((url), {
check_ids: [pollId],
group_ids: chooseId
}).then((Response) => {
if (Response.status == 200) {
this.props.showNotification(`${Response.data.message}`);
this.homeworkhide();
this.setState({
flagPageEdit:false
flagPageEdit: false
})
this.getSettingInfo();
this.props.getPollInfo();
}
}).catch((error)=>{
}).catch((error) => {
console.log(error);
})
}
})
}
getcourse_groupslist=(id)=>{
getcourse_groupslist = (id) => {
this.setState({
chooseId:id
chooseId: id
})
}
commitSetting=(callback)=>{
let pollId=this.props.match.params.pollId;
let url=`/polls/${pollId}/commit_setting.json`;
let params=[];
if(this.state.unitSetting){
params={
unified_setting:this.state.unitSetting,
publish_time:this.state.publish_time,
end_time:this.state.end_time,
show_result:this.state.flagPublic,
un_anonymous:this.state.flagRealName
commitSetting = (callback) => {
let pollId = this.props.match.params.pollId;
let url = `/polls/${pollId}/commit_setting.json`;
let params = [];
if (this.state.unitSetting) {
params = {
unified_setting: this.state.unitSetting,
publish_time: this.state.publish_time,
end_time: this.state.end_time,
show_result: this.state.flagPublic,
un_anonymous: this.state.flagRealName
}
}else{
params={
unified_setting:this.state.unitSetting,
show_result:this.state.flagPublic,
un_anonymous:this.state.flagRealName,
publish_time_groups:this.state.rules
} else {
params = {
unified_setting: this.state.unitSetting,
show_result: this.state.flagPublic,
un_anonymous: this.state.flagRealName,
publish_time_groups: this.state.rules
}
}
axios.post((url),params).then((result)=>{
axios.post((url), params).then((result) => {
callback(result);
}).catch((error)=>{
}).catch((error) => {
console.log(error);
})
}
rulesCheckInfo=(rules)=>{
rulesCheckInfo = (rules) => {
console.log(rules);
this.setState({
rules
@ -380,54 +376,54 @@ class PollDetailTabForth extends Component{
}
cancelBox=()=>{
cancelBox = () => {
this.setState({
modalsType:false,
modalsTopval:"",
loadtype:false,
modalsType: false,
modalsTopval: "",
loadtype: false,
})
}
// 是否统一设置
changeUnit=(e)=>{
changeUnit = (e) => {
this.setState({
unitSetting:e.target.checked
unitSetting: e.target.checked
})
}
//是否公开统计
ChangeFlagPublic=(e)=>{
ChangeFlagPublic = (e) => {
this.setState({
flagPublic:e.target.checked
flagPublic: e.target.checked
})
}
//是否实名问卷
ChangeFlagName=(e)=>{
ChangeFlagName = (e) => {
this.setState({
flagRealName:e.target.checked
flagRealName: e.target.checked
})
}
onChangeTimepublish=(date, dateString)=>{
if(date!=null && date!="" && date != undefined && moment(date,dataformat)>moment()){
onChangeTimepublish = (date, dateString) => {
if (date != null && date != "" && date != undefined && moment(date, dataformat) > moment()) {
this.setState({
unit_p_tip:""
unit_p_tip: ""
})
}
let { end_time }=this.state;
if(!end_time){
let { end_time } = this.state;
if (!end_time) {
end_time = moment(handleDateString(dateString)).add(1, 'months');
}
this.setState({
publish_time: handleDateString(dateString),
end_time:end_time
end_time: end_time
})
}
onChangeTimeEnd=(date, dateString)=>{
if( date && moment(date,dataformat)>moment(this.state.publish_time,dataformat) && moment(date,dataformat) > moment()){
onChangeTimeEnd = (date, dateString) => {
if (date && moment(date, dataformat) > moment(this.state.publish_time, dataformat) && moment(date, dataformat) > moment()) {
this.setState({
unit_e_tip:""
unit_e_tip: ""
})
}
this.setState({
@ -437,23 +433,23 @@ class PollDetailTabForth extends Component{
//编辑
editSetting = () => {
if(this.props.pollDetail.course_is_end==true){
if (this.props.pollDetail.course_is_end == true) {
this.setState({
modalsType:true,
modalsTopval:"课堂已结束不能再修改!",
loadtype:true,
modalSave:this.cancelBox
modalsType: true,
modalsTopval: "课堂已结束不能再修改!",
loadtype: true,
modalSave: this.cancelBox
})
}else{
} else {
this.setState({
flagPageEdit:this.props.isAdmin()?true:false
flagPageEdit: this.props.isAdmin() ? true : false
})
}
}
//取消编辑
cancelEdit=()=>{
cancelEdit = () => {
this.setState({
flagPageEdit:false
flagPageEdit: false
})
this.getSettingInfo(1);
}
@ -461,8 +457,8 @@ class PollDetailTabForth extends Component{
render(){
let{
render() {
let {
modalname,
modaltype,
visible,
@ -479,7 +475,7 @@ class PollDetailTabForth extends Component{
publishCourse,
un_change_unified,
un_change_end,
flagPageEdit,unitSetting,flagPublic,flagRealName,end_time,publish_time,course_group,rules,
flagPageEdit, unitSetting, flagPublic, flagRealName, end_time, publish_time, course_group, rules,
unit_p_tip,
unit_e_tip,
modalsType,
@ -487,7 +483,7 @@ class PollDetailTabForth extends Component{
loadtype,
modalSave,
firstSetting
}=this.state
} = this.state
let { pollDetail } = this.props;
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
@ -504,7 +500,7 @@ class PollDetailTabForth extends Component{
};
let isAdmin = this.props.isAdmin();
let isStudent = this.props.isStudent();
return(
return (
<div>
<HomeworkModal
modaltype={modaltype}
@ -521,7 +517,7 @@ class PollDetailTabForth extends Component{
Cancel={Cancel}
Saves={Saves}
course_groups={publishCourse}
getcourse_groupslist={(id)=>this.getcourse_groupslist(id)}
getcourse_groupslist={(id) => this.getcourse_groupslist(id)}
/>
<Modals
modalsType={modalsType}
@ -542,7 +538,7 @@ class PollDetailTabForth extends Component{
编辑设置
{/*<Tooltip title="编辑"><i className="iconfont icon-bianjidaibeijing font-20 color-green"></i></Tooltip>*/}
</a>
:""
: ""
}
</p>
<div className="pl25">
@ -553,7 +549,7 @@ class PollDetailTabForth extends Component{
{getFieldDecorator('unitSet')
(
<Checkbox disabled={un_change_unified == true ? true : !flagPageEdit}
className="mr15 font-16 color-grey-6" checked={ unitSetting }
className="mr15 font-16 color-grey-6" checked={unitSetting}
onChange={this.changeUnit}>统一设置</Checkbox>
)}
</Form.Item>
@ -566,7 +562,7 @@ class PollDetailTabForth extends Component{
<div className="clearfix mb5">
<span className="font-16 mr15 fl mt6">发布时间</span>
<div className="fl">
<Tooltip placement="bottom" title={un_change_unified == true?this.props.isAdmin()? "发布时间已过,不能再修改":"":""}>
<Tooltip placement="bottom" title={un_change_unified == true ? this.props.isAdmin() ? "发布时间已过,不能再修改" : "" : ""}>
<span>
<DatePicker
showToday={false}
@ -574,19 +570,19 @@ class PollDetailTabForth extends Component{
showTime={{ format: 'HH:mm' }}
placeholder="请选择发布时间"
locale={locale}
className={unit_p_tip && unit_p_tip != "" ?"noticeTip winput-240-40":"winput-240-40" }
style={{"height":"42px"}}
className={unit_p_tip && unit_p_tip != "" ? "noticeTip winput-240-40" : "winput-240-40"}
style={{ "height": "42px" }}
format="YYYY-MM-DD HH:mm"
disabledTime={disabledDateTime}
onChange={this.onChangeTimepublish}
value={publish_time && moment(publish_time,dataformat)}
disabled={un_change_unified == true ? true : !flagPageEdit }
value={publish_time && moment(publish_time, dataformat)}
disabled={un_change_unified == true ? true : !flagPageEdit}
></DatePicker>
</span>
</Tooltip>
<p className="color-red lineh-25 clearfix" style={{height:"25px"}}>
<p className="color-red lineh-25 clearfix" style={{ height: "25px" }}>
{
unit_p_tip && unit_p_tip != "" ? <span className="fl">{ unit_p_tip }</span>:""
unit_p_tip && unit_p_tip != "" ? <span className="fl">{unit_p_tip}</span> : ""
}
</p>
</div>
@ -595,7 +591,7 @@ class PollDetailTabForth extends Component{
<div className="clearfix">
<span className="mr15 fl mt10 font-16">截止时间</span>
<div className="fl">
<Tooltip placement="bottom" title={un_change_end ? this.props.isAdmin()?"":"截止时间已过,不能再修改":""}>
<Tooltip placement="bottom" title={un_change_end ? this.props.isAdmin() ? "" : "截止时间已过,不能再修改" : ""}>
<span>
<DatePicker
showToday={false}
@ -603,23 +599,23 @@ class PollDetailTabForth extends Component{
showTime={{ format: 'HH:mm' }}
locale={locale}
placeholder="请选择截止时间"
style={{"height":"42px"}}
className={unit_e_tip && unit_e_tip != "" ? "noticeTip winput-240-40 mr20":"winput-240-40 mr20" }
style={{ "height": "42px" }}
className={unit_e_tip && unit_e_tip != "" ? "noticeTip winput-240-40 mr20" : "winput-240-40 mr20"}
width={"240px"}
format="YYYY-MM-DD HH:mm"
disabledTime={disabledDateTime}
disabledDate={disabledDate}
onChange={this.onChangeTimeEnd}
value={ end_time && moment(end_time,dataformat) }
value={end_time && moment(end_time, dataformat)}
// disabled={un_change_end == true ?true : !flagPageEdit }
disabled={un_change_end == true ? this.props.isAdmin()?!flagPageEdit:true : !flagPageEdit }
disabled={un_change_end == true ? this.props.isAdmin() ? !flagPageEdit : true : !flagPageEdit}
>
</DatePicker>
</span>
</Tooltip>
<p className="color-red lineh-25 clearfix" style={{height:"25px"}}>
<p className="color-red lineh-25 clearfix" style={{ height: "25px" }}>
{
unit_e_tip && unit_e_tip != "" ? <span className="fl">{ unit_e_tip }</span>:""
unit_e_tip && unit_e_tip != "" ? <span className="fl">{unit_e_tip}</span> : ""
}
</p>
</div>
@ -635,7 +631,7 @@ class PollDetailTabForth extends Component{
type={"polls"}
course_group={course_group}
flagPageEdit={flagPageEdit}
rulesCheckInfo={(info)=>this.rulesCheckInfo(info)}
rulesCheckInfo={(info) => this.rulesCheckInfo(info)}
></PollDetailTabForthRules>
}
</div>
@ -665,11 +661,11 @@ class PollDetailTabForth extends Component{
</div>
</div>
{
flagPageEdit&& this.props.isAdmin() === true ?
flagPageEdit && this.props.isAdmin() === true ?
<div className="clearfix mt30 mb30">
<Button type="primary" htmlType="submit" className="defalutSubmitbtn fl mr20">提交</Button>
<a className="defalutCancelbtn fl" onClick={this.cancelEdit}>取消</ a>
</div>:""
</div> : ""
}
</Form>

@ -1,7 +1,7 @@
import React, {Component} from "react";
import {WordsBtn,markdownToHTML,getRandomcode,queryString,downloadFile,getImageUrl} from 'educoder';
import { Form, Select, Input, Button,Checkbox,Upload,Icon,message,Modal, Table, Divider,InputNumber, Tag,DatePicker,Radio,Tooltip,Spin} from "antd";
import {Link,Switch,Route,Redirect} from 'react-router-dom';
import React, { Component } from "react";
import { WordsBtn, markdownToHTML, getRandomcode, queryString, getImageUrl } from 'educoder';
import { Icon, Spin } from "antd";
import { Link } from 'react-router-dom';
import axios from 'axios';
import moment from 'moment';
import Modals from "../../modals/Modals";
@ -12,11 +12,7 @@ import Shixunechart from './shixunreport/Shixunechart';
import DownloadMessageysl from "../../modals/DownloadMessageysl"
import AppraiseModal from "../coursesPublic/AppraiseModal";
import ShowAppraiseList from './ShowAppraiseList';
import {UnControlled as CodeMirror} from 'react-codemirror2';
import 'codemirror/mode/cmake/cmake';
import 'codemirror/mode/xml/xml';
import 'codemirror/mode/javascript/javascript';
import 'codemirror/mode/clike/clike';
import { UnControlled as CodeMirror } from 'react-codemirror2';
import '../css/members.css';
import "../common/formCommon.css";
import '../css/Courses.css';
@ -29,54 +25,54 @@ class ShixunWorkReport extends Component {
constructor(props) {
super(props);
this.state = {
data:undefined,
spinning:true,
DownloadType:false,
DownloadMessageval:undefined,
isspinning:false,
showAppraiseModaltype:false,
work_comment_hidden:undefined,
work_comment:undefined,
data: undefined,
spinning: true,
DownloadType: false,
DownloadMessageval: undefined,
isspinning: false,
showAppraiseModaltype: false,
work_comment_hidden: undefined,
work_comment: undefined,
has_commit: false,
}
}
/// 确认是否下载
confirmysl(url,child){
confirmysl(url, child) {
this.setState({ isspinning: true })
let params ={}
if(child!=undefined){
params =child._getRequestParams()!==undefined?child._getRequestParams():{};
let params = {}
if (child != undefined) {
params = child._getRequestParams() !== undefined ? child._getRequestParams() : {};
}
const urll=url+`?${queryString.stringify(params)}`;
axios.get(urll+ '&export=true').then((response) => {
if(response===undefined){
const urll = url + `?${queryString.stringify(params)}`;
axios.get(urll + '&export=true').then((response) => {
if (response === undefined) {
return
}
if(response.data.status&&response.data.status===-1){
if (response.data.status && response.data.status === -1) {
}else if(response.data.status&&response.data.status===-2){
if(response.data.message === "100"){
} else if (response.data.status && response.data.status === -2) {
if (response.data.message === "100") {
// 已超出文件导出的上限数量100 ),建议:
this.setState({
DownloadType:true,
DownloadMessageval:100
DownloadType: true,
DownloadMessageval: 100
})
}else {
} else {
//因附件资料超过500M
this.setState({
DownloadType:true,
DownloadMessageval:500
DownloadType: true,
DownloadMessageval: 500
})
}
}else {
} else {
// this.props.slowDownload(url)
//
// this.props.showNotification(`正在下载中`);
window.open(getRandomcode("/api"+url+"?disposition=inline"), '_blank');
window.open(getRandomcode("/api" + url + "?disposition=inline"), '_blank');
this.setState({ isspinning: false })
}
}).catch((error) => {
@ -84,10 +80,10 @@ class ShixunWorkReport extends Component {
this.setState({ isspinning: false })
});
}
Downloadcal=()=>{
Downloadcal = () => {
this.setState({
DownloadType:false,
DownloadMessageval:undefined
DownloadType: false,
DownloadMessageval: undefined
})
}
@ -95,23 +91,23 @@ class ShixunWorkReport extends Component {
let query = this.props.location.pathname;
const type = query.split('/');
this.setState({
shixuntypes:type[3],
spinning:true
shixuntypes: type[3],
spinning: true
})
this.getdatalist()
}
getdatalist=()=>{
let homeworkid=this.props.match.params.homeworkid;
getdatalist = () => {
let homeworkid = this.props.match.params.homeworkid;
let url = `/student_works/${homeworkid}/shixun_work_report.json`
axios.get(url).then((result) => {
if (result.data.status === 403 || result.data.status === 401 || result.data.status === 407 || result.data.status === 408|| result.data.status === 409 || result.data.status === 500) {
if (result.data.status === 403 || result.data.status === 401 || result.data.status === 407 || result.data.status === 408 || result.data.status === 409 || result.data.status === 500) {
}else{
} else {
this.setState({
data:result.data,
work_comment_hidden:result.data.work_comment_hidden,
work_comment:result.data.work_comment,
data: result.data,
work_comment_hidden: result.data.work_comment_hidden,
work_comment: result.data.work_comment,
spinning: false,
has_commit: result.data.has_commit
})
@ -120,26 +116,26 @@ class ShixunWorkReport extends Component {
}).catch((error) => {
console.log(error)
this.setState({
spinning:false
spinning: false
})
})
}
jumptopic=(anchorName)=>{
; if (anchorName) {
jumptopic = (anchorName) => {
; if (anchorName) {
// 找到锚点
let anchorElement = document.getElementById(anchorName);
// 如果对应id的锚点存在就跳转到锚点
if(anchorElement) {
if (anchorElement) {
anchorElement.scrollIntoView();
}
}
}
gotohome=()=>{
let courseId=this.props.match.params.coursesId;
if(courseId===undefined){
gotohome = () => {
let courseId = this.props.match.params.coursesId;
if (courseId === undefined) {
this.props.history.push("/courses");
}else{
} else {
this.props.history.push(this.props.current_user.first_category_url);
}
}
@ -148,132 +144,132 @@ class ShixunWorkReport extends Component {
this.props.history.replace(`/courses/${this.props.match.params.coursesId}/shixun_homeworks/${this.state.data.homework_common_id}/list?tab=0`);
}
setupdalist=(challenge_score,overall_appraisal,work_score)=>{
let {data}=this.state;
let newdata=data;
newdata.challenge_score=challenge_score;
newdata.overall_appraisal=overall_appraisal;
newdata.work_score=work_score;
setupdalist = (challenge_score, overall_appraisal, work_score) => {
let { data } = this.state;
let newdata = data;
newdata.challenge_score = challenge_score;
newdata.overall_appraisal = overall_appraisal;
newdata.work_score = work_score;
this.setState({
data:newdata
data: newdata
})
}
showAppraiseModal=(type,id,show,hidden)=>{
let{data}=this.state;
showAppraiseModal = (type, id, show, hidden) => {
let { data } = this.state;
if(type==="child"){
data.stage_list.forEach((item,key)=>{
if(item.challenge_id===id){
item.challenge_comment=show;
item.challenge_comment_hidden=hidden;
if (type === "child") {
data.stage_list.forEach((item, key) => {
if (item.challenge_id === id) {
item.challenge_comment = show;
item.challenge_comment_hidden = hidden;
}
})
this.setState({
showAppraiseModaltype:true,
showAppraisetype:type,
challenge_id:id,
data:data
showAppraiseModaltype: true,
showAppraisetype: type,
challenge_id: id,
data: data
})
}else{
} else {
this.setState({
showAppraiseModaltype:true,
showAppraisetype:type,
challenge_id:undefined,
work_comment:show,
work_comment_hidden:hidden
showAppraiseModaltype: true,
showAppraisetype: type,
challenge_id: undefined,
work_comment: show,
work_comment_hidden: hidden
})
}
}
hideAppraiseModal=()=>{
hideAppraiseModal = () => {
this.setState({
showAppraiseModaltype:false,
showAppraiseModaltype: false,
})
}
showAppraiseModals=(show,hidden,id,comment_id)=>{
showAppraiseModals = (show, hidden, id, comment_id) => {
let{data,showAppraisetype}=this.state;
let { data, showAppraisetype } = this.state;
if(showAppraisetype==="child"){
data.stage_list.forEach((item,key)=>{
if(item.challenge_id===id){
item.challenge_comment=show;
item.challenge_comment_hidden=hidden;
item.comment_id=comment_id
if (showAppraisetype === "child") {
data.stage_list.forEach((item, key) => {
if (item.challenge_id === id) {
item.challenge_comment = show;
item.challenge_comment_hidden = hidden;
item.comment_id = comment_id
}
})
this.setState({
showAppraiseModaltype:false,
data:data
showAppraiseModaltype: false,
data: data
})
}else{
data.comment_id=comment_id;
} else {
data.comment_id = comment_id;
this.setState({
showAppraiseModaltype:false,
work_comment:show,
work_comment_hidden:hidden,
data:data
showAppraiseModaltype: false,
work_comment: show,
work_comment_hidden: hidden,
data: data
})
}
}
isdeleteModal=(comment_id,visible_comment,type)=>{
let newcomment_id=comment_id;
let newvisible_comment=visible_comment;
let newtype=type;
isdeleteModal = (comment_id, visible_comment, type) => {
let newcomment_id = comment_id;
let newvisible_comment = visible_comment;
let newtype = type;
this.setState({
modalsType: true,
modalsTopval:"是否确认删除?",
modalSave: ()=>this.isdeleteModals(newcomment_id,newvisible_comment,newtype),
modalCancel:()=>this.hideisdeleteModals(),
modalsTopval: "是否确认删除?",
modalSave: () => this.isdeleteModals(newcomment_id, newvisible_comment, newtype),
modalCancel: () => this.hideisdeleteModals(),
})
}
hideisdeleteModals=()=>{
hideisdeleteModals = () => {
this.setState({
modalsType:false,
modalsTopval:"是否确认删除?",
modalsType: false,
modalsTopval: "是否确认删除?",
modalSave: "",
modalCancel:"",
modalCancel: "",
})
}
hideisdeleteModal=(comment_id,visible_comment,type)=>{
hideisdeleteModal = (comment_id, visible_comment, type) => {
let{data,work_comment,work_comment_hidden}=this.state;
let { data, work_comment, work_comment_hidden } = this.state;
if(type==="child"){
data.stage_list.map((item,key)=>{
if (type === "child") {
data.stage_list.map((item, key) => {
console.log(item)
if(item.comment_id!=null){
if(item.comment_id===comment_id){
item.challenge_comment=null;
item.challenge_comment_hidden=null;
if (item.comment_id != null) {
if (item.comment_id === comment_id) {
item.challenge_comment = null;
item.challenge_comment_hidden = null;
}
}
})
this.setState({
modalsType:false,
modalsTopval:"是否确认删除?",
modalsType: false,
modalsTopval: "是否确认删除?",
modalSave: "",
modalCancel:"",
data:data
modalCancel: "",
data: data
})
}else{
} else {
this.setState({
modalsType:false,
modalsTopval:"是否确认删除?",
modalsType: false,
modalsTopval: "是否确认删除?",
modalSave: "",
modalCancel:"",
work_comment:null,
work_comment_hidden:null
modalCancel: "",
work_comment: null,
work_comment_hidden: null
})
@ -281,20 +277,22 @@ class ShixunWorkReport extends Component {
}
isdeleteModals=(comment_id,visible_comment,type)=>{
let newcomment_id=comment_id;
let newvisible_comment=visible_comment;
let newtype=type;
if(comment_id!=null){
let url =`/student_works/${this.props.match.params.homeworkid}/destroy_work_comment.json`
axios.delete(url, { data: {
comment_id:comment_id,
}}).then((response) => {
isdeleteModals = (comment_id, visible_comment, type) => {
let newcomment_id = comment_id;
let newvisible_comment = visible_comment;
let newtype = type;
if (comment_id != null) {
let url = `/student_works/${this.props.match.params.homeworkid}/destroy_work_comment.json`
axios.delete(url, {
data: {
comment_id: comment_id,
}
}).then((response) => {
// const { status } = response.data;
if(response.data.status===0){
if (response.data.status === 0) {
this.props.showNotification(response.data.message)
this.hideisdeleteModal(newcomment_id,newvisible_comment,newtype)
}else{
this.hideisdeleteModal(newcomment_id, newvisible_comment, newtype)
} else {
this.props.showNotification(response.data.message)
}
})
@ -305,20 +303,20 @@ class ShixunWorkReport extends Component {
}
render() {
let {data, showAppraiseModaltype, work_comment_hidden, work_comment, has_commit} = this.state;
let { data, showAppraiseModaltype, work_comment_hidden, work_comment, has_commit } = this.state;
let category_id=data===undefined?"":data.category===null?"":data.category.category_id;
let homework_common_id=data===undefined?"":data.homework_common_id;
let homeworkid=this.props.match.params.homeworkid;
let category_id = data === undefined ? "" : data.category === null ? "" : data.category.category_id;
let homework_common_id = data === undefined ? "" : data.homework_common_id;
let homeworkid = this.props.match.params.homeworkid;
const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />;
// let showAppraiseModals=this.props&&this.props.isAdminOrTeacher()===true?work_comment===null||work_comment===undefined?false:true:work_comment===null||work_comment===undefined?false:true;
let showAppraiseModals=work_comment===null||work_comment===undefined?false:true;
document.title=data&&data.course_name;
let showAppraiseModals = work_comment === null || work_comment === undefined ? false : true;
document.title = data && data.course_name;
return (
data===undefined?"":<Spin indicator={antIcon} spinning={this.state.spinning}>
data === undefined ? "" : <Spin indicator={antIcon} spinning={this.state.spinning}>
<Modals
modalsType={this.state.modalsType}
modalsTopval={this.state.modalsTopval}
@ -329,19 +327,19 @@ class ShixunWorkReport extends Component {
{showAppraiseModaltype===true?<AppraiseModal
{showAppraiseModaltype === true ? <AppraiseModal
{...this.props}
{...this.state}
visible={showAppraiseModaltype}
Cancel={()=>this.hideAppraiseModal()}
showCancel={(show,hidden,id,comment_id)=>this.showAppraiseModals(show,hidden,id,comment_id)}
Cancel={() => this.hideAppraiseModal()}
showCancel={(show, hidden, id, comment_id) => this.showAppraiseModals(show, hidden, id, comment_id)}
work_comment={this.state.work_comment}
work_type={work_comment===null||work_comment===undefined?this.state.work_type:work_comment_hidden===true?1:0}
/>:""}
work_type={work_comment === null || work_comment === undefined ? this.state.work_type : work_comment_hidden === true ? 1 : 0}
/> : ""}
<div className="newMain clearfix ">
<div className={"educontent mb20" }>
<div className={"educontent mb20"}>
<div className="educontent">
<DownloadMessageysl
{...this.props}
@ -350,40 +348,40 @@ class ShixunWorkReport extends Component {
modalsType={this.state.DownloadType}
/>
<p className="clearfix mt20">
<a className="btn colorgrey fl hovercolorblue " onClick={()=>this.gotohome()}>
<span className={"color-grey-9"}> {data&&data.course_name}</span>
<a className="btn colorgrey fl hovercolorblue " onClick={() => this.gotohome()}>
<span className={"color-grey-9"}> {data && data.course_name}</span>
</a>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<a className="btn colorgrey fl hovercolorblue " href={"/courses/"+this.props.match.params.coursesId+"/"+this.state.shixuntypes+"/"+category_id}>
<span className={"color-grey-9"}>{data===undefined?"":data.category===null?"":data.category.category_name}</span>
<a className="btn colorgrey fl hovercolorblue " href={"/courses/" + this.props.match.params.coursesId + "/" + this.state.shixuntypes + "/" + category_id}>
<span className={"color-grey-9"}>{data === undefined ? "" : data.category === null ? "" : data.category.category_name}</span>
</a>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<a href={"/courses/"+this.props.match.params.coursesId+"/"+this.state.shixuntypes+"/"+homework_common_id+"/list?tab=0"} className="fl color-grey-9">作业详情</a>
<a href={"/courses/" + this.props.match.params.coursesId + "/" + this.state.shixuntypes + "/" + homework_common_id + "/list?tab=0"} className="fl color-grey-9">作业详情</a>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<WordsBtn className="fl">{data&&data.username}</WordsBtn>
<WordsBtn className="fl">{data && data.username}</WordsBtn>
</p>
</div>
<div style={{ width:'100%',height:'75px'}} >
<p className=" fl color-black mt25 summaryname">{data&&data.shixun_name}</p>
<div style={{ width: '100%', height: '75px' }} >
<p className=" fl color-black mt25 summaryname">{data && data.shixun_name}</p>
{/*{this.props.isAdmin()?<a className=" fr font-14 ml30 mt10 mr20 color-grey-9 ">导出实训报告数据</a>:""}*/}
<a onClick={this.goback} className="color-grey-6 fr font-14 ml20 mt15">返回</a>
{this.props.isAdmin() ?<a
{this.props.isAdmin() ? <a
className=" color-blue font-14 fr ml20 mt15"
onClick={()=>this.confirmysl(`/student_works/${homeworkid}/export_shixun_work_report.pdf`)}
> <Spin size="small" spinning={this.state.isspinning}>导出实训报告</Spin></a>:
parseInt(this.props&&this.props.user.user_id)===parseInt(data&&data.user_id)?<a
onClick={() => this.confirmysl(`/student_works/${homeworkid}/export_shixun_work_report.pdf`)}
> <Spin size="small" spinning={this.state.isspinning}>导出实训报告</Spin></a> :
parseInt(this.props && this.props.user.user_id) === parseInt(data && data.user_id) ? <a
className=" color-blue font-14 fr ml20 mt15"
onClick={()=>this.confirmysl(`/student_works/${homeworkid}/export_shixun_work_report.pdf`)}
> <Spin size="small" spinning={this.state.isspinning}>导出实训报告</Spin></a>:""
onClick={() => this.confirmysl(`/student_works/${homeworkid}/export_shixun_work_report.pdf`)}
> <Spin size="small" spinning={this.state.isspinning}>导出实训报告</Spin></a> : ""
}
{/*{this.props.isAdmin() ?work_comment_hidden===true? "":<a*/}
{/*className=" color-blue font-14 fr ml20 mt15"*/}
{/*onClick={()=>this.showAppraiseModal(1)}*/}
{/*>评阅</a> : ""}*/}
{this.props.isAdmin() ?<a
{this.props.isAdmin() ? <a
className=" color-blue font-14 fr ml20 mt15"
onClick={()=>this.showAppraiseModal("main",undefined,work_comment,work_comment_hidden)}
>评阅</a>:""}
onClick={() => this.showAppraiseModal("main", undefined, work_comment, work_comment_hidden)}
>评阅</a> : ""}
</div>
@ -456,30 +454,30 @@ class ShixunWorkReport extends Component {
<div className="font-16 color-dark-21 shixunreporttitleboxtop pd20">总体评价</div>
<div className="font-16 color-dark-21 shixunreporttitleboxbom pd20">
<div style={{clear:"both",height:'100px'}}>
<div style={{ clear: "both", height: '100px' }}>
<div className="fl edu-back-white ml10 ">
<img alt="头像" className="radius" height="91" id="nh_user_logo" name="avatar_image"
src={ getImageUrl(`images/${data&&data.image_url}`)}
width="91"/>
src={getImageUrl(`images/${data && data.image_url}`)}
width="91" />
</div>
<div className={"fl edu-back-white ml39 "}>
<p className={"back_font mt10"}>{data&&data.username}</p>
<p className={"back_font mt10"}>{data && data.username}</p>
<p className={"mb16 mt10"}>
<span className={"passbox "}>
<div className={"passfont mb5"}><span className={"color999"}>当前完成关卡</span> <span className={"colorCF3B3B"}>{data&&data.complete_count}/{data&&data.challenges_count}</span></div>
<div className={"passfontbom"}><span className={"color999"}>经验值</span> <span className={"color333"}>{data&&data.myself_experience}/{data&&data.total_experience}</span></div>
<div className={"passfont mb5"}><span className={"color999"}>当前完成关卡</span> <span className={"colorCF3B3B"}>{data && data.complete_count}/{data && data.challenges_count}</span></div>
<div className={"passfontbom"}><span className={"color999"}>经验值</span> <span className={"color333"}>{data && data.myself_experience}/{data && data.total_experience}</span></div>
</span>
<span className={"passbox"}>
<div className={"passfontbommid mb5"}><span className={"color999"}>完成效率</span> <span className={data&&data.efficiency===null?"color999":"color333"}>{data&&data.efficiency===null?'--':data&&data.efficiency}</span></div>
<div className={"passfontmid "}><span className={"color999"}>课堂最高完成效率</span> <span className={data&&data.max_efficiency===null?"color999":"color333"}>{data&&data.max_efficiency===null?'--':data&&data.max_efficiency}</span></div>
<div className={"passfontbommid mb5"}><span className={"color999"}>完成效率</span> <span className={data && data.efficiency === null ? "color999" : "color333"}>{data && data.efficiency === null ? '--' : data && data.efficiency}</span></div>
<div className={"passfontmid "}><span className={"color999"}>课堂最高完成效率</span> <span className={data && data.max_efficiency === null ? "color999" : "color333"}>{data && data.max_efficiency === null ? '--' : data && data.max_efficiency}</span></div>
</span>
<span className={"passbox"}>
<div><span className={"color999"}>通关时间</span> <span className={data&&data.passed_time===null?"color999":"color333"}>{data&&data.passed_time===null||data&&data.passed_time=== "--"?'--':moment(data&&data.passed_time).format('YYYY-MM-DD HH:mm')}</span></div>
<div><span className={"color999"}>通关时间</span> <span className={data && data.passed_time === null ? "color999" : "color333"}>{data && data.passed_time === null || data && data.passed_time === "--" ? '--' : moment(data && data.passed_time).format('YYYY-MM-DD HH:mm')}</span></div>
{/*<div><span className={"color999"}>实战耗时:</span> <span className={data&&data.efficiency===null?"color999":"color333"}>{data&&data.time_consuming===null?'--':data&&data.time_consuming}</span></div>*/}
</span>
</p>
@ -504,9 +502,9 @@ class ShixunWorkReport extends Component {
{...this.props}
data={data}
jumptopic={this.jumptopic}
getdatalist={()=>this.getdatalist()}
setupdalist={(challenge_score,overall_appraisal,work_score)=>this.setupdalist(challenge_score,overall_appraisal,work_score)}
showAppraiseModal={(type,id,show,hidden)=>this.showAppraiseModal(type,id,show,hidden)}
getdatalist={() => this.getdatalist()}
setupdalist={(challenge_score, overall_appraisal, work_score) => this.setupdalist(challenge_score, overall_appraisal, work_score)}
showAppraiseModal={(type, id, show, hidden) => this.showAppraiseModal(type, id, show, hidden)}
/>
</div>
@ -539,17 +537,17 @@ class ShixunWorkReport extends Component {
</style>
<div className="stud-class-set mt17"
style={{display:data&&data.work_description===null?"none":""}}
style={{ display: data && data.work_description === null ? "none" : "" }}
>
<div className="clearfix edu-back-white poll_list">
<div className="font-16 color-dark-21 shixunreporttitleboxtop pd20 color333">
个人总结
</div>
<div className="font-16 color-dark-21 shixunreporttitleboxbom pd30">
<div style={{minHeight:'50px'}}>
<div style={{ minHeight: '50px' }}>
<div className={"personalsummary"}>
<div className={"markdown-body"}
dangerouslySetInnerHTML={{__html: markdownToHTML(data===undefined?"":data.work_description).replace(/▁/g, "▁▁▁")}}
dangerouslySetInnerHTML={{ __html: markdownToHTML(data === undefined ? "" : data.work_description).replace(/▁/g, "▁▁▁") }}
></div>
</div>
</div>
@ -561,8 +559,8 @@ class ShixunWorkReport extends Component {
<ShowAppraiseList
{...this.props}
{...this.state}
isdeleteModal={(comment_id,visible_comment,type)=>this.isdeleteModal(comment_id,visible_comment,type)}
showAppraiseModal={(type,id,show,hidden)=>this.showAppraiseModal(type,id,show,hidden)}
isdeleteModal={(comment_id, visible_comment, type) => this.isdeleteModal(comment_id, visible_comment, type)}
showAppraiseModal={(type, id, show, hidden) => this.showAppraiseModal(type, id, show, hidden)}
/>
{
@ -602,7 +600,7 @@ class ShixunWorkReport extends Component {
</span>
<span className="fl mt3 font-14">
<span className="font-bd mr15">{item.position}</span>
<Link to={/tasks/+item.game_identifier} >
<Link to={/tasks/ + item.game_identifier} >
<span className={"font-14"}>{item.subject}</span>
</Link>
</span>

@ -1,91 +1,89 @@
import React, {Component} from "react";
import {WordsBtn} from 'educoder';
import {Table,InputNumber} from "antd";
import {Link,Switch,Route,Redirect} from 'react-router-dom';
import React, { Component } from "react";
import { Table, InputNumber } from "antd";
import moment from 'moment';
import { MonacoDiffEditor } from 'react-monaco-editor';
import MonacoDiffEditor from 'react-monaco-editor';
import axios from 'axios';
class ShixunCustomsPass extends Component {
constructor(props) {
super(props);
this.state = {
loadingstate:true,
datas:undefined
loadingstate: true,
datas: undefined
}
}
componentDidMount() {
}
editgame_scores=(e,id,maxsum,code_rate,copy_user_id)=>{
editgame_scores = (e, id, maxsum, code_rate, copy_user_id) => {
let{datas}=this.state;
let newdatas=datas;
let score=e.target.value;
let { datas } = this.state;
let newdatas = datas;
let score = e.target.value;
if(score!=null&&score!=undefined&&score!=""){
if(score<0){
if (score != null && score != undefined && score != "") {
if (score < 0) {
this.props.showNotification("不能小于0");
this.setState({
customsids:id
customsids: id
})
}else if(score>maxsum){
} else if (score > maxsum) {
this.props.showNotification(`不能大于关卡分值${maxsum}`);
this.setState({
customsids:id
customsids: id
})
}else{
let work_id=this.props.data.work_id;
let url=`/student_works/${work_id}/adjust_review_score.json`
axios.post(url,{
type:"review",
score:score,
challenge_id:id,
code_rate:code_rate,
copy_user_id:copy_user_id
}).then((result)=>{
if(result.data.status===0){
} else {
let work_id = this.props.data.work_id;
let url = `/student_works/${work_id}/adjust_review_score.json`
axios.post(url, {
type: "review",
score: score,
challenge_id: id,
code_rate: code_rate,
copy_user_id: copy_user_id
}).then((result) => {
if (result.data.status === 0) {
this.props.updatas();
this.props.showNotification(result.data.message);
}else{
} else {
this.props.showNotification(result.data.message);
}
}).catch((error)=>{
}).catch((error) => {
})
}
}else{
} else {
this.props.showNotification("调分为空将不会修改之前的分数");
}
}
render() {
let {data}=this.props;
let {customsids}=this.state;
let { data } = this.props;
let { customsids } = this.state;
// console.log(data)
let datas=[];
let datas = [];
data&&data.challenge_list.forEach((item,key)=>{
data && data.challenge_list.forEach((item, key) => {
datas.push({
customs:{position:item.position,subject:item.subject},
taskname:{name:item.username},
openingtime:item.end_time===null?"无":item.end_time===undefined?"无":item.end_time===""?"无":moment(item.end_time).format('YYYY-MM-DD HH:mm:ss'),
evaluating: {final_score:item.final_score,all_score:item.all_score},
finishtime:item.copy_username,
elapsedtime:item.copy_end_time===null?"无":item.copy_end_time===undefined?"无":item.copy_end_time===""?"无":moment(item.copy_end_time).format('YYYY-MM-DD HH:mm:ss'),
empvalue:item.code_rate,
challenge_id:{id:item.id},
copy_user_id:item.copy_user_id
customs: { position: item.position, subject: item.subject },
taskname: { name: item.username },
openingtime: item.end_time === null ? "无" : item.end_time === undefined ? "无" : item.end_time === "" ? "无" : moment(item.end_time).format('YYYY-MM-DD HH:mm:ss'),
evaluating: { final_score: item.final_score, all_score: item.all_score },
finishtime: item.copy_username,
elapsedtime: item.copy_end_time === null ? "无" : item.copy_end_time === undefined ? "无" : item.copy_end_time === "" ? "无" : moment(item.copy_end_time).format('YYYY-MM-DD HH:mm:ss'),
empvalue: item.code_rate,
challenge_id: { id: item.id },
copy_user_id: item.copy_user_id
// adjustmentminute:asdasd
})
})
let columns=[{
let columns = [{
title: '关卡',
dataIndex: 'customs',
key: 'customs',
className:"customsPass",
className: "customsPass",
render: (text, record) => (
<span>
<style>
@ -135,7 +133,7 @@ class ShixunCustomsPass extends Component {
render: (text, record) => (
<span className={"color-grey-9"}>
<span style={{color:'#FF6800'}}>{record.evaluating.final_score}</span><span className={"color-grey-9"}>/{record.evaluating.all_score}</span>
<span style={{ color: '#FF6800' }}>{record.evaluating.final_score}</span><span className={"color-grey-9"}>/{record.evaluating.all_score}</span>
</span>
),
}, {
@ -157,7 +155,7 @@ class ShixunCustomsPass extends Component {
{record.elapsedtime}
</span>
),
},{
}, {
title: '调分',
key: 'adjustmentminute',
dataIndex: 'adjustmentminute',
@ -165,8 +163,8 @@ class ShixunCustomsPass extends Component {
render: (text, record) => (
<span>
<a>
{record.copy_user_id===null?"":<InputNumber size="small" className={customsids===record.challenge_id.id?"bor-red":""} defaultValue={record.evaluating.final_score}
onBlur={(e) => this.editgame_scores(e,record.challenge_id.id,record.evaluating.all_score,record.empvalue,record.copy_user_id)}
{record.copy_user_id === null ? "" : <InputNumber size="small" className={customsids === record.challenge_id.id ? "bor-red" : ""} defaultValue={record.evaluating.final_score}
onBlur={(e) => this.editgame_scores(e, record.challenge_id.id, record.evaluating.all_score, record.empvalue, record.copy_user_id)}
// min={0} max={record.game_scores.game_score_full}
/>}
</a>
@ -197,8 +195,8 @@ class ShixunCustomsPass extends Component {
// },
if(this.props.isAdmin()===false){
columns.some((item,key)=> {
if (this.props.isAdmin() === false) {
columns.some((item, key) => {
if (item.title === "调分") {
columns.splice(key, 1)
return true
@ -249,7 +247,7 @@ class ShixunCustomsPass extends Component {
}
`}
</style>
{datas===undefined?"":<Table
{datas === undefined ? "" : <Table
dataSource={datas}
columns={columns}
pagination={false}
@ -269,11 +267,11 @@ class ShixunCustomsPass extends Component {
`}
</style>
{
data&&data.challenge_list.map((item,key)=>{
data && data.challenge_list.map((item, key) => {
// console.log("203challenge_list下面的数据");
// console.log(item);
// console.log(JSON.stringify(item));
return(
return (
<div key={key} className={"mb20"}>
<div className="font-16 color-dark-21 ml20 mr20">
<p className="clearfix mb20">
@ -286,14 +284,14 @@ class ShixunCustomsPass extends Component {
<span className={"font-14"}>{item.subject}</span>
</a>
</span>
<span className="fr codeboxright">代码文件{item.code_list.length===0?"无":item.code_list[0].path===undefined?"无":item.code_list[0].path}</span>
<span className="fr codeboxright">代码文件{item.code_list.length === 0 ? "无" : item.code_list[0].path === undefined ? "无" : item.code_list[0].path}</span>
</p>
</div>
{item.code_list.length===0?"":item.code_list.map((ite,k)=>{
return(
{item.code_list.length === 0 ? "" : item.code_list.map((ite, k) => {
return (
<div className="font-16 color-dark-21 ml20 mr20" key={k}>
<div className=" mt15">
<p className="clearfix pt5 pb5 codebox">
@ -319,7 +317,7 @@ class ShixunCustomsPass extends Component {
height="500"
// language="javascript"
original={ite.origin_content}
value={ ite.target_content}
value={ite.target_content}
// options={options}
/>
</li>

@ -6,7 +6,7 @@
* @Last Modified time: 2019-11-18 16:52:38
*/
import './index.scss';
import './index.less';
import React from 'react';
import { Table, Button, Dropdown, Icon, Menu, Card, Input, Select, Tag } from 'antd';
@ -19,7 +19,7 @@ import { withRouter } from 'react-router';
import { toStore, CNotificationHOC } from 'educoder';
// import MyIcon from '../../common/components/MyIcon';
const {tagBackground, diffText} = CONST;
const { tagBackground, diffText } = CONST;
const { Search } = Input;
const { Option } = Select;
// import reqwest from 'reqwest';
@ -190,7 +190,7 @@ class DeveloperHome extends React.PureComponent {
title: '通过率',
dataIndex: 'passed_rate',
sorter: true,
align:'right',
align: 'right',
width: '10%',
render: val => <span>{`${val}%`}</span>
},
@ -218,7 +218,7 @@ class DeveloperHome extends React.PureComponent {
// 是否是我的,如果是我的 显示编辑按钮
const { isMySource } = this.props;
if (isMySource) {
this.handleFilterSearch({come_from: 'mine'});
this.handleFilterSearch({ come_from: 'mine' });
let _columns = this.columns.concat([this.options]);
this.setState({
columns: _columns
@ -227,7 +227,7 @@ class DeveloperHome extends React.PureComponent {
this.fetchData();
}
const {hacks_count} = this.props.ojListReducer;
const { hacks_count } = this.props.ojListReducer;
this.setState({
pagination: {
total: hacks_count
@ -237,7 +237,7 @@ class DeveloperHome extends React.PureComponent {
// 是否登录
isLogin = (url) => {
if(this.props.checkIfLogin()===false){
if (this.props.checkIfLogin() === false) {
this.props.showLoginDialog()
return false;
}
@ -266,7 +266,7 @@ class DeveloperHome extends React.PureComponent {
this.props.confirm({
title: '提示',
content: `确定要删除${record.name}吗?`,
onOk () {
onOk() {
// 调用删除接口
// console.log(record.identifier);
deleteItem(record.identifier);
@ -286,8 +286,8 @@ class DeveloperHome extends React.PureComponent {
}
// table条件变化时
handleTableChange = (pagination, filters, sorter) => {
const {field, order} = sorter;
const {current, pageSize} = pagination;
const { field, order } = sorter;
const { current, pageSize } = pagination;
this.handleFilterSearch({
sort_by: field,
sort_direction: order === 'descend' ? 'desc' : 'asc',
@ -341,7 +341,7 @@ class DeveloperHome extends React.PureComponent {
// 添加显示搜索条件
addShowFilterCtx = (obj) => {
const {searchInfo} = this.state
const { searchInfo } = this.state
const index = searchInfo.findIndex(item => item.type === obj.type);
let tempArr = [...searchInfo];
if (index > -1) {
@ -360,7 +360,7 @@ class DeveloperHome extends React.PureComponent {
handleInputSearch = (value) => {
value = value.trim();
// if (value.length === 0) return;
this.handleFilterSearch({search: value});
this.handleFilterSearch({ search: value });
}
// handleSearchChange = (e) => {
// console.log(e.target.value);
@ -372,7 +372,7 @@ class DeveloperHome extends React.PureComponent {
type: 'category',
key: item.key
});
this.handleFilterSearch({category: +item.key === 0 ? '' : +item.key});
this.handleFilterSearch({ category: +item.key === 0 ? '' : +item.key });
}
// 下拉语言
handleLanguageMenuClick = (item) => {
@ -380,7 +380,7 @@ class DeveloperHome extends React.PureComponent {
type: 'language',
key: item.key
});
this.handleFilterSearch({language: item.key})
this.handleFilterSearch({ language: item.key })
}
// 难度下拉
handleHardMenuClick = (item) => {
@ -388,7 +388,7 @@ class DeveloperHome extends React.PureComponent {
type: 'difficult',
key: item.key
});
this.handleFilterSearch({difficult: +item.key});
this.handleFilterSearch({ difficult: +item.key });
}
// 状态下拉
handleSatusMenuClick = (item) => {
@ -396,7 +396,7 @@ class DeveloperHome extends React.PureComponent {
type: 'status',
key: item.key
});
this.handleFilterSearch({status: +item.key});
this.handleFilterSearch({ status: +item.key });
}
// 来源下拉
handleOriginMenuClick = (item) => {
@ -406,7 +406,7 @@ class DeveloperHome extends React.PureComponent {
key: item.key
});
this.handleFilterSearch({come_from: item.key === 'all' ? '' : item.key});
this.handleFilterSearch({ come_from: item.key === 'all' ? '' : item.key });
if (item.key !== 'all') {
let _columns = this.columns.concat([this.options]);
@ -422,7 +422,7 @@ class DeveloperHome extends React.PureComponent {
handleTagClose = (info) => {
this.handleFilterSearch({[info.type]: ''});
this.handleFilterSearch({ [info.type]: '' });
// 移除 searcInfo 中的数据
const { type } = info;
let tempArr = [...this.state.searchInfo];
@ -453,14 +453,14 @@ class DeveloperHome extends React.PureComponent {
// return
// }
render () {
render() {
// const { testReducer, handleClick } = this.props;
const {
ojListReducer: {hacks_list, top_data, hacks_count},
ojListReducer: { hacks_list, top_data, hacks_count },
user,
pagination
} = this.props;
const {passed_count = 0, simple_count = 0, medium_count = 0, diff_count = 0} = top_data;
const { passed_count = 0, simple_count = 0, medium_count = 0, diff_count = 0 } = top_data;
const { columns } = this.state;
// 渲染条件内容
@ -478,13 +478,14 @@ class DeveloperHome extends React.PureComponent {
key={info.type}
onClose={() => this.handleTagClose(info)}
>{ctx}</Tag>
)});
)
});
};
// console.log('=====>>>>>>>>>.', this.props);
const newBtnStyle = user && (user.admin || (user.is_teacher && user.professional_certification) || user.business)
? { display: 'block'}
: { display: 'none'};
? { display: 'block' }
: { display: 'none' };
return (
<div className="developer-list">
<div className="ant-spin-container">
@ -494,12 +495,12 @@ class DeveloperHome extends React.PureComponent {
<div className="search-params">
<p className={'save-question'}>已解决 <span className={''}>{passed_count}</span> / {hacks_count} </p>
<div className={'question-level'}>
<MultipTags type="success" text="简单" numb={simple_count} style={{ marginRight: '20px' }}/>
<MultipTags type="warning" text="中等" numb={medium_count} style={{ marginRight: '20px' }}/>
<MultipTags type="error" text="困难" numb={diff_count}/>
<MultipTags type="success" text="简单" numb={simple_count} style={{ marginRight: '20px' }} />
<MultipTags type="warning" text="中等" numb={medium_count} style={{ marginRight: '20px' }} />
<MultipTags type="error" text="困难" numb={diff_count} />
</div>
{/* 认证的老师, 超级管理员, 运营人员可见 */}
<Button style={ newBtnStyle } type="primary" onClick={this.handleClickNew}>新建
<Button style={newBtnStyle} type="primary" onClick={this.handleClickNew}>新建
{/* <Link to="/problems/new">新建</Link> */}
</Button>
</div>
@ -508,19 +509,19 @@ class DeveloperHome extends React.PureComponent {
<div className={'filter_ctx_area'}>
<div>
<Dropdown className={'dropdonw-style'} placement="bottomLeft" overlay={this.getMenuItems('categoryMenu', this.handleCategoryMenuClick)}>
<span className={'dropdown-span'}>分类 <Icon type="down"/></span>
<span className={'dropdown-span'}>分类 <Icon type="down" /></span>
</Dropdown>
<Dropdown className={'dropdonw-style'} placement="bottomLeft" overlay={this.getMenuItems('languageMenu', this.handleLanguageMenuClick)}>
<span className={'dropdown-span'}>语言 <Icon type="down"/></span>
<span className={'dropdown-span'}>语言 <Icon type="down" /></span>
</Dropdown>
<Dropdown className={'dropdonw-style'} placement="bottomLeft" overlay={this.getMenuItems('difficultMenu', this.handleHardMenuClick)}>
<span className={'dropdown-span'}>难度 <Icon type="down"/></span>
<span className={'dropdown-span'}>难度 <Icon type="down" /></span>
</Dropdown>
<Dropdown className={'dropdonw-style'} placement="bottomLeft" overlay={this.getMenuItems('statusMenu', this.handleSatusMenuClick)}>
<span className={'dropdown-span'}>状态 <Icon type="down"/></span>
<span className={'dropdown-span'}>状态 <Icon type="down" /></span>
</Dropdown>
<Dropdown className={'dropdonw-style'} placement="bottomLeft" overlay={this.getMenuItems('come_fromMenu', this.handleOriginMenuClick)}>
<span className={'dropdown-span'}>来源 <Icon type="down"/></span>
<span className={'dropdown-span'}>来源 <Icon type="down" /></span>
</Dropdown>
</div>
@ -535,7 +536,7 @@ class DeveloperHome extends React.PureComponent {
/>
</div>
<Card bordered={false} style={{ marginTop: '2px'}}>
<Card bordered={false} style={{ marginTop: '2px' }}>
<Table
columns={columns}
rowKey={record => Math.random()}
@ -585,5 +586,5 @@ const mapDispatchToProps = (dispatch) => ({
export default withRouter(connect(
mapStateToProps,
mapDispatchToProps
)(CNotificationHOC() (DeveloperHome)));
)(CNotificationHOC()(DeveloperHome)));
// export default DeveloperHome;

@ -6,7 +6,7 @@
* @LastEditors : tangjiang
* @LastEditTime : 2020-01-20 17:42:06
*/
import './index.scss';
import './index.less';
import React, { useState, useRef, useEffect } from 'react';
import { Tabs, Button, Icon, notification } from 'antd';
import { connect } from 'react-redux';
@ -108,7 +108,7 @@ const ControlSetting = (props) => {
style={{ top: showTextResult ? '-267px' : 0 }}
>
{/* <i className="iconfont icon-xiajiantou icon"></i> */}
<Icon type={ showTextResult ? "down" : "up" } />
<Icon type={showTextResult ? "down" : "up"} />
</div>
<Tabs
className={classNames}
@ -161,8 +161,8 @@ const ControlSetting = (props) => {
}
const mapStateToProps = (state) => {
const {commonReducer, ojForUserReducer} = state;
const {loading, excuteState, submitLoading, showOrHideControl } = commonReducer;
const { commonReducer, ojForUserReducer } = state;
const { loading, excuteState, submitLoading, showOrHideControl } = commonReducer;
const { commitTestRecordDetail, hack, userCode } = ojForUserReducer;
return {
hack,

@ -6,11 +6,11 @@
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 22:35:14
*/
import './index.scss';
import './index.less';
import React from 'react';
import MonacoEditor from '@monaco-editor/react';
import MonacoEditor from 'react-monaco-editor';
function ErrorResult (props) {
function ErrorResult(props) {
const { detail, language } = props;
const renderError = (detail = {}) => {

@ -6,13 +6,13 @@
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 08:51:21
*/
import './index.scss';
import './index.less';
import React, { useState, useEffect } from 'react';
import { Icon } from 'antd';
import CONST from '../../../../constants';
const {reviewResult} = CONST;
function ExecResult (props) {
const { reviewResult } = CONST;
function ExecResult(props) {
const { excuteState, excuteDetail } = props;
// console.log('执行状态: ======', excuteState);
@ -25,7 +25,7 @@ function ExecResult (props) {
const renderLoading = () => (
<div className={'excute_result_area excute_flex_center'}>
<span className={'loading_ctx'}>
<Icon className={'ctx_icon'} type="loading"/>
<Icon className={'ctx_icon'} type="loading" />
<span>加载中...</span>
</span>
</div>
@ -33,7 +33,7 @@ function ExecResult (props) {
const readerLoaded = () => (
<div className={'excute_result_area excute_flex_center'}>
<span className={'loaded_ctx'}>
<Icon className={'ctx_icon'} type="loading"/>
<Icon className={'ctx_icon'} type="loading" />
<span>加载完成</span>
</span>
</div>
@ -79,7 +79,7 @@ function ExecResult (props) {
<p className={'result_info_style'}>执行用时: {`${execute_time}s`}</p>
</React.Fragment>
);
} else if (state === 4){
} else if (state === 4) {
return (
<p className={'result_info_style'}>
{/* 系统繁忙,请稍后重试 */}

@ -6,9 +6,9 @@
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-26 20:07:35
*/
import './index.scss';
import './index.less';
import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef } from 'react';
import { Form, Input} from 'antd';
import { Form, Input } from 'antd';
const FormItem = Form.Item;
const { TextArea } = Input;
@ -20,7 +20,7 @@ const { TextArea } = Input;
* onDebuggerCode: func // 点击调试代码执行函数
* }
*/
function InitTabCtx (props, ref) {
function InitTabCtx(props, ref) {
// useImperativeHandle // 让子组件只暴露一定的api给父组件
const tabRef = useRef(null);
@ -42,7 +42,7 @@ function InitTabCtx (props, ref) {
const renderText = () => (<span className={'ctx_default'}>请在这里添加测试用例点击调试代码时将从这里读取输入来测试你的代码...</span>);
// 渲染表单信息
const renderForm = () => {
const {form: { getFieldDecorator } } = props;
const { form: { getFieldDecorator } } = props;
return (
<Form className={'user_case_form'}>
<FormItem
@ -51,7 +51,7 @@ function InitTabCtx (props, ref) {
{
getFieldDecorator('input', {
rules: [
{ required: true, message: '输入值不能为空'}
{ required: true, message: '输入值不能为空' }
],
initialValue: inputValue
})(<TextArea
@ -79,7 +79,7 @@ function InitTabCtx (props, ref) {
}, [inputValue]);
const _handleTestCodeFormSubmit = (cb) => {
const {form} = props;
const { form } = props;
form.validateFields((err, values) => {
if (!err) { // 表单验证通过时,调用测试接口
cb && cb(); // 调用回调函数,切换 tab
@ -88,7 +88,7 @@ function InitTabCtx (props, ref) {
});
}
return(
return (
<div ref={tabRef}>
{renderCtx()}
</div>

@ -5,7 +5,7 @@
* @Last Modified by: tangjiang
* @Last Modified time: 2019-11-18 11:35:12
*/
import './index.scss';
import './index.less';
import React, { PureComponent } from 'react';
import { Icon, Form, Input } from 'antd';
import { connect } from 'react-redux';
@ -14,7 +14,7 @@ const FormItem = Form.Item;
const { TextArea } = Input;
const tabCtx = (ctx, props) => (<p {...props}>{ctx}</p>);
const renderUserCase = (ctx, position, props) => {
const {form: { getFieldDecorator }, testCases = []} = props;
const { form: { getFieldDecorator }, testCases = [] } = props;
const testCase = testCases[0] || {}; // 获取第一个测试用例
return (
<Form className={'user_case_form'}>
@ -25,7 +25,7 @@ const renderUserCase = (ctx, position, props) => {
{
getFieldDecorator('input', {
rules: [
{ required: true, message: '输入值不能为空'}
{ required: true, message: '输入值不能为空' }
],
initialValue: testCase.input
})(<TextArea rows={5} />)
@ -47,8 +47,8 @@ const renderUserCase = (ctx, position, props) => {
)
};
const defaultCtx = (<span className={'ctx_default'}>请在这里添加测试用例点击调试代码时将从这里读取输入来测试你的代码...</span>)
const loadingCtx = (<span className={'ctx_loading'}><Icon className={'ctx_icon'} type="loading"/>加载中...</span>);
const loadedCtx = (<span className={'ctx_loaded'}><Icon className={'ctx_icon'} type="loading"/>加载完成</span>);
const loadingCtx = (<span className={'ctx_loading'}><Icon className={'ctx_icon'} type="loading" />加载中...</span>);
const loadedCtx = (<span className={'ctx_loaded'}><Icon className={'ctx_icon'} type="loading" />加载完成</span>);
const maps = {
// default: (ctx, position) => (<p className={`tab_ctx_area tab_ctx_default pos_${position}`}>{ctx}</p>),
// loading: (ctx, position) => (<p className={`tab_ctx_area tab_ctx_loading pos_${position}`}>{ctx}</p>),
@ -74,7 +74,7 @@ class InitTabCtx extends PureComponent {
}
handleTestCodeFormSubmit = (cb) => {
const {form, debuggerCode} = this.props;
const { form, debuggerCode } = this.props;
console.log(debuggerCode);
form.validateFields((err, values) => {
if (!err) { // 表单验证通过时,调用测试接口
@ -85,26 +85,26 @@ class InitTabCtx extends PureComponent {
});
}
componentDidMount () {
const { testCases = []} = this.props;
componentDidMount() {
const { testCases = [] } = this.props;
this.setState({
status: testCases.length > 0 ? 'userCase' : 'default'
});
}
render () {
render() {
/**
* @param state 当前状态 default: 显示提示信息 init: 加载初始内容 loading: 加载中 loaded: 加载完成 final: 显示最终内容
* @param position: start | cetner | end
* @param testCase: 自定义测试用例
* @returns
*/
const { testCodeStatus} = this.props;
const { testCodeStatus } = this.props;
const { ctx, position } = this.state;
// console.log('===>>>>> 测试用例集合: ', testCases);
return(
return (
<React.Fragment>
{ maps[testCodeStatus](ctx, position, this.props) }
{maps[testCodeStatus](ctx, position, this.props)}
</React.Fragment>
)
}

@ -6,13 +6,13 @@
* @LastEditors : tangjiang
* @LastEditTime : 2020-01-07 15:46:24
*/
import './index.scss';
import './index.less';
import React, { useState, useEffect } from 'react';
import { Select, notification, Modal, Form, Input, Button } from 'antd';
const { Option } = Select;
function KnowLedge (props) {
function KnowLedge(props) {
const {
options = [], // 下拉选项
@ -150,7 +150,7 @@ function KnowLedge (props) {
return (
<React.Fragment>
<div className="knowledge-select-area">
{ renderSelect(selectOptions) }
{renderSelect(selectOptions)}
{/* 渲染下拉选择项 */}
<div className="knowledge-result">
<i
@ -158,7 +158,7 @@ function KnowLedge (props) {
className="iconfont icon-roundaddfill icon-add-knowledge"
onClick={handleAddKnowledge}
></i>
{ renderResult(selectValue) }
{renderResult(selectValue)}
</div>
</div>

@ -8,9 +8,6 @@
*/
import React, { useState } from 'react';
import { fromStore, toStore } from 'educoder';
// import { Icon } from 'antd';
// import { Select } from 'antd';
// const { Option } = Select;
const SettingDrawer = (props) => {
/**
* title: '', // 一级标题
@ -25,7 +22,7 @@ const SettingDrawer = (props) => {
return fromStore('oj_theme') || 'dark';
});
const {title, type = 'label', content = [] } = props;
const { title, type = 'label', content = [] } = props;
// 字体改变时, 方法全名: handleChangeXX, XX 为指定的类型;
const {
@ -78,11 +75,12 @@ const SettingDrawer = (props) => {
>
{opt.text}
</option>
)});
)
});
renderResult = (
<div className={'setting_desc'} key={`sel_${index}`}>
<span className={'flex_item'}>{ctx.text}</span>
<select defaultValue={defaultValue} style={{ width: '100px'}} onChange={(e) => handleSelectChange(e, ctx.type)}>
<select defaultValue={defaultValue} style={{ width: '100px' }} onChange={(e) => handleSelectChange(e, ctx.type)}>
{child}
</select>
</div>
@ -94,7 +92,7 @@ const SettingDrawer = (props) => {
return (
<React.Fragment>
<h2 className={'setting_h2'}>{title}</h2>
{ result }
{result}
</React.Fragment>
);
}

@ -5,15 +5,15 @@
* @Last Modified by: tangjiang
* @Last Modified time: 2019-11-15 17:15:27
*/
import './index.scss';
import './index.less';
import React, { PureComponent } from 'react';
const numberal = require('numeral');
export default class MultipTags extends PureComponent {
render () {
const { type = 'primary', text, numb, ...props} = this.props;
render() {
const { type = 'primary', text, numb, ...props } = this.props;
if (typeof numb !== 'number' && typeof numb !== 'string') {
throw new Error('输入的numb必须为数字或数字类型字符串.');
@ -25,10 +25,10 @@ export default class MultipTags extends PureComponent {
return (
<div className={'mul-tag-wrap'} {...props}>
<span className={`tag-txt ${type}`}>
{ text }
{text}
</span>
<span className={`tag-numb ${type}`}>
{ result }
{result}
</span>
</div>
)

@ -6,18 +6,16 @@
* @LastEditors : tangjiang
* @LastEditTime : 2020-01-02 13:59:38
*/
import './index.scss';
import './index.less';
import React, { useState, useRef, useEffect } from 'react';
import { Drawer, Tooltip, Badge } from 'antd';
import { fromStore, CNotificationHOC } from 'educoder';
import { connect } from 'react-redux';
import MonacoEditor from '@monaco-editor/react';
import MonacoEditor from 'react-monaco-editor';
import SettingDrawer from '../../components/monacoSetting';
import CONST from '../../../../constants';
import MyIcon from '../../../../common/components/MyIcon';
// import actions from '../../../../redux/actions';
const { fontSetting, opacitySetting } = CONST;
const maps = {
'c': 'main.c',
@ -26,7 +24,7 @@ const maps = {
'python': 'main.py'
};
function MyMonacoEditor (props, ref) {
function MyMonacoEditor(props, ref) {
const {
code,
@ -35,28 +33,21 @@ function MyMonacoEditor (props, ref) {
identifier,
hadCodeUpdate,
showOrHideControl,
// saveUserInputCode,
onCodeChange,
onRestoreInitialCode,
onUpdateNotice
} = props;
const [showDrawer, setShowDrawer] = useState(false); // 控制配置滑框
// const [editCode, setEditCode] = useState('');
// const [curLang, setCurLang] = useState('C');
const [fontSize, setFontSize] = useState(() => { // 字体
return +fromStore('oj_fontSize') || 14;
});
const [theme, setTheme] = useState(() => { // 主题 theme
return fromStore('oj_theme') || 'dark';
});
const [ height, setHeight ] = useState('calc(100% - 56px)');
const [height, setHeight] = useState('calc(100% - 56px)');
const editorRef = useRef(null);
// useEffect(() => {
// setEditCode(props.code || '');
// }, [props]);
useEffect(() => {
setHeight(showOrHideControl ? 'calc(100% - 378px)' : 'calc(100% - 56px)');
}, [showOrHideControl]);
@ -105,18 +96,10 @@ function MyMonacoEditor (props, ref) {
props.confirm({
title: '提示',
content: '确定要恢复代码吗?',
onOk () {
onOk() {
onRestoreInitialCode && onRestoreInitialCode();
}
})
// Modal.confirm({
// content: '确定要恢复代码吗?',
// okText: '确定',
// cancelText: '取消',
// onOk () {
// onRestoreInitialCode && onRestoreInitialCode();
// }
// })
}
const handleUpdateNotice = () => {
@ -125,37 +108,26 @@ function MyMonacoEditor (props, ref) {
}
}
// const renderRestore = identifier ? (
// <MyIcon type="iconzaicizairu" />
// ) : '';
// lex_has_save ${hadCodeUpdate} ? : ''
const _classnames = hadCodeUpdate ? `flex_strict flex_has_save` : 'flex_strict';
return (
<React.Fragment>
<div className={"monaco_editor_area"}>
<div className="code_title">
{/* 未保存时 ? '学员初始代码文件' : main.x */}
<span className='flex_strict' style={{ color: '#ddd'}}>{identifier ? language ? maps[language.toLowerCase()] : '' : '学员初始代码文件'}</span>
<span className='flex_strict' style={{ color: '#ddd' }}>{identifier ? language ? maps[language.toLowerCase()] : '' : '学员初始代码文件'}</span>
<span className={_classnames}>{hadCodeUpdate ? '已保存' : ''}</span>
{/* <Tooltip
style={{ background: 'gold' }}
className="tooltip_style"
title="通知"
placement="bottom"
> */}
<Tooltip
placement="bottom"
title="通知"
>
<Badge
className="flex_normal"
style={{ color: '#666'}}
style={{ color: '#666' }}
dot={notice}
onClick={handleUpdateNotice}
>
{/* <Icon type="bell" /> */}
<MyIcon type="iconxiaoxi1" style={{fontSize: '18px'}}/>
<MyIcon type="iconxiaoxi1" style={{ fontSize: '18px' }} />
</Badge>
</Tooltip>
<Tooltip
@ -166,7 +138,7 @@ function MyMonacoEditor (props, ref) {
className="flex_normal"
onClick={handleRestoreCode}
type="iconzaicizairu"
style={{ display: identifier ? 'inline-block' : 'none', fontSize: '18px'}}
style={{ display: identifier ? 'inline-block' : 'none', fontSize: '18px' }}
/>
{/* <span onClick={handleRestoreCode} className="flex_normal" style={{ display: identifier ? 'inline-block' : 'none'}}>{renderRestore}</span> */}
</Tooltip>
@ -174,7 +146,7 @@ function MyMonacoEditor (props, ref) {
placement="bottom"
title="设置"
>
<MyIcon className='code-icon' type="iconshezhi" onClick={handleShowDrawer} style={{fontSize: '18px'}}/>
<MyIcon className='code-icon' type="iconshezhi" onClick={handleShowDrawer} style={{ fontSize: '18px' }} />
</Tooltip>
</div>
<MonacoEditor
@ -199,7 +171,7 @@ function MyMonacoEditor (props, ref) {
onChangeFontSize={handleChangeFontSize}
onChangeTheme={handleChangeTheme}
/>
<SettingDrawer {...opacitySetting}/>
<SettingDrawer {...opacitySetting} />
</Drawer>
</React.Fragment>
)
@ -212,12 +184,6 @@ const mapStateToProps = (state) => {
}
};
// const mapDispatchToProps = (dispatch) => ({
// // saveUserInputCode: (code) => dispatch(actions.saveUserInputCode(code)),
// });
// MyMonacoEditor = React.forwardRef(MyMonacoEditor);
export default connect(
mapStateToProps,
// mapDispatchToProps
)(CNotificationHOC() (MyMonacoEditor));
)(CNotificationHOC()(MyMonacoEditor));

@ -0,0 +1,79 @@
.monaco_editor_area {
height: 100%;
background-color: rgba(7, 15, 25, 1);
.code_title {
display: flex;
align-items: center;
background-color: rgba(18, 28, 36, 1);
color: #fff;
height: 56px;
padding: 0 20px;
.flex_strict {
flex: 1;
}
.flex_normal {
color: #E51C24;
cursor: pointer;
margin-right: 20px;
}
.code-icon {
cursor: pointer;
}
.flex_strict,
.flex_normal,
.code-icon {
color: #666;
}
}
}
.setting_drawer {
.ant-drawer-close {
color: #ffffff;
}
.ant-drawer-content {
top: 120px;
bottom: 56px;
height: calc(100vh - 176px);
// background: #333333;
background: rgba(7, 15, 25, 1);
color: #fff;
.setting_h2 {
color: #fff;
}
select {
color: #fff;
background: #222222;
height: 24px;
// line-height: 24px;
margin-top: 4px;
}
select option {
background: gold;
color: #fff;
}
}
}
.flex_has_save {
animation-name: blink;
animation-duration: .4s;
animation-iteration-count: 3;
}
@keyframes blink {
50% {
color: #fff;
}
}

@ -1,96 +0,0 @@
.monaco_editor_area{
height: 100%;
background-color: rgba(7,15,25,1);
.code_title{
display: flex;
align-items: center;
background-color: rgba(18,28,36,1);
color: #fff;
height: 56px;
padding: 0 20px;
.flex_strict{
flex: 1;
}
.flex_normal{
color: #E51C24;
cursor: pointer;
margin-right: 20px;
}
.code-icon{
cursor: pointer;
}
.flex_strict,
.flex_normal,
.code-icon{
color: #666;
}
}
// .margin,
// .margin-view-overlays,
// .current-line{
// width: 40px !important;
// }
// .monaco-editor .margin-view-overlays .line-numbers{
// text-align: center;
// }
// .monaco-scrollable-element{
// left: 40px !important;
// }
}
.setting_drawer{
.ant-drawer-close{
color: #ffffff;
}
.ant-drawer-content{
top: 120px;
bottom: 56px;
height: calc(100vh - 176px);
// background: #333333;
background: rgba(7,15,25,1);
color: #fff;
.setting_h2{
color: #fff;
}
select{
color: #fff;
background: #222222;
height: 24px;
// line-height: 24px;
margin-top: 4px;
}
select option{
background: gold;
color: #fff;
}
}
}
.flex_has_save{
// animation: blink 3s line 3;
animation-name: blink;
animation-duration: .4s;
animation-iteration-count: 3;
}
// .monaco-editor, .monaco-editor-background, .monaco-editor .inputarea.ime-input,
// .monaco-editor .margin,
// .minimap slider-mouseover,
// .minimap-decorations-layer{
// background:rgba(3,19,40,1) !important;
// }
@keyframes blink{
50% {
color: #fff;
}
}
.monaco-editor, .monaco-editor-background, .monaco-editor .inputarea.ime-input,
.monaco-editor .margin,
.minimap .minimap-decorations-layer{
background-color: transparent !important;
}

@ -1,48 +0,0 @@
/*
* @Description:
* @Author: tangjiang
* @Github:
* @Date: 2019-12-27 19:18:09
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-27 19:19:23
*/
import React, { useState } from 'react';
import Editor from "@monaco-editor/react";
function App() {
const [theme, setTheme] = useState("light");
const [language, setLanguage] = useState("javascript");
const [isEditorReady, setIsEditorReady] = useState(false);
function handleEditorDidMount() {
setIsEditorReady(true);
}
function toggleTheme() {
setTheme(theme === "light" ? "dark" : "light");
}
function toggleLanguage() {
setLanguage(language === "javascript" ? "python" : "javascript");
}
return (
<React.Fragment>
<LinkToRepo />
<button onClick={toggleTheme} disabled={!isEditorReady}>
Toggle theme
</button>
<button onClick={toggleLanguage} disabled={!isEditorReady}>
Toggle language
</button>
<Editor
height="calc(100% - 19px)" // By default, it fully fits with its parent
theme={theme}
language={language}
value={'c'}
editorDidMount={handleEditorDidMount}
/>
</React.Fragment>
);
}

@ -6,7 +6,7 @@
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-25 10:02:03
*/
import './index.scss';
import './index.less';
import React from 'react';
// import { Icon } from 'antd';
const numberal = require('numeral');

@ -6,15 +6,15 @@
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-09 17:36:55
*/
import './index.scss';
import './index.less';
import React from 'react';
import { getImageUrl } from 'educoder'
function UserInfo (props) {
const {image_url, name} = props.userInfo;
function UserInfo(props) {
const { image_url, name } = props.userInfo;
return (
<div className={'avator_nicker'}>
<img style={{ display: image_url ? 'inline-block' : 'none'}} alt="用户头像" className={'student_img'} src={getImageUrl(`images/${image_url}` || 'images/educoder/headNavLogo.png?1526520218')} />
<img style={{ display: image_url ? 'inline-block' : 'none' }} alt="用户头像" className={'student_img'} src={getImageUrl(`images/${image_url}` || 'images/educoder/headNavLogo.png?1526520218')} />
<span className={'student_nicker'}>
{name || ''}
</span>

@ -5,7 +5,7 @@
* @Last Modified by: tangjiang
* @Last Modified time: 2019-11-19 23:23:41
*/
import './index.scss';
import './index.less';
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import SplitPane from 'react-split-pane';// import { Form } from 'antd';
@ -69,7 +69,7 @@ const NewOrEditTask = (props) => {
// 清空store中的测试用例集合
// props.clearOJFormStore();
}
return () => {}
return () => { }
}, []);
// 模拟挑战
@ -108,7 +108,7 @@ const NewOrEditTask = (props) => {
props.confirm({
title: '提示',
content: (<p>发布后即可应用到自己管理的课堂<br /> 是否确认发布?</p>),
onOk () {
onOk() {
changePublishLoadingStatus(true);
handlePublish(props, 'publish');
}
@ -123,7 +123,7 @@ const NewOrEditTask = (props) => {
props.confirm({
title: '提示',
content: ((<p>是否确认撤销发布?</p>)),
onOk () {
onOk() {
changePublishLoadingStatus(true);
handleCancelPublish(props, identifier);
}
@ -208,9 +208,9 @@ const NewOrEditTask = (props) => {
return (
<div className={'new_add_task_wrap'}>
<div className={'task_header'}>
<UserInfo userInfo={userInfo}/>
<UserInfo userInfo={userInfo} />
<p className={'header_title'}>{props.name || ''}</p>
{ renderQuit() }
{renderQuit()}
</div>
<div className="split-pane-area">
<SplitPane className='outer-split-pane' split="vertical" minSize={350} maxSize={-350} defaultSize="40%">
@ -218,7 +218,7 @@ const NewOrEditTask = (props) => {
<LeftPane />
</div>
<SplitPane split="vertical" defaultSize="100%" allowResize={false}>
<RightPane onSubmitForm={handleSubmitForm}/>
<RightPane onSubmitForm={handleSubmitForm} />
<div />
</SplitPane>
</SplitPane>
@ -229,7 +229,7 @@ const NewOrEditTask = (props) => {
/* 录入时: 取消 保存 */
/* 保存未发布: 立即发布 模拟挑战 */
}
{ !identifier ? renderSaveOrCancel() : renderPubOrFight() }
{!identifier ? renderSaveOrCancel() : renderPubOrFight()}
</div>
</div>
)
@ -284,4 +284,4 @@ const mapDispatchToProps = (dispatch) => ({
export default withRouter(connect(
mapStateToProps,
mapDispatchToProps
)(CNotificationHOC() (NewOrEditTask)));
)(CNotificationHOC()(NewOrEditTask)));

@ -1,4 +1,4 @@
@import '../split_pane_resizer.scss';
@import '../split_pane_resizer.less';
.new_add_task_wrap {
.split-pane-area{

@ -6,12 +6,12 @@
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 10:37:41
*/
import './index.scss';
import './index.less';
import React from 'react';
import { Collapse, Icon, Input, Form } from 'antd';
import { connect } from 'react-redux';
import actions from '../../../../../redux/actions';
import { CNotificationHOC} from 'educoder';
import { CNotificationHOC } from 'educoder';
const { Panel } = Collapse;
const { TextArea } = Input;
const FormItem = Form.Item;
@ -141,19 +141,19 @@ const AddTestDemo = (props) => {
// 切换手风琴
const handleChangeCollapse = () => {
const {index, updateOpenTestCaseIndex} = props;
const { index, updateOpenTestCaseIndex } = props;
updateOpenTestCaseIndex(index);
}
return (
<Collapse className={'collapse_area'} activeKey={isOpen?'1':''} onChange={() => handleChangeCollapse()}>
<Collapse className={'collapse_area'} activeKey={isOpen ? '1' : ''} onChange={() => handleChangeCollapse()}>
<Panel header={`测试用例${props.index + 1}`} extra={genExtra()} key="1">
<Form>
<FormItem
label={<span className={'label_text'}>输入</span>}
validateStatus={testCaseValidate.input.validateStatus}
help={testCaseValidate.input.errMsg}
colon={ false }
colon={false}
>
<TextArea
rows={5}
@ -166,7 +166,7 @@ const AddTestDemo = (props) => {
label={<span className={'label_text'}>输出</span>}
validateStatus={testCaseValidate.output.validateStatus}
help={testCaseValidate.output.errMsg}
colon={ false }
colon={false}
>
<TextArea
rows={5}
@ -183,7 +183,7 @@ const AddTestDemo = (props) => {
}
const mapStateToProps = (state) => {
const {identifier, loading} = state.ojFormReducer;
const { identifier, loading } = state.ojFormReducer;
// console.log(state.ojFormReducer);
return {
identifier,

@ -6,7 +6,7 @@
* @LastEditors : tangjiang
* @LastEditTime : 2020-02-05 13:26:58
*/
import './index.scss';
import './index.less';
// import 'katex/dist/katex.css';
import React from 'react';
import { Form, Input, Select, InputNumber, Button, Cascader, notification } from 'antd';
@ -20,7 +20,7 @@ import { toStore } from 'educoder'; // 保存和读取store值
import QuillForEditor from '../../../../../common/quillForEditor';
import KnowLedge from '../../../components/knowledge';
const scrollIntoView = require('scroll-into-view');
const {jcLabel} = CONST;
const { jcLabel } = CONST;
const FormItem = Form.Item;
const { Option } = Select;
const maps = {
@ -34,13 +34,13 @@ const maps = {
difficult: [
{ title: (<span style={{ color: 'rgba(0, 0, 0, 0.35)' }}>请选择</span>), key: '' },
{ title: '简单', key: '1' },
{ title: '中等', key: '2'},
{ title: '中等', key: '2' },
{ title: '困难', key: '3' }
],
category: [
{ title: (<span style={{ color: 'rgba(0, 0, 0, 0.35)' }}>请选择</span>), key: '' },
{ title: '程序设计', key: '1' },
{ title: '算法', key: '2'}
{ title: '算法', key: '2' }
],
openOrNot: [
{ title: '公开', key: '1' },
@ -49,7 +49,7 @@ const maps = {
}
class EditTab extends React.Component {
constructor (props) {
constructor(props) {
super(props);
// this.editorRef = React.createRef();
this.scrollRef = React.createRef();
@ -67,7 +67,7 @@ class EditTab extends React.Component {
}
}
componentDidMount () {
componentDidMount() {
const oWrap = document.getElementById('textCase');
const scrollHeight = oWrap.offsetHeight;
@ -91,7 +91,7 @@ class EditTab extends React.Component {
// console.log(nextProp);
// }
componentWillUnmount (nextPro) {
componentWillUnmount(nextPro) {
this.state.scrollEl.removeEventListener('scroll', this.handleScroll, false);
}
@ -101,12 +101,12 @@ class EditTab extends React.Component {
const tOffsetTop = oTarget.offsetTop;
const tOffsetHeight = oTarget.offsetHeight;
const scrollTop = e.target.scrollTop;
const { scrollHeight, offsetTop} = this.state;
const { scrollHeight, offsetTop } = this.state;
// 滚动距离 + 元素的高度 大于 offsetTop值时 添加 fix_top 样式
// console.log(tOffsetTop, tOffsetHeight, scrollTop, scrollHeight, offsetTop);
if ((scrollTop + tOffsetHeight > tOffsetTop) && (tOffsetTop >= offsetTop)) {
oTarget.className = `test_demo_title fix_top`;
} else if ((scrollHeight + scrollTop < offsetTop) && (scrollHeight <= offsetTop)){
} else if ((scrollHeight + scrollTop < offsetTop) && (scrollHeight <= offsetTop)) {
oTarget.className = `test_demo_title`;
} else if ((tOffsetTop < offsetTop) && (tOffsetTop + tOffsetHeight + scrollTop) < offsetTop) {
oTarget.className = `test_demo_title`;
@ -169,7 +169,7 @@ class EditTab extends React.Component {
scrollIntoView(this.scrollRef.current);
}
render () {
render() {
const { showAdd } = this.state;
const {
@ -236,7 +236,7 @@ class EditTab extends React.Component {
};
// 添加测试用例
const handleAddTest = () => {
const {position, testCases = []} = this.props;
const { position, testCases = [] } = this.props;
if (testCases.length >= 50) {
notification.warning({
message: '提示',
@ -262,7 +262,7 @@ class EditTab extends React.Component {
}
// this.scrollRef.current.scrollTo(1000);
addTestCase({testCase: obj, tcValidate: validateObj});
addTestCase({ testCase: obj, tcValidate: validateObj });
// TODO 点击新增时,需要滚到到最底部
this.scrollToBottom();
}
@ -281,12 +281,12 @@ class EditTab extends React.Component {
}
// 编辑器配置信息
const quillConfig = [
{ header: 1}, {header: 2},
{ header: 1 }, { header: 2 },
// {size: ['12px', '14px', '16px', '18px', '20px', false]},
'bold', 'italic', 'underline', 'strike', // 切换按钮
'blockquote', 'code-block', // 代码块
{align: []}, { 'list': 'ordered' }, { 'list': 'bullet' }, // 列表
{ 'script': 'sub'}, { 'script': 'super' },
{ align: [] }, { 'list': 'ordered' }, { 'list': 'bullet' }, // 列表
{ 'script': 'sub' }, { 'script': 'super' },
{ 'color': [] }, { 'background': [] }, // 字体颜色与背景色
// {font: []},
'image', 'formula', // 数学公式、图片、视频
@ -297,7 +297,7 @@ class EditTab extends React.Component {
const renderCourseQuestion = (arrs) => {
const tempArr = [];
const sub_id = this.props.ojForm.sub_discipline_id;
function loop (arrs, tempArr) {
function loop(arrs, tempArr) {
arrs.forEach(item => {
const obj = {};
obj.value = item.id;
@ -341,7 +341,7 @@ class EditTab extends React.Component {
}
// 知识点
const handleKnowledgeChange = (values= []) => {
const handleKnowledgeChange = (values = []) => {
const _result = [];
values.forEach(v => {
_result.push(v.id);
@ -355,8 +355,8 @@ class EditTab extends React.Component {
const handleAddKnowledge = (values) => {
// console.log('调用了新增知识点并返回了结果: ', values);
// 获取课程id
const {sub_discipline_id} = this.props.ojForm;
const obj = Object.assign({}, values, {sub_discipline_id})
const { sub_discipline_id } = this.props.ojForm;
const obj = Object.assign({}, values, { sub_discipline_id })
tagDisciplines(obj);
}
@ -368,7 +368,7 @@ class EditTab extends React.Component {
label={<span>{myLabel(jcLabel['difficult'])}</span>}
validateStatus={ojFormValidate.difficult.validateStatus}
help={ojFormValidate.difficult.errMsg}
colon={ false }
colon={false}
>
<Select onChange={this.handleChangeDifficult} value={`${ojForm.difficult}`}>
{getOptions('difficult')}
@ -380,7 +380,7 @@ class EditTab extends React.Component {
label={<span>{myLabel(jcLabel['sub_discipline_id'], '合理的课程分类有利于快速检索')}</span>}
validateStatus={ojFormValidate.sub_discipline_id.validateStatus}
help={ojFormValidate.sub_discipline_id.errMsg}
colon={ false }
colon={false}
>
{/* <Select onChange={this.handleChangeCategory} value={`${ojForm.category}`}>
{getOptions('category')}
@ -390,11 +390,11 @@ class EditTab extends React.Component {
expandTrigger="hover"
onChange={this.handleChangeCategory}
/> */}
{ renderCourseQuestion(courseQuestions)}
{renderCourseQuestion(courseQuestions)}
</FormItem>
<FormItem
colon={ false }
colon={false}
className='input_area flex_100'
label={<span>{myLabel(jcLabel['knowledge'], '', 'nostar')}</span>}
>
@ -412,9 +412,9 @@ class EditTab extends React.Component {
label={<span>{myLabel(jcLabel['timeLimit'], '程序允许时间限制时长,单位:秒')}</span>}
validateStatus={ojFormValidate.timeLimit.validateStatus}
help={ojFormValidate.timeLimit.errMsg}
colon={ false }
colon={false}
>
<InputNumber value={ojForm.timeLimit} min={0} max={5} style={{ width: '100%' }} onChange={this.handleTimeLimitChange}/>
<InputNumber value={ojForm.timeLimit} min={0} max={5} style={{ width: '100%' }} onChange={this.handleTimeLimitChange} />
</FormItem>
<FormItem
@ -422,7 +422,7 @@ class EditTab extends React.Component {
label={<span>{myLabel(jcLabel['language'])}</span>}
validateStatus={ojFormValidate.language.validateStatus}
help={ojFormValidate.language.errMsg}
colon={ false }
colon={false}
>
<Select onChange={this.handleLanguageChange} value={`${ojForm.language}`}>
{getOptions('language')}
@ -434,7 +434,7 @@ class EditTab extends React.Component {
label={<span>{myLabel(jcLabel['name'])}</span>}
validateStatus={ojFormValidate.name.validateStatus}
help={ojFormValidate.name.errMsg}
colon={ false }
colon={false}
>
<Input
maxLength={60}
@ -450,7 +450,7 @@ class EditTab extends React.Component {
label={<span>{myLabel(jcLabel['description'])}</span>}
validateStatus={ojFormValidate.description.validateStatus}
help={ojFormValidate.description.errMsg}
colon={ false }
colon={false}
>
<QuillForEditor
autoFocus={true}
@ -482,10 +482,10 @@ class EditTab extends React.Component {
<Button type="primary" ghost onClick={handleAddTest}>添加测试用例</Button>
</div>
<div className="test_demo_ctx">
{ renderTestCase() }
{renderTestCase()}
</div>
<div style={ {float:"left", clear: "both", background: 'red' } } ref={this.scrollRef}></div>
<div style={{ float: "left", clear: "both", background: 'red' }} ref={this.scrollRef}></div>
</div>
)
}

@ -9,7 +9,7 @@
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.bubble.css';
import 'quill/dist/quill.snow.css';
import './index.scss';
import './index.less';
import React, { useState, useImperativeHandle, useRef, useEffect } from 'react';
import { Form, Input, InputNumber, Button, Select } from 'antd';
import { connect } from 'react-redux';
@ -18,7 +18,7 @@ import QuillEditor from '../../../quillEditor';
import actions from '../../../../../redux/actions';
import CONST from '../../../../../constants';
const {jcLabel} = CONST;
const { jcLabel } = CONST;
const { Option } = Select;
const FormItem = Form.Item;
@ -31,12 +31,12 @@ const maps = {
],
difficult: [
{ title: '简单', key: '1' },
{ title: '中等', key: '2'},
{ title: '中等', key: '2' },
{ title: '困难', key: '3' }
],
category: [
{ title: '程序设计', key: '1' },
{ title: '算法', key: '2'}
{ title: '算法', key: '2' }
],
openOrNot: [
{ title: '公开', key: '1' },
@ -44,7 +44,7 @@ const maps = {
]
}
function EditTab (props, ref) {
function EditTab(props, ref) {
const {
form,
@ -89,7 +89,7 @@ function EditTab (props, ref) {
};
// 向外暴露的方法
useImperativeHandle(ref, () => ({
validateForm () {
validateForm() {
props.form.validateFields((err, values) => {
if (!err) {
getFormData(() => {
@ -119,7 +119,7 @@ function EditTab (props, ref) {
errMsg: ''
}
}
addTestCase({testCase: obj, tcValidate: validateObj});
addTestCase({ testCase: obj, tcValidate: validateObj });
// TODO 点击新增时,需要滚到到最底部
// this.editorRef.current.scrollTop
// const oDiv = this.editorRef.current;
@ -185,7 +185,7 @@ function EditTab (props, ref) {
{ required: true, message: '任务名称不能为空' }
],
initialValue: ojForm.name
})(<Input placeholder="请输入任务名称"/>)
})(<Input placeholder="请输入任务名称" />)
}
</FormItem>
@ -299,7 +299,7 @@ function EditTab (props, ref) {
<Button type="primary" onClick={handleAddTest}>添加测试用例</Button>
</div>
<div className="test_demo_ctx">
{ renderTestCase() }
{renderTestCase()}
</div>
</div>
);
@ -307,7 +307,7 @@ function EditTab (props, ref) {
const mapStateToProps = (state) => {
const ojFormReducer = state.ojFormReducer;
const {ojForm, position, testCases, testCasesValidate} = ojFormReducer;
const { ojForm, position, testCases, testCasesValidate } = ojFormReducer;
return {
ojForm,
testCases,

@ -6,7 +6,7 @@
* @Last Modified time: 2019-11-19 19:07:02
*/
import './index.scss';
import './index.less';
import React, { useState, useMemo } from 'react';
// import { Tabs } from 'antd';
import EditorTab from './editorTab';
@ -14,7 +14,7 @@ import PrevTab from './prevTab';
// const { TabPane } = Tabs;
function LeftPane (props) {
function LeftPane(props) {
const navItem = [
{
@ -56,10 +56,10 @@ function LeftPane (props) {
// </Tabs>
<React.Fragment>
<ul className={'add_editor_list_area'}>
{ renderNavItem }
{renderNavItem}
</ul>
<div className="comp_ctx" style={{ height: 'calc(100vh - 177px)' }}>
{ renderComp }
{renderComp}
</div>
</React.Fragment>
)

@ -6,10 +6,10 @@
* @LastEditors: tangjiang
* @LastEditTime: 2019-12-18 10:02:24
*/
import './index.scss';
import './index.less';
import React, { useEffect, useState, useRef } from 'react';
import { connect } from 'react-redux';
import {Empty} from 'antd';
import { Empty } from 'antd';
// import Wrapper from '../../../../../common/reactQuill';
import QuillForEditor from '../../../../../common/quillForEditor';
@ -25,7 +25,7 @@ const PrevTab = (props) => {
setRenderCtx(() => (
<div
id="quill_editor"
style = {{ height: '100%', width: '100%'}}
style={{ height: '100%', width: '100%' }}
ref={prevRef}>
<QuillForEditor
readOnly={true}

@ -6,14 +6,14 @@
* @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 19:33:50
*/
import './index.scss';
import './index.less';
import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import MyMonacoEditor from '../../components/myMonacoEditor';
// import ControlSetting from '../../components/controlSetting';
import actions from '../../../../redux/actions';
function RightPane (props, ref) {
function RightPane(props, ref) {
const {
// identifier,
@ -48,7 +48,7 @@ function RightPane (props, ref) {
<MyMonacoEditor
language={language}
code={showCode}
onCodeChange={handleCodeChange}/>
onCodeChange={handleCodeChange} />
{/* <ControlSetting
// identifier={identifier}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save