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", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@icedesign/base": "^0.2.5", "@material-ui/core": "^4.9.4",
"@monaco-editor/react": "^2.3.0",
"@novnc/novnc": "^1.1.0", "@novnc/novnc": "^1.1.0",
"antd": "^3.23.2", "antd": "^3.23.2",
"array-flatten": "^2.1.2", "axios": "^0.19.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",
"bizcharts": "^3.5.5", "bizcharts": "^3.5.5",
"bundle-loader": "^0.5.6",
"case-sensitive-paths-webpack-plugin": "2.1.1",
"chalk": "1.1.3", "chalk": "1.1.3",
"classnames": "^2.2.5", "classnames": "^2.2.5",
"clipboard": "^2.0.4", "clipboard": "^2.0.4",
"codemirror": "^5.46.0", "codemirror": "^5.52.0",
"connected-react-router": "4.4.1",
"css-loader": "0.28.7",
"dotenv": "4.0.0",
"dotenv-expand": "4.2.0",
"echarts": "^4.2.0-rc.2", "echarts": "^4.2.0-rc.2",
"editor.md": "^1.5.0", "editor.md": "^1.5.0",
"eslint": "4.10.0", "immutability-helper": "^3.0.1",
"eslint-config-react-app": "^2.1.0", "js-base64": "^2.5.2",
"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",
"katex": "^0.11.1", "katex": "^0.11.1",
"lodash": "^4.17.5", "lodash": "^4.17.5",
"loglevel": "^1.6.1", "loglevel": "^1.6.1",
"material-ui": "^1.0.0-beta.40",
"md5": "^2.2.1", "md5": "^2.2.1",
"moment": "^2.23.0", "moment": "^2.23.0",
"monaco-editor": "^0.15.6", "monaco-editor": "^0.20.0",
"monaco-editor-webpack-plugin": "^1.7.0", "monaco-editor-webpack-plugin": "^1.9.0",
"npm": "^6.10.1",
"numeral": "^2.0.6", "numeral": "^2.0.6",
"object-assign": "4.1.1", "object-assign": "4.1.1",
"postcss-flexbugs-fixes": "3.2.0",
"postcss-loader": "2.0.8",
"promise": "8.0.1", "promise": "8.0.1",
"prop-types": "^15.6.1", "prop-types": "^15.6.1",
"qs": "^6.6.0", "qs": "^6.6.0",
"quill": "^1.3.7", "quill": "^1.3.7",
"quill-delta-to-html": "^0.11.0", "quill-delta-to-html": "^0.11.0",
"raf": "3.4.0", "react": "^16.12.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-beautiful-dnd": "^10.0.4", "react-beautiful-dnd": "^10.0.4",
"react-codemirror": "^1.0.0",
"react-codemirror2": "^6.0.0", "react-codemirror2": "^6.0.0",
"react-content-loader": "^3.1.1", "react-content-loader": "^3.1.1",
"react-cookie": "^4.0.3",
"react-cookies": "^0.1.1", "react-cookies": "^0.1.1",
"react-dev-utils": "^5.0.0", "react-dom": "^16.12.0",
"react-dom": "^16.9.0",
"react-hot-loader": "^4.0.0",
"react-infinite-scroller": "^1.2.4", "react-infinite-scroller": "^1.2.4",
"react-loadable": "^5.3.1", "react-loadable": "^5.3.1",
"react-monaco-editor": "^0.25.1", "react-monaco-editor": "^0.34.0",
"react-player": "^1.11.1", "react-player": "^1.11.1",
"react-redux": "5.0.7", "react-redux": "5.0.7",
"react-router": "^4.2.0", "react-router": "^5.1.2",
"react-router-dom": "^4.2.2", "react-router-dom": "^5.1.2",
"react-scripts": "3.4.0",
"react-split-pane": "^0.1.89", "react-split-pane": "^0.1.89",
"react-url-query": "^1.4.0", "react-url-query": "^1.4.0",
"redux": "^4.0.0", "redux": "^4.0.0",
"redux-thunk": "2.3.0", "redux-thunk": "^2.3.0",
"rsuite": "^4.0.1", "rsuite": "^4.0.1",
"sass-loader": "7.3.1",
"scroll-into-view": "^1.12.3", "scroll-into-view": "^1.12.3",
"showdown": "^1.9.1",
"store": "^2.0.12", "store": "^2.0.12",
"style-loader": "0.19.0", "styled-components": "^5.0.1",
"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",
"whatwg-fetch": "2.0.3", "whatwg-fetch": "2.0.3",
"wrap-md-editor": "^0.2.20" "wrap-md-editor": "^0.2.20"
}, },
"scripts": { "scripts": {
"start": "node --max_old_space_size=15360 scripts/start.js", "start": "PORT=3007 react-app-rewired start",
"build": "node --max_old_space_size=15360 scripts/build.js", "build": "react-app-rewired build ",
"concat": "node scripts/concat.js", "test": "react-scripts test",
"gen_stats": "NODE_ENV=production webpack --profile --config=./config/webpack.config.prod.js --json > stats.json", "eject": "react-scripts eject"
"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"
}, },
"jest": { "eslintConfig": {
"collectCoverageFrom": [ "extends": "react-app"
"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"
}, },
"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": { "devDependencies": {
"@babel/runtime": "7.0.0-beta.51", "babel-plugin-import": "^1.13.0",
"babel-plugin-import": "^1.11.0", "customize-cra": "^0.5.0",
"compression-webpack-plugin": "^1.1.12", "less": "^3.11.1",
"concat": "^1.0.3", "less-loader": "^5.0.0",
"happypack": "^5.0.1", "react-app-rewired": "^2.1.5",
"mockjs": "^1.1.0", "uglifyjs-webpack-plugin": "^2.2.0",
"node-sass": "^4.12.0", "webpack-bundle-analyzer": "^3.6.0"
"reqwest": "^2.0.5",
"webpack-bundle-analyzer": "^3.0.3",
"webpack-parallel-uglify-plugin": "^1.1.0"
} }
} }

@ -1,51 +1,33 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<head>
<meta charset="utf-8"> <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=”EduCoder,信息技术实践教学,精品课程网,慕课MOOC″>
<meta name=”Keywords” Content=”实践课程,项目实战,java实训,python实战,人工智能技术,后端开发学习,移动开发入门″> <meta name=”Keywords” Content=”实践课程,项目实战,java实训,python实战,人工智能技术,后端开发学习,移动开发入门″>
<meta name=”Keywords” Content=”翻转课堂,高效课堂创建,教学模式″> <meta name=”Keywords” Content=”翻转课堂,高效课堂创建,教学模式″>
<meta name=”Keywords” Content=”实训项目,python教程,C语言入门,java书,php后端开发,app前端开发,数据库技术″> <meta name=”Keywords” Content=”实训项目,python教程,C语言入门,java书,php后端开发,app前端开发,数据库技术″>
<meta name=”Keywords” Content=”在线竞赛,计算机应用大赛,编程大赛,大学生计算机设计大赛,全国高校绿色计算机大赛″> <meta name=”Keywords” Content=”在线竞赛,计算机应用大赛,编程大赛,大学生计算机设计大赛,全国高校绿色计算机大赛″>
<meta name=”Description” Content=”EduCoder是信息技术类实践教学平台。EduCoder涵盖了计算机、大数据、云计算、人工智能、软件工程、物联网等专业课程。超10000个实训案例及22000个技能评测点建立学、练、评、测一体化实验环境。”> <meta name=”Description”
<meta name=”Description” Content=”EduCoder实践课程旨在于通过企业级实战实训案例帮助众多程序员提升各项业务能力。解决学生、学员、企业员工等程序设计能力、算法设计能力、问题求解能力、应用开发能力、系统运维能力等。”> 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=”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="viewport" id="viewport" content="width=device-width, initial-scale=0.3, maximum-scale=0.3">
<meta name="theme-color" content="#000000"> <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="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"> <script type="text/javascript">
window.__isR = true; window.__isR = true;
// 不支持ie9 ie10 // 不支持ie9 ie10
if ( if (
( navigator.userAgent.indexOf('MSIE 9') != -1 (navigator.userAgent.indexOf('MSIE 9') != -1
|| navigator.userAgent.indexOf('MSIE 10') != -1 ) || navigator.userAgent.indexOf('MSIE 10') != -1)
&& &&
location.pathname.indexOf("/compatibility") == -1) { location.pathname.indexOf("/compatibility") == -1) {
debugger; debugger;
@ -59,39 +41,8 @@
} }
</script> </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="/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配置--> <!--需要去build js配置-->
<link rel="stylesheet" type="text/css" href="/css/iconfont.css"> <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"> <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; user-select: none;
</style> </style>
</head> </head>
<body>
<body>
<noscript> <noscript>
You need to enable JavaScript to run this app. You need to enable JavaScript to run this app.
</noscript> </noscript>
<!--用于markdown转html -->
<div id="md_div" style="display: none;"></div> <div id="md_div" style="display: none;"></div>
<div id="root" class="page -layout-v -fit widthunit"> <div id="root" class="page -layout-v -fit widthunit"></div>
<!--<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="picture_display" style="display: none;"></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/marked.min.js"></script>
<script type="text/javascript" src="/js/editormd/prettify.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/sequence-diagram.min.js"></script>
<script type="text/javascript" src="/js/editormd/flowchart.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> <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/codemirror.js"></script>
<script type="text/javascript" src="/js/codemirror/mode/javascript.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/merge.js"></script>
<script type="text/javascript" src="/js/edu_tpi.js"></script> <script type="text/javascript" src="/js/edu_tpi.js"></script>
-->
<!-- testbdweb.trustie.net testbdweb.educoder.net -->
<!-- 在tpi js里加载这3个脚本 -->
<script> <script>
(function() { // Scoping function to avoid globals (function () { // Scoping function to avoid globals
var href = location.href; var href = location.href;
if(window.location.port === "3007"){ if (window.location.port === "3007") {
if (href.indexOf('/tasks/') != -1) { if (href.indexOf('/tasks/') != -1) {
document.write('<script type="text/javascript" src="https://newweb.educoder.net/assets/kindeditor/kindeditor.js"><\/script>'); document.write('<script type="text/javascript" src="https://newweb.educoder.net/assets/kindeditor/kindeditor.js"><\/script>');
// build.js中会将这个url附加一个前缀 react/build // 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>'); document.write('<script type="text/javascript" src="https://newweb.educoder.net/javascripts/educoder/edu_application.js"><\/script>');
} }
}else{ } else {
if (href.indexOf('/tasks/') != -1) { if (href.indexOf('/tasks/') != -1) {
document.write('<script type="text/javascript" src="/assets/kindeditor/kindeditor.js"><\/script>'); document.write('<script type="text/javascript" src="/assets/kindeditor/kindeditor.js"><\/script>');
// build.js中会将这个url附加一个前缀 react/build // 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://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 type="text/javascript" src="https://cdn.bootcss.com/quill/1.3.7/quill.core.min.js"></script>
<!-- <script>--> </body>
<!-- document.body.addEventListener('touchmove', function (e) {-->
<!-- e.preventDefault(); //阻止默认的处理方式(阻止下拉滑动的效果)-->
<!-- }, {passive: false});-->
<!-- </script>-->
</body>
</html> </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 './public-path';
import logo from './logo.svg'; import { ConfigProvider } from 'antd'
import './App.css';
import {ConfigProvider} from 'antd'
import zhCN from 'antd/lib/locale-provider/zh_CN'; import zhCN from 'antd/lib/locale-provider/zh_CN';
import { import {
BrowserRouter as Router, BrowserRouter as Router,
@ -10,9 +8,6 @@ import {
Switch Switch
} from 'react-router-dom'; } from 'react-router-dom';
import axios from 'axios'; import axios from 'axios';
import '@icedesign/base/dist/ICEDesignBase.css';
import '@icedesign/base/index.scss';
import LoginDialog from './modules/login/LoginDialog'; import LoginDialog from './modules/login/LoginDialog';
import Notcompletedysl from './modules/user/Notcompletedysl'; import Notcompletedysl from './modules/user/Notcompletedysl';
@ -21,45 +16,21 @@ import Trialapplicationreview from './modules/user/Trialapplicationreview';
import Addcourses from "./modules/courses/coursesPublic/Addcourses"; import Addcourses from "./modules/courses/coursesPublic/Addcourses";
import AccountProfile from "./modules/user/AccountProfile"; import AccountProfile from "./modules/user/AccountProfile";
import Accountnewprofile from './modules/user/Accountnewprofile'; import Accountnewprofile from './modules/user/Accountnewprofile';
import Trialapplication from './modules/login/Trialapplication';
import Certifiedprofessional from './modules/modals/Certifiedprofessional'; import Certifiedprofessional from './modules/modals/Certifiedprofessional';
import NotFoundPage from './NotFoundPage'
import Loading from './Loading' import Loading from './Loading'
import Loadable from 'react-loadable'; import Loadable from 'react-loadable';
import moment from 'moment' import moment from 'moment'
import {MuiThemeProvider, createMuiTheme} from 'material-ui/styles';
// import './AppConfig'
import history from './history'; import history from './history';
import {SnackbarHOC} from 'educoder' import { SnackbarHOC } from './common/educoder'
import {initAxiosInterceptors} from './AppConfig' import { initAxiosInterceptors } from './AppConfig'
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import configureStore from './redux/stores/configureStore'; import configureStore from './redux/stores/configureStore';
// tpi需要这个来加载css
import {TPMIndexHOC} from './modules/tpm/TPMIndexHOC';
const store = configureStore(); 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({ const EducoderLogin = Loadable({
loader: () => import('./modules/login/EducoderLogin'), loader: () => import('./modules/login/EducoderLogin'),
@ -68,30 +39,26 @@ const EducoderLogin = Loadable({
//微信登录 //微信登录
const Otherlogin=Loadable({ const Otherlogin = Loadable({
loader: () => import('./modules/login/Otherlogin'), loader: () => import('./modules/login/Otherlogin'),
loading: Loading, loading: Loading,
}) })
//微信登录 //微信登录
const Loginqq=Loadable({ const Loginqq = Loadable({
loader: () => import('./modules/login/Loginqq'), loader: () => import('./modules/login/Loginqq'),
loading: Loading, loading: Loading,
}) })
const Otherloginstart=Loadable({ const Otherloginstart = Loadable({
loader: () => import('./modules/login/Otherloginstart'), loader: () => import('./modules/login/Otherloginstart'),
loading: Loading, loading: Loading,
}) })
const Otherloginsqq=Loadable({ const Otherloginsqq = Loadable({
loader: () => import('./modules/login/Otherloginqq'), loader: () => import('./modules/login/Otherloginqq'),
loading: Loading, loading: Loading,
}) })
// const TestIndex = Loadable({
// loader: () => import('./modules/test'),
// loading: Loading,
// })
const IndexWrapperComponent = Loadable({ const IndexWrapperComponent = Loadable({
loader: () => import('./modules/page/IndexWrapper'), loader: () => import('./modules/page/IndexWrapper'),
@ -103,24 +70,6 @@ const CommentComponent = Loadable({
loading: Loading, 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({ const TPMIndexComponent = Loadable({
loader: () => import('./modules/tpm/TPMIndex'), loader: () => import('./modules/tpm/TPMIndex'),
loading: Loading, loading: Loading,
@ -146,49 +95,12 @@ const SearchPage = Loadable({
loading: Loading, 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({ const ForumsIndexComponent = Loadable({
loader: () => import('./modules/forums/ForumsIndex'), loader: () => import('./modules/forums/ForumsIndex'),
loading: Loading, 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({ const Newshixuns = Loadable({
loader: () => import('./modules/tpm/newshixuns/Newshixuns'), loader: () => import('./modules/tpm/newshixuns/Newshixuns'),
@ -227,21 +139,11 @@ const http500 = Loadable({
loading: Loading, loading: Loading,
}) })
// 登录注册
const LoginRegisterPage = Loadable({
loader: () => import('./modules/user/LoginRegisterPage'),
loading: Loading,
})
const AccountPage = Loadable({ const AccountPage = Loadable({
loader: () => import('./modules/user/AccountPage'), loader: () => import('./modules/user/AccountPage'),
loading: Loading, loading: Loading,
}) })
// 个人主页
const UsersInfo = Loadable({
loader: () => import('./modules/user/usersInfo/Infos'),
loading: Loading,
})
const InfosIndex = Loadable({ const InfosIndex = Loadable({
loader: () => import('./modules/user/usersInfo/InfosIndex'), loader: () => import('./modules/user/usersInfo/InfosIndex'),
loading: Loading, loading: Loading,
@ -259,36 +161,25 @@ const MoopCases = Loadable({
loading: Loading, 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'), loader: () => import('./modules/competitions/Competitions'),
loading: Loading, loading: Loading,
}) })
//黑客松定制竞赛 //黑客松定制竞赛
const Osshackathon=Loadable({ const Osshackathon = Loadable({
loader: () => import('./modules/osshackathon/Osshackathon'), loader: () => import('./modules/osshackathon/Osshackathon'),
loading: Loading, loading: Loading,
}) })
const Messagerouting= Loadable({ const Messagerouting = Loadable({
loader: () => import('./modules/message/js/Messagerouting'), loader: () => import('./modules/message/js/Messagerouting'),
loading: Loading, loading: Loading,
}) })
const Topicbank= Loadable({ const Topicbank = Loadable({
loader: () => import('./modules/topic_bank/Topic_bank'), loader: () => import('./modules/topic_bank/Topic_bank'),
loading: Loading, loading: Loading,
}) })
@ -321,28 +212,28 @@ const Questionitem_banks = Loadable({
}) })
//试卷库 //试卷库
const Testpaperlibrary= Loadable({ const Testpaperlibrary = Loadable({
loader: () => import('./modules/testpaper/Testpaperlibrary'), loader: () => import('./modules/testpaper/Testpaperlibrary'),
loading: Loading loading: Loading
}) })
//试卷编辑 //试卷编辑
const Paperlibraryeditid= Loadable({ const Paperlibraryeditid = Loadable({
loader: () => import('./modules/testpaper/Paperlibraryeditid'), loader: () => import('./modules/testpaper/Paperlibraryeditid'),
loading: Loading loading: Loading
}) })
//试卷查看 //试卷查看
const Paperlibraryseeid= Loadable({ const Paperlibraryseeid = Loadable({
loader: () => import('./modules/testpaper/Paperlibraryseeid'), loader: () => import('./modules/testpaper/Paperlibraryseeid'),
loading: Loading loading: Loading
}) })
//人工组卷 //人工组卷
const Paperreview= Loadable({ const Paperreview = Loadable({
loader: () => import('./modules/question/Paperreview'), loader: () => import('./modules/question/Paperreview'),
loading: Loading loading: Loading
}) })
//智能组卷 //智能组卷
const Integeneration= Loadable({ const Integeneration = Loadable({
loader: () => import('./modules/testpaper/Intecomponents'), loader: () => import('./modules/testpaper/Intecomponents'),
loading: Loading loading: Loading
}) })
@ -373,58 +264,48 @@ const JupyterTPI = Loadable({
loader: () => import('./modules/tpm/jupyter'), loader: () => import('./modules/tpm/jupyter'),
loading: Loading 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 { class App extends Component {
constructor(props) { constructor(props) {
super(props) super(props)
this.state = { this.state = {
Addcoursestype:false, Addcoursestype: false,
Addcoursestypes:false, Addcoursestypes: false,
mydisplay:false, mydisplay: false,
occupation:0, occupation: 0,
mygetHelmetapi: null, mygetHelmetapi: null,
} }
} }
HideAddcoursestypess=(i)=>{ HideAddcoursestypess = (i) => {
console.log("调用了"); console.log("调用了");
this.setState({ this.setState({
Addcoursestype:false, Addcoursestype: false,
Addcoursestypes:false, Addcoursestypes: false,
mydisplay:true, mydisplay: true,
occupation:i, occupation: i,
}) })
}; };
hideAddcoursestypes=()=>{ hideAddcoursestypes = () => {
this.setState({ this.setState({
Addcoursestypes:false Addcoursestypes: false
}) })
}; };
ModalCancelsy=()=>{ ModalCancelsy = () => {
this.setState({ this.setState({
mydisplay:false, mydisplay: false,
}) })
window.location.href = "/"; window.location.href = "/";
}; };
ModalshowCancelsy=()=>{ ModalshowCancelsy = () => {
this.setState({ this.setState({
mydisplay:true, mydisplay: true,
}) })
}; };
disableVideoContextMenu = () => { disableVideoContextMenu = () => {
window.$( "body" ).on( "mousedown", "video", function(event) { window.$("body").on("mousedown", "video", function (event) {
if(event.which === 3) { if (event.which === 3) {
window.$('video').bind('contextmenu',function () { return false; }); window.$('video').bind('contextmenu', function () { return false; });
} else { } else {
window.$('video').unbind('contextmenu'); window.$('video').unbind('contextmenu');
} }
@ -443,20 +324,6 @@ class App extends Component {
initAxiosInterceptors(this.props); initAxiosInterceptors(this.props);
this.getAppdata(); 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) => { window.addEventListener('error', (event) => {
const msg = `${event.type}: ${event.message}`; const msg = `${event.type}: ${event.message}`;
@ -464,9 +331,9 @@ class App extends Component {
}); });
} }
//修改登录方法 //修改登录方法
Modifyloginvalue=()=>{ Modifyloginvalue = () => {
this.setState({ this.setState({
isRender:false, isRender: false,
}) })
}; };
@ -501,19 +368,17 @@ class App extends Component {
document.head.appendChild(link); document.head.appendChild(link);
} }
//获取当前定制信息 //获取当前定制信息
getAppdata=()=>{ getAppdata = () => {
let url = "/setting.json"; let url = "/setting.json";
axios.get(url).then((response) => { axios.get(url).then((response) => {
// console.log("app.js开始请求/setting.json"); if (response) {
// console.log("获取当前定制信息"); if (response.data) {
if(response){
if(response.data){
this.setState({ this.setState({
mygetHelmetapi:response.data.setting mygetHelmetapi: response.data.setting
}); });
//存储配置到游览器 //存储配置到游览器
localStorage.setItem('chromesetting',JSON.stringify(response.data.setting)); localStorage.setItem('chromesetting', JSON.stringify(response.data.setting));
localStorage.setItem('chromesettingresponse',JSON.stringify(response)); localStorage.setItem('chromesettingresponse', JSON.stringify(response));
try { try {
if (response.data.setting.tab_logo_url) { if (response.data.setting.tab_logo_url) {
this.gettablogourldata(response); this.gettablogourldata(response);
@ -543,21 +408,18 @@ class App extends Component {
}; };
render() { render() {
let{mygetHelmetapi}=this.state;
// console.log("appappapp");
// console.log(mygetHelmetapi);
return ( return (
<Provider store={store}> <Provider store={store}>
<ConfigProvider locale={zhCN}> <ConfigProvider locale={zhCN}>
<MuiThemeProvider theme={theme}>
<Accountnewprofile {...this.props}{...this.state}/> <Accountnewprofile {...this.props}{...this.state} />
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={()=>this.Modifyloginvalue()}></LoginDialog> <LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
<Notcompletedysl {...this.props} {...this.state}></Notcompletedysl> <Notcompletedysl {...this.props} {...this.state}></Notcompletedysl>
<Trialapplicationysl {...this.props} {...this.state}></Trialapplicationysl> <Trialapplicationysl {...this.props} {...this.state}></Trialapplicationysl>
<Trialapplicationreview {...this.props} {...this.state}></Trialapplicationreview> <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} /> <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> <Router>
<Switch> <Switch>
@ -577,8 +439,6 @@ class App extends Component {
return (<Topicbank {...this.props} {...props} {...this.state} />) return (<Topicbank {...this.props} {...props} {...this.state} />)
} }
}></Route> }></Route>
{/*/!*众包创新*!/*/}
{/*<Route path={"/crowdsourcing"} component={ProjectPackages}/>*/}
{/*竞赛*/} {/*竞赛*/}
<Route path={"/competitions"} <Route path={"/competitions"}
render={ render={
@ -592,8 +452,8 @@ class App extends Component {
<Route <Route
path={"/osshackathon"} path={"/osshackathon"}
render={ render={
(props)=>{ (props) => {
return( return (
<Osshackathon {...this.props} {...props} {...this.state} /> <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*/} {/*403*/}
<Route path="/403" component={Shixunauthority}/> <Route path="/403" component={Shixunauthority} />
<Route path="/500" component={http500}/> <Route path="/500" component={http500} />
{/*404*/} {/*404*/}
<Route path="/nopage" component={Shixunnopage}/> <Route path="/nopage" component={Shixunnopage} />
<Route path="/compatibility" component={CompatibilityPageLoadable}/> <Route path="/compatibility" component={CompatibilityPageLoadable} />
<Route <Route
path="/login" path="/login"
render={ render={
@ -657,12 +517,6 @@ class App extends Component {
return (<BanksIndex {...this.props} {...props} {...this.state} />) return (<BanksIndex {...this.props} {...props} {...this.state} />)
} }
}></Route> }></Route>
{/*<Route*/}
{/*path="/personalcompetit"*/}
{/*render={*/}
{/*(props) => (<PersonalCompetit {...this.props} {...props} {...this.state}></PersonalCompetit>)*/}
{/*}*/}
{/*/>*/}
<Route <Route
path="/changepassword" path="/changepassword"
render={ render={
@ -681,91 +535,72 @@ class App extends Component {
<Route path="/colleges/:id/statistics" <Route path="/colleges/:id/statistics"
render={ render={
(props) => (<College {...this.props} {...props} {...this.state} />) (props) => (<College {...this.props} {...props} {...this.state} />)
}/> } />
{/* jupyter */} {/* jupyter */}
<Route path="/tasks/:identifier/jupyter/" <Route path="/tasks/:identifier/jupyter/"
render={ render={
(props) => { (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 path="/shixuns/:shixunId" component={TPMIndexComponent}>*/}
{/*</Route>*/} {/*</Route>*/}
<Route path="/shixuns/:shixunId" <Route path="/shixuns/:shixunId"
render={ render={
(props)=>(<TPMIndexComponent {...this.props} {...props} {...this.state}></TPMIndexComponent>) (props) => (<TPMIndexComponent {...this.props} {...props} {...this.state}></TPMIndexComponent>)
} }
></Route> ></Route>
{/*列表页 实训项目列表*/} {/*列表页 实训项目列表*/}
{/*<Route path="/shixuns" component={TPMShixunsIndexComponent}/>*/}
<Route path="/shixuns" <Route path="/shixuns"
render={ render={
(props)=>(<TPMShixunsIndexComponent {...this.props} {...props} {...this.state}></TPMShixunsIndexComponent>) (props) => (<TPMShixunsIndexComponent {...this.props} {...props} {...this.state}></TPMShixunsIndexComponent>)
} }
></Route> ></Route>
{/*实训课程(原实训路径)*/} {/*实训课程(原实训路径)*/}
<Route path="/paths" component={ShixunPaths}></Route> <Route path="/paths" component={ShixunPaths}></Route>
<Route path="/search" <Route path="/search"
render={ render={
(props)=>(<SearchPage {...this.props} {...props} {...this.state}></SearchPage>) (props) => (<SearchPage {...this.props} {...props} {...this.state}></SearchPage>)
} }
></Route> ></Route>
{/*课堂*/} {/*课堂*/}
<Route path="/courses" component={CoursesIndex} {...this.props} {...this.state}></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} />) (props) => (<MoopCases {...this.props} {...props} {...this.state} />)
}/> } />
<Route path="/forums" <Route path="/forums"
render={ render={
(props)=>(<ForumsIndexComponent {...this.props} {...props} {...this.state}></ForumsIndexComponent>) (props) => (<ForumsIndexComponent {...this.props} {...props} {...this.state}></ForumsIndexComponent>)
} }
> >
</Route> </Route>
<Route path="/comment" component={CommentComponent}/> <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="/messages" <Route path="/messages"
render={ render={
(props)=>(<Messagerouting {...this.props} {...props} {...this.state}></Messagerouting>) (props) => (<Messagerouting {...this.props} {...props} {...this.state}></Messagerouting>)
} }
></Route> ></Route>
<Route path="/help/:type" <Route path="/help/:type"
render={ render={
(props)=>(<Help {...this.props} {...props} {...this.state}></Help>) (props) => (<Help {...this.props} {...props} {...this.state}></Help>)
}/> } />
<Route path="/ecs" <Route path="/ecs"
render={ render={
(props)=>(<Ecs {...this.props} {...props} {...this.state}></Ecs>) (props) => (<Ecs {...this.props} {...props} {...this.state}></Ecs>)
}/> } />
<Route path="/problems/new/:id?" <Route path="/problems/new/:id?"
render={ render={
@ -788,20 +623,20 @@ class App extends Component {
<Route path="/Integeneration/:type/:id" <Route path="/Integeneration/:type/:id"
render={ render={
(props) => (<Paperreview {...this.props} {...props} {...this.state} />) (props) => (<Paperreview {...this.props} {...props} {...this.state} />)
}/> } />
<Route path="/paperreview/:type" <Route path="/paperreview/:type"
render={ render={
(props) => (<Paperreview {...this.props} {...props} {...this.state} />) (props) => (<Paperreview {...this.props} {...props} {...this.state} />)
}/> } />
<Route path="/paperlibrary/edit/:id" <Route path="/paperlibrary/edit/:id"
render={ render={
(props) => (<Paperlibraryeditid {...this.props} {...props} {...this.state} />) (props) => (<Paperlibraryeditid {...this.props} {...props} {...this.state} />)
}/> } />
<Route path="/paperlibrary/see/:id" <Route path="/paperlibrary/see/:id"
render={ render={
(props) => (<Paperlibraryseeid {...this.props} {...props} {...this.state} />) (props) => (<Paperlibraryseeid {...this.props} {...props} {...this.state} />)
}/> } />
<Route path="/myproblems/:id/:tab?" <Route path="/myproblems/:id/:tab?"
render={ render={
@ -823,40 +658,36 @@ class App extends Component {
<Route path="/paperlibrary" <Route path="/paperlibrary"
render={ render={
(props) => (<Testpaperlibrary {...this.props} {...props} {...this.state} />) (props) => (<Testpaperlibrary {...this.props} {...props} {...this.state} />)
}/> } />
<Route path="/Integeneration" <Route path="/Integeneration"
render={ render={
(props) => (<Integeneration {...this.props} {...props} {...this.state} />) (props) => (<Integeneration {...this.props} {...props} {...this.state} />)
}/> } />
<Route path="/problems" <Route path="/problems"
render={ render={
(props) => (<Developer {...this.props} {...props} {...this.state} />) (props) => (<Developer {...this.props} {...props} {...this.state} />)
}/> } />
<Route path="/question" <Route path="/question"
render={ render={
(props) => (<Headplugselection {...this.props} {...props} {...this.state} />) (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="/" <Route exact path="/"
// component={ShixunsHome} // component={ShixunsHome}
render={ render={
(props)=>(<ShixunsHome {...this.props} {...props} {...this.state}></ShixunsHome>) (props) => (<ShixunsHome {...this.props} {...props} {...this.state}></ShixunsHome>)
} }
/> />
<Route component={Shixunnopage}/> <Route component={Shixunnopage} />
</Switch> </Switch>
</Router> </Router>
</MuiThemeProvider>
</ConfigProvider> </ConfigProvider>
</Provider> </Provider>
); );
} }
} }
@ -972,4 +803,4 @@ moment.defineLocale('zh-cn', {
doy: 4 // The week that contains Jan 4th is the first week of the year. 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 axios from 'axios';
import md5 from 'md5'; import md5 from 'md5';
import { requestProxy } from "./indexEduplus2RequestProxy"; import { requestProxy } from "./indexEduplus2RequestProxy";
import { broadcastChannelOnmessage ,SetAppModel, isDev, queryString } from 'educoder'; import { broadcastChannelOnmessage, isDev, queryString } from './common/educoder';
import { notification } from 'antd'; import { notification } from 'antd';
import cookie from 'react-cookies'; import cookie from 'react-cookies';
import './index.css'; import './index.css';
const $ = window.$; const $ = window.$;
const opens ="79e33abd4b6588941ab7622aed1e67e8"; const opens = "79e33abd4b6588941ab7622aed1e67e8";
let timestamp; let timestamp;
let checkSubmitFlg = false; let checkSubmitFlg = false;
let message501=false; let message501 = false;
broadcastChannelOnmessage('refreshPage', () => { broadcastChannelOnmessage('refreshPage', () => {
window.location.reload() window.location.reload()
}) })
function locationurl(list){ function locationurl(list) {
if (window.location.port === "3007") { if (window.location.port === "3007") {
} else { } else {
window.location.href=list window.location.href = list
} }
} }
@ -30,7 +29,7 @@ function locationurl(list){
// TODO 开发期多个身份切换 // TODO 开发期多个身份切换
let debugType ="" let debugType = ""
if (isDev) { if (isDev) {
const _search = window.location.search; const _search = window.location.search;
let parsed = {}; let parsed = {};
@ -53,30 +52,25 @@ if (isDev) {
function clearAllCookie() { function clearAllCookie() {
cookie.remove('_educoder_session', {path: '/'}); cookie.remove('_educoder_session', { path: '/' });
cookie.remove('autologin_trustie', {path: '/'}); cookie.remove('autologin_trustie', { path: '/' });
setpostcookie() setpostcookie()
} }
clearAllCookie(); clearAllCookie();
function setpostcookie() { function setpostcookie() {
const str =window.location.pathname; const str = window.location.pathname;
// console.log(str.indexOf("/wxcode")) if (str.indexOf("/wxcode") !== -1) {
let newdomain=".educoder.net"
if(str.indexOf("/wxcode") !== -1){
console.log("123") console.log("123")
cookie.remove('_educoder_session', {path: '/'}); cookie.remove('_educoder_session', { path: '/' });
cookie.remove('autologin_trustie', {path: '/'}); cookie.remove('autologin_trustie', { path: '/' });
// console.log("开始重写cookis");
const _params = window.location.search; const _params = window.location.search;
// console.log("1111");
if (_params) { if (_params) {
// console.log("22222");
let _search = _params.split('?')[1]; let _search = _params.split('?')[1];
let _educoder_sessions= _search.split('&')[0].split('='); let _educoder_sessions = _search.split('&')[0].split('=');
cookie.save('_educoder_session',_educoder_sessions[1], { domain:'.educoder.net', path: '/'}); cookie.save('_educoder_session', _educoder_sessions[1], { domain: '.educoder.net', path: '/' });
let autologin_trusties=_search.split('&')[1].split('='); let autologin_trusties = _search.split('&')[1].split('=');
cookie.save('autologin_trustie',autologin_trusties[1], { domain:'.educoder.net', path: '/'}); cookie.save('autologin_trustie', autologin_trusties[1], { domain: '.educoder.net', path: '/' });
} }
} }
@ -84,31 +78,35 @@ function setpostcookie() {
setpostcookie(); setpostcookie();
function railsgettimes(proxy) { function railsgettimes(proxy) {
clearAllCookie() clearAllCookie()
if(timestamp&&checkSubmitFlg===false){ if (timestamp && checkSubmitFlg === false) {
$.ajax({url:proxy,async:false,success:function(data){ $.ajax({
if(data.status===0){ url: proxy, async: false, success: function (data) {
timestamp=data.message; if (data.status === 0) {
timestamp = data.message;
setpostcookie(); setpostcookie();
} }
}}) }
checkSubmitFlg=true })
window.setTimeout(()=>{ checkSubmitFlg = true
checkSubmitFlg=false; window.setTimeout(() => {
checkSubmitFlg = false;
}, 2000); }, 2000);
}else if(checkSubmitFlg===false){ } else if (checkSubmitFlg === false) {
$.ajax({url:proxy,async:false,success:function(data){ $.ajax({
if(data.status===0){ url: proxy, async: false, success: function (data) {
timestamp=data.message; if (data.status === 0) {
timestamp = data.message;
setpostcookie(); setpostcookie();
} }
}}) }
checkSubmitFlg=true })
window.setTimeout( ()=>{ checkSubmitFlg = true
checkSubmitFlg=false; window.setTimeout(() => {
checkSubmitFlg = false;
}, 2000); }, 2000);
} }
@ -131,8 +129,8 @@ export function initAxiosInterceptors(props) {
// proxy = "http://testbdweb.educoder.net" // proxy = "http://testbdweb.educoder.net"
// proxy = "https://testeduplus2.educoder.net" // proxy = "https://testeduplus2.educoder.net"
//proxy="http://47.96.87.25:48080" //proxy="http://47.96.87.25:48080"
proxy="https://pre-newweb.educoder.net" proxy = "https://pre-newweb.educoder.net"
proxy="https://test-newweb.educoder.net" proxy = "https://test-newweb.educoder.net"
// proxy="https://test-jupyterweb.educoder.net" // proxy="https://test-jupyterweb.educoder.net"
// proxy="https://test-newweb.educoder.net" // proxy="https://test-newweb.educoder.net"
// proxy="https://test-jupyterweb.educoder.net" // proxy="https://test-jupyterweb.educoder.net"
@ -143,7 +141,7 @@ export function initAxiosInterceptors(props) {
// 如果需要支持重复的请求考虑config里面自定义一个allowRepeat参考来控制 // 如果需要支持重复的请求考虑config里面自定义一个allowRepeat参考来控制
const requestMap = {}; const requestMap = {};
window.setfalseInRequestMap = function(keyName) { window.setfalseInRequestMap = function (keyName) {
requestMap[keyName] = false; requestMap[keyName] = false;
} }
@ -164,55 +162,6 @@ export function initAxiosInterceptors(props) {
// proxy = 'http://localhost:3000' // 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) { if (config.url.indexOf(proxy) != -1 || config.url.indexOf(':') != -1) {
return config return config
@ -222,19 +171,19 @@ export function initAxiosInterceptors(props) {
let url = `/api${config.url}`; let url = `/api${config.url}`;
//qq登录去掉api //qq登录去掉api
if(config.params&&config.params.redirect_uri!=undefined){ if (config.params && config.params.redirect_uri != undefined) {
if(config.params.redirect_uri.indexOf('otherloginqq')!=-1){ if (config.params.redirect_uri.indexOf('otherloginqq') != -1) {
url = `${config.url}`; url = `${config.url}`;
} }
} }
if(`${config[0]}`!=`true`){ if (`${config[0]}` != `true`) {
let timestamp = Date.parse(new Date())/1000; let timestamp = Date.parse(new Date()) / 1000;
if (window.location.port === "3007") { if (window.location.port === "3007") {
// let timestamp=railsgettimes(proxy); // let timestamp=railsgettimes(proxy);
// console.log(timestamp) // console.log(timestamp)
// `https://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp` // `https://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp`
railsgettimes( `${proxy}/api/main/first_stamp.json`); railsgettimes(`${proxy}/api/main/first_stamp.json`);
let newopens=md5(opens+timestamp) let newopens = md5(opens + timestamp)
config.url = `${proxy}${url}`; config.url = `${proxy}${url}`;
if (config.url.indexOf('?') == -1) { if (config.url.indexOf('?') == -1) {
config.url = `${config.url}?debug=${debugType}&randomcode=${timestamp}&client_key=${newopens}`; config.url = `${config.url}?debug=${debugType}&randomcode=${timestamp}&client_key=${newopens}`;
@ -245,8 +194,8 @@ export function initAxiosInterceptors(props) {
// 加api前缀 // 加api前缀
// railsgettimes(`http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp`); // railsgettimes(`http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp`);
railsgettimes( `/api/main/first_stamp.json`); railsgettimes(`/api/main/first_stamp.json`);
let newopens=md5(opens+timestamp) let newopens = md5(opens + timestamp)
config.url = url; config.url = url;
if (config.url.indexOf('?') == -1) { if (config.url.indexOf('?') == -1) {
config.url = `${config.url}?randomcode=${timestamp}&client_key=${newopens}`; config.url = `${config.url}?randomcode=${timestamp}&client_key=${newopens}`;
@ -271,7 +220,7 @@ export function initAxiosInterceptors(props) {
if (config.url.indexOf('update_file') === -1) { if (config.url.indexOf('update_file') === -1) {
requestMap[config.url] = true; requestMap[config.url] = true;
window.setTimeout("setfalseInRequestMap('"+config.url+"')", 900) window.setTimeout("setfalseInRequestMap('" + config.url + "')", 900)
} }
// setTimeout("setfalseInRequestMap(" + config.url + ")", 1200) // setTimeout("setfalseInRequestMap(" + config.url + ")", 1200)
return config; return config;
@ -283,7 +232,7 @@ export function initAxiosInterceptors(props) {
axios.interceptors.response.use(function (response) { axios.interceptors.response.use(function (response) {
// console.log(".............") // console.log(".............")
if(response===undefined){ if (response === undefined) {
return return
} }
const config = response.config const config = response.config
@ -296,10 +245,10 @@ export function initAxiosInterceptors(props) {
// message.info(response.data.message || '服务端返回status -1请联系管理员。'); // message.info(response.data.message || '服务端返回status -1请联系管理员。');
// props.showSnackbar( response.data.message || '服务器异常,请联系管理员。' ) // props.showSnackbar( response.data.message || '服务器异常,请联系管理员。' )
if (window.location.pathname.startsWith('/tasks/')) { if (window.location.pathname.startsWith('/tasks/')) {
props.showSnackbar( response.data.message || '服务器异常,请联系管理员。' ) props.showSnackbar(response.data.message || '服务器异常,请联系管理员。')
} else { } else {
notification.open({ notification.open({
message:"提示", message: "提示",
description: response.data.message || '服务器异常,请联系管理员。', description: response.data.message || '服务器异常,请联系管理员。',
style: { style: {
zIndex: 99999999 zIndex: 99999999
@ -328,7 +277,7 @@ export function initAxiosInterceptors(props) {
// if(response.data.status === 401){ // if(response.data.status === 401){
// console.log("401401401") // console.log("401401401")
// } // }
if (response.data.status === 403||response.data.status === "403") { if (response.data.status === 403 || response.data.status === "403") {
locationurl('/403'); locationurl('/403');
} }
@ -342,53 +291,27 @@ export function initAxiosInterceptors(props) {
} }
if (response.data.status === 501) { if (response.data.status === 501) {
if(message501===false){ if (message501 === false) {
message501=true message501 = true
notification.open({ notification.open({
message:"提示", message: "提示",
description:response.data.message || '访问异常,请求不合理', description: response.data.message || '访问异常,请求不合理',
style: { style: {
zIndex: 99999999 zIndex: 99999999
} }
}) })
} }
window.setTimeout(function () { window.setTimeout(function () {
message501=false message501 = false
}, 2000); }, 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; requestMap[response.config.url] = false;
setpostcookie(); setpostcookie();
return response; return response;
}, function (error) { }, function (error) {
return Promise.reject(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 { class NotFoundPage extends Component {
render() { render() {
@ -8,29 +8,28 @@ class NotFoundPage extends Component {
<div className="App"> <div className="App">
404 Page 404 Page
<br></br> <br></br>
 
<Link to="/tasks/ixq5euhgrf7y">Index</Link> <Link to="/tasks/ixq5euhgrf7y">Index</Link>
|  |
<Link to="/shixuns/uznmbg54/challenges">tpm challenges</Link> <Link to="/shixuns/uznmbg54/challenges">tpm challenges</Link>
|  |
<Link to="/shixuns/uznmbg54/shixun_discuss">tpm discuss</Link> <Link to="/shixuns/uznmbg54/shixun_discuss">tpm discuss</Link>
|  |
<Link to="/forums/categories/all">forums</Link> <Link to="/forums/categories/all">forums</Link>
 |  |
<Link to="/comment">Comment</Link> <Link to="/comment">Comment</Link>
 |  |
<Link to="/testMaterial">testMaterial</Link> <Link to="/testMaterial">testMaterial</Link>
 |  |
<Link to="/testCodeMirror">testCodeMirror</Link> <Link to="/testCodeMirror">testCodeMirror</Link>
 |  |
<Link to="/taskList">taskList</Link> <Link to="/taskList">taskList</Link>
 |  |
<Link to="/testRCComponent">testRCComponent</Link> <Link to="/testRCComponent">testRCComponent</Link>
|  |
<Link to="/tpforums">tpforums</Link> <Link to="/tpforums">tpforums</Link>
|  |
<Link to="/testUrlQuery">url-query test</Link> <Link to="/testUrlQuery">url-query test</Link>
</div> </div>

File diff suppressed because it is too large Load Diff

@ -1,13 +1,13 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import Snackbar from 'material-ui/Snackbar'; import { notification, Alert } from 'antd'
import Fade from 'material-ui/transitions/Fade';
import { notification } from 'antd'
export function SnackbarHOC(options = {}) { export function SnackbarHOC(options = {}) {
return function wrap(WrappedComponent) { return function wrap(WrappedComponent) {
return class Wrapper extends Component { return class Wrapper extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.showSnackbar = this.showSnackbar.bind(this) this.showSnackbar = this.showSnackbar.bind(this)
this.handleSnackbarClose = this.handleSnackbarClose.bind(this)
this.state = { this.state = {
snackbarText: '', snackbarText: '',
snackbarOpen: false, 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) { showSnackbar(text, vertical, horizontal) {
this.setState({ this.setState({
snackbarOpen: true, snackbarOpen: true,
@ -60,27 +42,12 @@ export function SnackbarHOC(options = {}) {
notification.open(data); notification.open(data);
} }
render() { render() {
const { snackbarOpen, snackbarText, snackbarHorizontal, snackbarVertical } = this.state; const { snackbarOpen, snackbarText } = this.state
return ( return (
<React.Fragment> <React.Fragment>
<Snackbar {snackbarOpen ? <Alert messagg={snackbarText} onClose={this.handleSnackbarClose} /> : null}
className={"rootSnackbar"} <WrappedComponent {...this.props} showSnackbar={this.showSnackbar} showNotification={this.showNotification} >
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 } >
</WrappedComponent> </WrappedComponent>
</React.Fragment> </React.Fragment>

@ -1,44 +1,14 @@
import { bytesToSize, getUrl, getUrl2 } from 'educoder'; import { bytesToSize, getUrl, getUrl2 } from 'educoder';
const $ = window.$ const $ = window.$
import showdown from 'showdown'
export function isImageExtension(fileName) { export function isImageExtension(fileName) {
return fileName ? !!(fileName.match(/.(jpg|jpeg|png|gif)$/i)) : false return fileName ? !!(fileName.match(/.(jpg|jpeg|png|gif)$/i)) : false
} }
export function markdownToHTML(oldContent, selector) { export function markdownToHTML(oldContent) {
window.$('#md_div').html('') var converter = new showdown.Converter()
// markdown to html return converter.makeHtml(oldContent);
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
}
} }
function _doDownload(options) { function _doDownload(options) {
$.fileDownload(getUrl() + "/api" + options.url, { $.fileDownload(getUrl() + "/api" + options.url, {
@ -66,7 +36,7 @@ export function appendFileSizeToUploadFile(item) {
export function appendFileSizeToUploadFileAll(fileList) { export function appendFileSizeToUploadFileAll(fileList) {
return fileList.map(item => { return fileList.map(item => {
if (item.name.indexOf(uploadNameSizeSeperator) == -1) { 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 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", 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",
"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 * @LastEditors : tangjiang
* @LastEditTime : 2020-01-06 18:42:09 * @LastEditTime : 2020-01-06 18:42:09
*/ */
import './index.scss'; import './index.less';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Form, Button, Input } from 'antd'; import { Form, Button, Input } from 'antd';
import QuillForEditor from '../../quillForEditor'; import QuillForEditor from '../../quillForEditor';
@ -14,7 +14,7 @@ import QuillForEditor from '../../quillForEditor';
// import {formatDelta} from './util'; // import {formatDelta} from './util';
const FormItem = Form.Item; const FormItem = Form.Item;
function CommentForm (props) { function CommentForm(props) {
const { const {
onCancel, onCancel,
@ -57,7 +57,7 @@ function CommentForm (props) {
try { try {
// const _html = new QuillDeltaToHtmlConverter(content.ops, {}).convert(); // const _html = new QuillDeltaToHtmlConverter(content.ops, {}).convert();
// props.form.setFieldsValue({'comment': _html.replace(/<\/?[^>]*>/g, '')}); // props.form.setFieldsValue({'comment': _html.replace(/<\/?[^>]*>/g, '')});
props.form.setFieldsValue({'comment': content}); props.form.setFieldsValue({ 'comment': content });
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
@ -69,7 +69,7 @@ function CommentForm (props) {
if (!err) { if (!err) {
setShowQuill(false); setShowQuill(false);
const content = ctx; const content = ctx;
props.form.setFieldsValue({'comment': ''}); props.form.setFieldsValue({ 'comment': '' });
setCtx(''); setCtx('');
// const _html = formatDelta(content.ops); // const _html = formatDelta(content.ops);
// console.log('保存的内容=====》》》》', content); // console.log('保存的内容=====》》》》', content);
@ -95,7 +95,7 @@ function CommentForm (props) {
{ {
getFieldDecorator('comment', { getFieldDecorator('comment', {
rules: [ rules: [
{ required: true, message: '评论内容不能为空'} { required: true, message: '评论内容不能为空' }
], ],
})( })(
<Input <Input
@ -112,7 +112,7 @@ function CommentForm (props) {
} }
<QuillForEditor <QuillForEditor
imgAttrs={{width: '60px', height: '30px'}} imgAttrs={{ width: '60px', height: '30px' }}
wrapStyle={{ wrapStyle={{
height: showQuill ? 'auto' : '0px', height: showQuill ? 'auto' : '0px',
opacity: showQuill ? 1 : 0, opacity: showQuill ? 1 : 0,
@ -130,7 +130,7 @@ function CommentForm (props) {
</FormItem> </FormItem>
<FormItem style={{ textAlign: 'right', display: showQuill ? 'block' : 'none' }}> <FormItem style={{ textAlign: 'right', display: showQuill ? 'block' : 'none' }}>
<Button onClick={handleCancle}>取消</Button> <Button onClick={handleCancle}>取消</Button>
<Button onClick={handleSubmit} type="primary" style={{ marginLeft: '10px'}}>发送</Button> <Button onClick={handleSubmit} type="primary" style={{ marginLeft: '10px' }}>发送</Button>
</FormItem> </FormItem>
</Form> </Form>
); );

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

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

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

@ -1,87 +1,98 @@
$bdColor: rgba(244,244,244,1); @bdColor: rgba(244, 244, 244, 1);
$bgColor: rgba(250,250,250,1); @bgColor: rgba(250, 250, 250, 1);
$lh14: 14px; @lh14: 14px;
$lh22: 22px; @lh22: 22px;
$fz14: 14px; @fz14: 14px;
$fz12: 12px; @fz12: 12px;
$ml: 20px; @ml: 20px;
.comment_list_wrapper{ .comment_list_wrapper {
box-sizing: border-box; box-sizing: border-box;
// border-top: 1px solid $bdColor;
.empty_comment{ // border-top: 1px solid @bdColor;
.empty_comment {
display: flex; display: flex;
height: calc(100vh - 200px); height: calc(100vh - 200px);
width: 100%; width: 100%;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.comment_item_show{
.comment_item_show {
display: block; display: block;
} }
.comment_item_hide{
.comment_item_hide {
display: none; display: none;
} }
.comment_item_area{
.comment_item_area {
display: flex; display: flex;
padding: 20px 0; padding: 20px 0;
box-sizing: border-box; box-sizing: border-box;
border-bottom: 1px solid $bdColor; border-bottom: 1px solid @bdColor;
.comment_child_item_area:hover{ .comment_child_item_area:hover {
.item-close{ .item-close {
display: inline-block; display: inline-block;
} }
} }
.flex-image{ .flex-image {
width: 48px; width: 48px;
height: 48px; height: 48px;
border-radius: 50%; border-radius: 50%;
} }
.item-desc{
.item-desc {
flex: 1; flex: 1;
// margin-left: $ml; // margin-left: @ml;
margin-left: 5px; margin-left: 5px;
} }
.item-header{
font-size: $fz14; .item-header {
line-height: $lh14; font-size: @fz14;
line-height: @lh14;
color: #333; color: #333;
margin-left: 15px; margin-left: 15px;
.item-time{
font-size: $fz12; .item-time {
line-height: $lh14; font-size: @fz12;
margin-left: $ml; line-height: @lh14;
margin-left: @ml;
} }
.item-close{
.item-close {
display: none; display: none;
cursor: pointer; cursor: pointer;
float: right; float: right;
} }
.item-close.hide{ .item-close.hide {
display: none; display: none;
} }
} }
.item-ctx{
.item-ctx {
position: relative; position: relative;
line-height: $lh22; line-height: @lh22;
font-size: $fz12; font-size: @fz12;
color: #333; color: #333;
margin-top: 10px; margin-top: 10px;
vertical-align: top; vertical-align: top;
} }
.comment_icon_area{
.comment_icon_area {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
margin-top: 10px; margin-top: 10px;
.comment-icon-margin{ .comment-icon-margin {
margin-left: 20px; margin-left: 20px;
} }
.comment-icon-margin-10{
.comment-icon-margin-10 {
margin-left: 10px; margin-left: 10px;
} }
} }
@ -89,23 +100,24 @@ $ml: 20px;
// .comment_item_quill{ // .comment_item_quill{
// // margin-top: 10px; // // margin-top: 10px;
// } // }
.show_upload_image{ .show_upload_image {
position: fixed; position: fixed;
left: 0; left: 0;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
z-index: 1000; z-index: 1000;
&::before{
&::before {
position: absolute; position: absolute;
height: 100%; height: 100%;
width:100%; width: 100%;
content: ''; content: '';
background: #000; background: #000;
opacity: .7; opacity: .7;
} }
.image_info{ .image_info {
display: flex; display: flex;
position: absolute; position: absolute;
width: 80%; width: 80%;
@ -114,14 +126,15 @@ $ml: 20px;
top: 10%; top: 10%;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
// background: green; // background: green;
.image{ .image {
display: block; display: block;
width: 100%; width: 100%;
} }
} }
.image_close{ .image_close {
position: absolute; position: absolute;
right: 20px; right: 20px;
top: 20px; top: 20px;
@ -130,40 +143,47 @@ $ml: 20px;
} }
} }
} }
.comment_icon_count{
.comment_icon_count {
cursor: pointer; cursor: pointer;
font-size: 12px; font-size: 12px;
line-height: 1.5; line-height: 1.5;
.comment_icon{ .comment_icon {
color: #333; color: #333;
} }
.comment_count{
.comment_count {
color: #999999; color: #999999;
margin-left: 10px; margin-left: 10px;
transition: color .3s; transition: color .3s;
} }
.comment_count_none{
.comment_count_none {
margin-left: 0; margin-left: 0;
} }
&:hover{ &:hover {
.comment_icon, .comment_icon,
.comment_count{ .comment_count {
color: #5091FF; color: #5091FF;
} }
} }
} }
.comment_item_append_list{
.comment_item_append_list {
display: none; display: none;
position: relative; position: relative;
background-color: $bgColor; background-color: @bgColor;
border-radius: 5px; border-radius: 5px;
padding: 0 15px 10px; padding: 0 15px 10px;
margin: 15px 0; margin: 15px 0;
&.active{
&.active {
display: block; display: block;
} }
&::before { &::before {
position: absolute; position: absolute;
left: 15px; left: 15px;
@ -173,53 +193,57 @@ $ml: 20px;
content: ''; content: '';
// border: 5px solid transparent; // border: 5px solid transparent;
border: 10px solid transparent; border: 10px solid transparent;
border-bottom-color: $bgColor; border-bottom-color: @bgColor;
} }
.comment_item_loadmore{ .comment_item_loadmore {
display: none; display: none;
padding-top: 10px; padding-top: 10px;
cursor: pointer; cursor: pointer;
.loadmore-txt, .loadmore-txt,
.loadmore-icon{ .loadmore-icon {
color: #999; color: #999;
text-align: center; text-align: center;
font-size: $fz12; font-size: @fz12;
} }
&.show{ &.show {
display: block; display: block;
} }
} }
} }
.icon_font_size_14{ .icon_font_size_14 {
font-size: 14px !important; font-size: 14px !important;
} }
} }
.comment_form_area, .comment_form_area,
.comment_form_bottom_area{ .comment_form_bottom_area {
width: 100%; width: 100%;
} }
.comment_form_area{
.comment_form_area {
position: relative; position: relative;
background: #fff; background: #fff;
// top: 10px; // top: 10px;
.ant-form-explain{ .ant-form-explain {
padding-left: 0px; padding-left: 0px;
} }
.show_input{
.show_input {
margin-top: 10px; margin-top: 10px;
} }
} }
.comment_form_bottom_area{ .comment_form_bottom_area {
position: relative; position: relative;
background: #fff; background: #fff;
top: 10px; top: 10px;
&.active{ &.active {
position: absolute; position: absolute;
background: #fff; background: #fff;
left: 0px; 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 { setmiyah as setmiyah } from './Component';
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 { default as queryString } from './UrlTool2'; export { default as queryString } from './UrlTool2';
export { SnackbarHOC as SnackbarHOC } from './SnackbarHOC'; export { SnackbarHOC as SnackbarHOC } from './SnackbarHOC';
export { trigger as trigger, on as on, off as off export {
, broadcastChannelPostMessage, broadcastChannelOnmessage } from './EventUtil'; trigger as trigger, on as on, off as off
, broadcastChannelPostMessage, broadcastChannelOnmessage
} from './EventUtil';
export { updatePageParams as updatePageParams } from './RouterUtil'; export { updatePageParams as updatePageParams } from './RouterUtil';
export { bytesToSize as bytesToSize } from './UnitUtil'; export { bytesToSize as bytesToSize } from './UnitUtil';
export { markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension, export {
downloadFile, sortDirections } from './TextUtil' markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension,
export { handleDateString, getNextHalfHourOfMoment,formatDuring } from './DateUtil' downloadFile, sortDirections
} from './TextUtil'
export { handleDateString, getNextHalfHourOfMoment, formatDuring } from './DateUtil'
export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil' 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 { 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 export {
, EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL} from './Const' 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' 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 ModalWrapper } from '../modules/courses/common/ModalWrapper'
export { default as NoneData } from '../modules/courses/coursesPublic/NoneData' 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 * @LastEditors : tangjiang
* @LastEditTime : 2020-02-05 11:23:03 * @LastEditTime : 2020-02-05 11:23:03
*/ */
import './index.scss'; import './index.less';
import 'quill/dist/quill.core.css'; // 核心样式 import 'quill/dist/quill.core.css'; // 核心样式
import 'quill/dist/quill.snow.css'; // 有工具栏 import 'quill/dist/quill.snow.css'; // 有工具栏
import 'quill/dist/quill.bubble.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 Font = Quill.import('formats/font');
// const Color = Quill.import('attributes/style/color'); // const Color = Quill.import('attributes/style/color');
Size.whitelist = ['12px', '14px', '16px', '18px', '20px', false]; 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.Quill = Quill;
window.katex = katex; window.katex = katex;
@ -37,7 +37,7 @@ Quill.register({
// Quill.register(Color); // Quill.register(Color);
function QuillForEditor ({ function QuillForEditor({
placeholder, placeholder,
readOnly, readOnly,
autoFocus = false, autoFocus = false,
@ -55,11 +55,11 @@ function QuillForEditor ({
// toolbar 默认值 // toolbar 默认值
const defaultConfig = [ const defaultConfig = [
'bold', 'italic', 'underline', 'bold', 'italic', 'underline',
{size: ['12px', '14px', '16px', '18px', '20px']}, { size: ['12px', '14px', '16px', '18px', '20px'] },
{align: []}, {list: 'ordered'}, {list: 'bullet'}, // 列表 { align: [] }, { list: 'ordered' }, { list: 'bullet' }, // 列表
{script: 'sub'}, {script: 'super'}, { script: 'sub' }, { script: 'super' },
{ 'color': [] }, { 'background': [] }, { 'color': [] }, { 'background': [] },
{header: [1,2,3,4,5,false]}, { header: [1, 2, 3, 4, 5, false] },
'blockquote', 'code-block', 'blockquote', 'code-block',
'link', 'image', 'video', 'link', 'image', 'video',
'formula', 'formula',
@ -102,7 +102,7 @@ function QuillForEditor ({
* index: 删除元素的位置 * index: 删除元素的位置
* length: 删除元素的个数 * length: 删除元素的个数
*/ */
const {index, length} = range; const { index, length } = range;
const _start = length === 0 ? index - 1 : index; const _start = length === 0 ? index - 1 : index;
const _length = length || 1; const _length = length || 1;
let delCtx = this.quill.getText(_start, _length); // 删除的元素 let delCtx = this.quill.getText(_start, _length); // 删除的元素
@ -214,7 +214,7 @@ function QuillForEditor ({
const ops = value.ops || []; const ops = value.ops || [];
ops.forEach((item, i) => { ops.forEach((item, i) => {
if (item.insert['image']) { 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 ReactDOM from 'react-dom';
import axios from 'axios'; import axios from 'axios';
import Snackbar from 'material-ui/Snackbar'; import Snackbar from '@material-ui/core/Snackbar';
import Fade from 'material-ui/transitions/Fade';
import update from 'immutability-helper' import update from 'immutability-helper'
import Dialog, { import Dialog from '@material-ui/core/Dialog';
DialogActions, import DialogActions from '@material-ui/core/DialogActions';
DialogContent, import DialogContent from '@material-ui/core/DialogContent';
DialogContentText, import DialogContentText from '@material-ui/core/DialogContentText';
DialogTitle, import DialogTitle from '@material-ui/core/DialogTitle';
} from 'material-ui/Dialog';
import Button from 'material-ui/Button'; import Button from '@material-ui/core/Button';
import EvaluateSuccessEffectDisplay from './EvaluateSuccessEffectDisplay' import EvaluateSuccessEffectDisplay from './EvaluateSuccessEffectDisplay'
@ -31,9 +29,11 @@ import _ from 'lodash'
*/ */
import TPIContext from './TPIContext' import TPIContext from './TPIContext'
import { EDU_ADMIN, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER import {
, EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL, EDU_BUSINESS, CNotificationHOC ,getRandomNumber} from 'educoder' EDU_ADMIN, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER
import { MuiThemeProvider, createMuiTheme, withStyles } from 'material-ui/styles'; , 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' import MUIDialogStyleUtil from '../modules/page/component/MUIDialogStyleUtil'
const styles = MUIDialogStyleUtil.getTwoButtonStyle() const styles = MUIDialogStyleUtil.getTwoButtonStyle()
@ -109,7 +109,7 @@ class TPIContextProvider extends Component {
} }
onShowUpdateDialog() { onShowUpdateDialog() {
this.setState({showUpdateDialog: true}) this.setState({ showUpdateDialog: true })
} }
// updateNowSuccess true 立即更新成功 // updateNowSuccess true 立即更新成功
// TODO updateDialogClose方法名不对 改为updateDialogCallback // TODO updateDialogClose方法名不对 改为updateDialogCallback
@ -145,7 +145,7 @@ class TPIContextProvider extends Component {
window.__fetchAllFlag = false; window.__fetchAllFlag = false;
this.fetchAll(stageId); this.fetchAll(stageId);
this.costTimeInterval = window.setInterval(()=> { this.costTimeInterval = window.setInterval(() => {
const { game } = this.state; const { game } = this.state;
if (!game || game.status === 2) { // 已完成的任务不需要计时 if (!game || game.status === 2) { // 已完成的任务不需要计时
return; return;
@ -153,14 +153,14 @@ class TPIContextProvider extends Component {
if (game.cost_time || game.cost_time === 0) { if (game.cost_time || game.cost_time === 0) {
// game.cost_time += 1; // game.cost_time += 1;
this.setState({ this.setState({
game: update(game, {cost_time: { $set: (game.cost_time+1) }}) game: update(game, { cost_time: { $set: (game.cost_time + 1) } })
}) })
} }
}, 1000) }, 1000)
// 页面离开时存下用户的任务耗时 // 页面离开时存下用户的任务耗时
window.$(window).unload( ()=>{ window.$(window).unload(() => {
this._updateCostTime(); this._updateCostTime();
}); });
} }
@ -176,7 +176,7 @@ class TPIContextProvider extends Component {
testPath = 'http://test-newweb.educoder.net' testPath = 'http://test-newweb.educoder.net'
} }
// var url = `${testPath}/api/v1/games/${ game.identifier }/cost_time` // 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({ window.$.ajax({
type: 'get', type: 'get',
url: url, url: url,
@ -194,7 +194,7 @@ class TPIContextProvider extends Component {
// 随便给个分以免重新评测时又出现评星组件注意目前game.star没有显示在界面上如果有则不能这么做 // 随便给个分以免重新评测时又出现评星组件注意目前game.star没有显示在界面上如果有则不能这么做
// game.star = 6; // game.star = 6;
this.setState({ this.setState({
game: update(game, {star: { $set: 6 }}), game: update(game, { star: { $set: 6 } }),
currentGamePassed: !!passed currentGamePassed: !!passed
}) })
} }
@ -253,7 +253,8 @@ pop_box_new(htmlvalue, 480, 182);
const { praise_count, praise } = response.data; const { praise_count, praise } = response.data;
// challenge.praise_count = praise_tread_count; // challenge.praise_count = praise_tread_count;
// challenge.user_praise = praise; // challenge.user_praise = praise;
this.setState({ challenge: update(challenge, this.setState({
challenge: update(challenge,
{ {
praise_count: { $set: praise_count }, praise_count: { $set: praise_count },
user_praise: { $set: praise }, user_praise: { $set: praise },
@ -272,7 +273,7 @@ pop_box_new(htmlvalue, 480, 182);
// challenge = Object.assign({}, challenge) // challenge = Object.assign({}, challenge)
// challenge.pathIndex = index; // challenge.pathIndex = index;
this.setState({ this.setState({
challenge: update(challenge, {pathIndex: { $set: index }}), challenge: update(challenge, { pathIndex: { $set: index } }),
}, () => { }, () => {
callback && callback() callback && callback()
}) })
@ -290,15 +291,16 @@ pop_box_new(htmlvalue, 480, 182);
challenge.path = path; challenge.path = path;
const newChallenge = this.handleChallengePath(challenge); const newChallenge = this.handleChallengePath(challenge);
this.setState({ challenge: newChallenge, this.setState({
myshixun: update(myshixun, {system_tip: { $set: false }}), challenge: newChallenge,
myshixun: update(myshixun, { system_tip: { $set: false } }),
}) })
} }
handleChallengePath(challenge) { handleChallengePath(challenge) {
if (challenge.path && typeof challenge.path === "string") { // 多path的处理 if (challenge.path && typeof challenge.path === "string") { // 多path的处理
let path = challenge.path.split(''); let path = challenge.path.split('');
_.remove(path, (item)=> !item) _.remove(path, (item) => !item)
if (path.length > 1) { if (path.length > 1) {
challenge.path = path; challenge.path = path;
challenge.multiPath = true; challenge.multiPath = true;
@ -376,10 +378,10 @@ pop_box_new(htmlvalue, 480, 182);
} else { // 选择题 } else { // 选择题
// 选择题题干markdown初始化 // 选择题题干markdown初始化
const $ = window.$ const $ = window.$
window.setTimeout(()=>{ window.setTimeout(() => {
var lens = $("#choiceRepositoryView textarea").length; 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, { window.editormd.markdownToHTML("choose_subject_" + i, {
htmlDecode: "style,script,iframe", // you can filter tags decode htmlDecode: "style,script,iframe", // you can filter tags decode
taskList: true, taskList: true,
@ -502,7 +504,7 @@ pop_box_new(htmlvalue, 480, 182);
fetchAll(stageId, noTimeout) { fetchAll(stageId, noTimeout) {
if (window.__fetchAllFlag == true ) { if (window.__fetchAllFlag == true) {
console.log('TPIContextProvider call fetchAll repeatly!') console.log('TPIContextProvider call fetchAll repeatly!')
return; return;
} }
@ -575,7 +577,7 @@ pop_box_new(htmlvalue, 480, 182);
if (resData.final_score) { if (resData.final_score) {
var game = this.state.game; var game = this.state.game;
this.setState({ this.setState({
game: update(game, {final_score: { $set: resData.final_score }}), game: update(game, { final_score: { $set: resData.final_score } }),
grade: resData.grade grade: resData.grade
}) })
} else { } else {
@ -589,7 +591,7 @@ pop_box_new(htmlvalue, 480, 182);
this.setState({ this.setState({
game: (this.state.game.status == 2 ? update(this.state.game, { game: (this.state.game.status == 2 ? update(this.state.game, {
isPassThrough: { $set: true }, isPassThrough: { $set: true },
}) : this.state.game) , }) : this.state.game),
currentGamePassed: false currentGamePassed: false
}) })
} }
@ -625,7 +627,8 @@ pop_box_new(htmlvalue, 480, 182);
window.clearTimeout(this.showWebDisplayButtonTimeout) window.clearTimeout(this.showWebDisplayButtonTimeout)
} }
this.showWebDisplayButtonTimeout = window.setTimeout(() => { this.showWebDisplayButtonTimeout = window.setTimeout(() => {
this.setState({ challenge: update(challenge, this.setState({
challenge: update(challenge,
{ {
showWebDisplayButton: { $set: false }, showWebDisplayButton: { $set: false },
}) })
@ -657,7 +660,7 @@ pop_box_new(htmlvalue, 480, 182);
language_display(data) { language_display(data) {
const { game, tomcat_url } = this.state; const { game, tomcat_url } = this.state;
const challenge = Object.assign({}, this.state.challenge) const challenge = Object.assign({}, this.state.challenge)
if(challenge.isWeb && data.port != -1) { if (challenge.isWeb && data.port != -1) {
// var $result = $("#php_display"); // var $result = $("#php_display");
challenge.showWebDisplayButton = true; // ActionView处是否出现查看效果按钮 challenge.showWebDisplayButton = true; // ActionView处是否出现查看效果按钮
this.initDisplayInterval() this.initDisplayInterval()
@ -675,7 +678,7 @@ pop_box_new(htmlvalue, 480, 182);
// }); // });
// challenge.showLanguagePictrue = true; // challenge.showLanguagePictrue = true;
// } // }
else if(data.picture != 0){ else if (data.picture != 0) {
// 对应服务端erb文件为 _picture_display.html.erb // 对应服务端erb文件为 _picture_display.html.erb
// $.ajax({ // $.ajax({
// url: "/users/picture_show?game_id="+data.picture, // 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_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_passed_testsests_public_count, final_score, gold, experience, latest_output, status
, had_done, score, tag_count, power, record, next_game, grade, picture, , 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; const { game } = this.state;
@ -812,7 +815,7 @@ pop_box_new(htmlvalue, 480, 182);
this.setState({ this.setState({
output_sets: output_sets, output_sets: output_sets,
grade: this.state.grade + deltaScore, 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) testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0)
}) })
this.handleGdialogClose(); this.handleGdialogClose();
@ -917,14 +920,14 @@ pop_box_new(htmlvalue, 480, 182);
> >
<DialogTitle id="alert-dialog-title">{"提示"}</DialogTitle> <DialogTitle id="alert-dialog-title">{"提示"}</DialogTitle>
<DialogContent id="dialog-content"> <DialogContent id="dialog-content">
<DialogContentText id="alert-dialog-description" style={{textAlign: 'center'}}> <DialogContentText id="alert-dialog-description" style={{ textAlign: 'center' }}>
{this.state.gDialogContentText} {this.state.gDialogContentText}
</DialogContentText> </DialogContentText>
</DialogContent> </DialogContent>
{/* mb20 加了有样式问题 */} {/* mb20 加了有样式问题 */}
<DialogActions className={""} id="dialog-actions"> <DialogActions className={""} id="dialog-actions">
{ this.isSingleButton ? <div className="task-popup-submit clearfix" {this.isSingleButton ? <div className="task-popup-submit clearfix"
style={{ textAlign: 'center', 'margin-bottom': '14px'}}> style={{ textAlign: 'center', 'margin-bottom': '14px' }}>
<a className="task-btn task-btn-orange" <a className="task-btn task-btn-orange"
onClick={this.handleGdialogClose} onClick={this.handleGdialogClose}
>知道啦</a> >知道啦</a>
@ -935,10 +938,10 @@ pop_box_new(htmlvalue, 480, 182);
关闭 关闭
</Button> </Button>
<Button variant="raised" className={`${classes.button} ${classes.borderRadiusNone}`} <Button variant="raised" className={`${classes.button} ${classes.borderRadiusNone}`}
onClick={() => this.onGdialogOkBtnClick() } color="primary" autoFocus> onClick={() => this.onGdialogOkBtnClick()} color="primary" autoFocus>
{ this.okButtonText ? this.okButtonText : '确定' } {this.okButtonText ? this.okButtonText : '确定'}
</Button> </Button>
</React.Fragment> } </React.Fragment>}
{this.moreButtonsRender && this.moreButtonsRender()} {this.moreButtonsRender && this.moreButtonsRender()}
</DialogActions> </DialogActions>
</Dialog> </Dialog>
@ -947,10 +950,11 @@ pop_box_new(htmlvalue, 480, 182);
className={"rootSnackbar"} className={"rootSnackbar"}
open={this.state.snackbarOpen} open={this.state.snackbarOpen}
autoHideDuration={3000} autoHideDuration={3000}
anchorOrigin={{ vertical: this.state.snackbarVertical || 'top' anchorOrigin={{
, horizontal: this.state.snackbarHorizontal || 'center' }} vertical: this.state.snackbarVertical || 'top'
, horizontal: this.state.snackbarHorizontal || 'center'
}}
onClose={() => this.handleSnackbarClose()} onClose={() => this.handleSnackbarClose()}
transition={Fade}
SnackbarContentProps={{ SnackbarContentProps={{
'aria-describedby': 'message-id', '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 { .page--header {
z-index: 101 !important; z-index: 101 !important;
} }
.ant-popover-buttons { .ant-popover-buttons {
text-align: center !important; text-align: center !important;
} }
@ -17,24 +18,121 @@ body {
z-index: 1; z-index: 1;
} }
/* 隐藏newMessage提示按钮 */ #root,
#shixun_comment_block .buttons > p:last-child { .app {
display: none !important; 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;*/
/*}*/ /* antd扩展 */
.ant-upload-list-item-info .anticon-loading, .ant-upload-list-item-info .anticon-paper-clip{ .formItemInline.ant-form-item {
color: #29bd8b !important; 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{ .indexHOC {
z-index: 1000 !important; position: relative;
} }

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

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

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

@ -1,29 +1,23 @@
import React, { Component } from 'react'; 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 { Dialog } from '@material-ui/core';
import 'rc-pagination/assets/index.css'; 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 { getImageUrl } from 'educoder';
import { FormControl, FormHelperText } from 'material-ui/Form';
import CommentItemKEEditor from './CommentItemKEEditor'; import CommentItemKEEditor from './CommentItemKEEditor';
import CommentItemMDEditor from './CommentItemMDEditor'; import CommentItemMDEditor from './CommentItemMDEditor';
import './Comment.css' import './Comment.css'
import Modals from '../modals/Modals' 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"); $(document).off("onReply");
} }
componentDidMount() { componentDidMount() {
setTimeout(()=>{ setTimeout(() => {
const $ = window.$; const $ = window.$;
// 绑定后会自动off 加timeout试试 // 绑定后会自动off 加timeout试试
$(document).on("onReply", (e, args)=>{ $(document).on("onReply", (e, args) => {
const { commentContent, id, editor } = args; const { commentContent, id, editor } = args;
this.props.replyComment(commentContent, id, editor) this.props.replyComment(commentContent, id, editor)
@ -126,15 +120,15 @@ class Comments extends Component {
var id = comment.id var id = comment.id
var reply_message_el = `#reply_message_${id}` var reply_message_el = `#reply_message_${id}`
var reply_iconup_el = `#reply_iconup_${id}` var reply_iconup_el = `#reply_iconup_${id}`
if($(reply_message_el).html() == "") { if ($(reply_message_el).html() == "") {
$(".reply_to_message").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_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(); $(reply_iconup_el).show();
$(function(){ $(function () {
window.sd_create_editor_from_data(id ,null,"100%", "Discuss"); window.sd_create_editor_from_data(id, null, "100%", "Discuss");
}); });
}else { } else {
if ($(reply_message_el).is(':visible')) { if ($(reply_message_el).is(':visible')) {
$(reply_message_el).hide(); $(reply_message_el).hide();
} else { } else {
@ -161,7 +155,7 @@ class Comments extends Component {
return '' return ''
} }
const { user } = this.props; const { user } = this.props;
let childCommentsElement = comment.children.map((item, index) =>{ let childCommentsElement = comment.children.map((item, index) => {
let _content = this.parseCommentContent(item.content); let _content = this.parseCommentContent(item.content);
return ( return (
@ -175,11 +169,11 @@ class Comments extends Component {
{/* { item.position ? <span className="fl color-light-green font-14 ml15">[第{item.position}关]</span> : ""} */} {/* { item.position ? <span className="fl color-light-green font-14 ml15">[第{item.position}关]</span> : ""} */}
{ {
item.reward ? item.reward ?
<Tooltip title={ `已奖励金币${item.reward}` } disableFocusListener={true}> <Tooltip title={`已奖励金币${item.reward}`} disableFocusListener={true}>
<a href="javascript:void(0);" style={{ marginLeft: '20px', cursor: 'default'}} <a href="javascript:void(0);" style={{ marginLeft: '20px', cursor: 'default' }}
className={`rewarded color-grey-8 font-12 fl ${ item.admin === true ? '': 'normalUser'}`} 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> </a>
</Tooltip> : '' </Tooltip> : ''
} }
@ -190,26 +184,26 @@ class Comments extends Component {
</span> </span>
{this.props.showRewardButton != false && comment.admin === true ? {this.props.showRewardButton != false && comment.admin === true ?
<a href="javascript:void(0);" className="color-grey-8" onClick={() => this.showGoldRewardDialog(comment, item) }> <a href="javascript:void(0);" className="color-grey-8" onClick={() => this.showGoldRewardDialog(comment, item)}>
<Tooltip title={ "给TA奖励金币" } disableFocusListener={true}> <Tooltip title={"给TA奖励金币"} disableFocusListener={true}>
<i className="iconfont icon-jiangli fl"></i> <i className="iconfont icon-jiangli fl"></i>
</Tooltip> </Tooltip>
</a> </a>
:""} : ""}
{/*子回复还没hidden字段*/} {/*子回复还没hidden字段*/}
{false && comment.admin === true ? {false && comment.admin === true ?
<Tooltip title={ item.hidden ? "取消隐藏" : "隐藏评论" }> <Tooltip title={item.hidden ? "取消隐藏" : "隐藏评论"}>
<a href="javascript:void(0);" className="color-grey-8" onClick={() => this.onCommentBtnClick(comment, item, item.hidden ? 'hiddenCancel' : '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> <i className={`fa ${item.hidden ? 'fa-eye' : 'fa-eye-slash'} mr5`}></i>
</a> </a>
</Tooltip> </Tooltip>
:""} : ""}
{/* 新版user_id不准获取方式不对 */} {/* 新版user_id不准获取方式不对 */}
{ comment.admin === true || item.can_delete || item.user_id === user.user_id || item.user_login == user.login ? {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') }> <a href="javascript:void(0);" className="color-grey-8" id="delete_reply_118_952" onClick={() => this.onCommentBtnClick(comment, item, 'delete')}>
<Tooltip title={ "删除" } disableFocusListener={true}> <Tooltip title={"删除"} disableFocusListener={true}>
<i className="iconfont icon-shanchu mr5"></i> <i className="iconfont icon-shanchu mr5"></i>
</Tooltip> </Tooltip>
</a> </a>
@ -242,7 +236,7 @@ class Comments extends Component {
<div className="comment_content clearfix" id={`reply_content_${item.id}`}> <div className="comment_content clearfix" id={`reply_content_${item.id}`}>
<div className="color-grey-3" 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 className="cl"></div>
</div> </div>
</div> </div>
@ -291,13 +285,13 @@ class Comments extends Component {
<div className="comment_item_cont df clearfix" key={index}> <div className="comment_item_cont df clearfix" key={index}>
<div className="J_Comment_Face fl"> <div className="J_Comment_Face fl">
<a href={`${_origin}/users/${item.user_login}`} target="_blank"> <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> </a>
</div> </div>
<div className="t_content fl"> <div className="t_content fl">
<div className="J_Comment_Reply"> <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"> <div className="J_Comment_Info clearfix mt3">
@ -306,9 +300,9 @@ class Comments extends Component {
{item.username} {item.username}
</a> </a>
<span className="t_area fl">{item.time}</span> <span className="t_area fl">{item.time}</span>
{ item.position && <span className="fl color-light-green font-14 ml15">[{item.position}]</span> } {item.position && <span className="fl color-light-green font-14 ml15">[{item.position}]</span>}
{ item.game_url ? {item.game_url ?
<Tooltip title={ `点击查看TA的代码页面` } disableFocusListener={true}> <Tooltip title={`点击查看TA的代码页面`} disableFocusListener={true}>
<a href={item.game_url} target="_blank" className="fl font-14 ml15" <a href={item.game_url} target="_blank" className="fl font-14 ml15"
style={{ color: "#4CACFF", cursor: "pointer" }} style={{ color: "#4CACFF", cursor: "pointer" }}
>查看</a> >查看</a>
@ -316,9 +310,9 @@ class Comments extends Component {
{ {
item.reward ? item.reward ?
<Tooltip title={ `已奖励金币${item.reward}` } disableFocusListener={true}> <Tooltip title={`已奖励金币${item.reward}`} disableFocusListener={true}>
<a href="javascript:void(0);" style={{ marginLeft: '20px', cursor: 'default'}} <a href="javascript:void(0);" style={{ marginLeft: '20px', cursor: 'default' }}
className={`rewarded color-grey-8 font-12 fl ${ item.admin === true ? '': 'normalUser'}`} 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> <i className="iconfont icon-gift mr5 color-orange fl"></i><span className="fl">{item.reward}</span>
</a> </a>
@ -346,17 +340,17 @@ class Comments extends Component {
|| !this.props.onlySuperAdminCouldHide && item.admin === false && (item.manager === false || item.manager == undefined)) || !this.props.onlySuperAdminCouldHide && item.admin === false && (item.manager === false || item.manager == undefined))
? <p className="color-orange font-16">违规评论已被屏蔽</p> ? <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 className="cl"></div>
</div> </div>
</div> </div>
<div className="childrenCommentsView"> <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)} {this.renderChildenComments(item)}
{ item.isAllChildrenLoaded != true && item.children && this.props.isChildCommentPagination == true && item.child_message_count > 5? {item.isAllChildrenLoaded != true && item.children && this.props.isChildCommentPagination == true && item.child_message_count > 5 ?
<Tooltip title={ "点击查看更多回复" } disableFocusListener={true}> <Tooltip title={"点击查看更多回复"} disableFocusListener={true}>
<div className="loadMoreChildComments" onClick={() => {this.props.loadMoreChildComments && this.props.loadMoreChildComments(item)}}> <div className="loadMoreChildComments" onClick={() => { this.props.loadMoreChildComments && this.props.loadMoreChildComments(item) }}>
<i className="iconfont icon-xiajiantou"></i> <i className="iconfont icon-xiajiantou"></i>
</div> </div>
</Tooltip> </Tooltip>
@ -369,36 +363,36 @@ class Comments extends Component {
{/* && !item.reward */} {/* && !item.reward */}
{this.props.showRewardButton != false && item.admin === true ? {this.props.showRewardButton != false && item.admin === true ?
<a href="javascript:void(0);" className="color-grey-8 fl mt2" onClick={() => this.showGoldRewardDialog(item) }> <a href="javascript:void(0);" className="color-grey-8 fl mt2" onClick={() => this.showGoldRewardDialog(item)}>
<Tooltip title={ "给TA奖励金币" } disableFocusListener={true}> <Tooltip title={"给TA奖励金币"} disableFocusListener={true}>
<i className="iconfont icon-jiangli mr5 fl"></i> <i className="iconfont icon-jiangli mr5 fl"></i>
</Tooltip> </Tooltip>
</a> </a>
:""} : ""}
{ this.props.showHiddenButton == true {this.props.showHiddenButton == true
&& (this.props.onlySuperAdminCouldHide && item.isSuperAdmin || !this.props.onlySuperAdminCouldHide && item.admin === true) ? && (this.props.onlySuperAdminCouldHide && item.isSuperAdmin || !this.props.onlySuperAdminCouldHide && item.admin === true) ?
<Tooltip title={ item.hidden ? "取消隐藏" : "隐藏评论" } disableFocusListener={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') }> <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> <i className={` ${item.hidden ? 'iconfont icon-yincangbiyan' : 'fa fa-eye'} mr5`}></i>
</a> </a>
</Tooltip> </Tooltip>
:""} : ""}
{ item.admin && ( !item.children || item.children.length === 0 )? {item.admin && (!item.children || item.children.length === 0) ?
<a href="javascript:void(0);" className="color-grey-8" onClick={() => this.onCommentBtnClick(item, '', 'delete') }> <a href="javascript:void(0);" className="color-grey-8" onClick={() => this.onCommentBtnClick(item, '', 'delete')}>
<Tooltip title={ "删除" } disableFocusListener={true}> <Tooltip title={"删除"} disableFocusListener={true}>
<i className="iconfont icon-shanchu mr5"></i> <i className="iconfont icon-shanchu mr5"></i>
</Tooltip> </Tooltip>
</a> : '' } </a> : ''}
{/* <span className="ml5 mr5 color-grey-8">|</span>*/} {/* <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" {(this.props.showReply == undefined || this.props.showReply == true) && <a href={`javascript:void(0)`} className="color-grey-8"
onClick={() => this.initReply(item) } > onClick={() => this.initReply(item)} >
<Tooltip title={ "回复" }> <Tooltip title={"回复"}>
<i className="iconfont icon-huifu1 mr5"></i> <i className="iconfont icon-huifu1 mr5"></i>
</Tooltip> </Tooltip>
</a>} </a>}
@ -406,17 +400,17 @@ class Comments extends Component {
{/* <span className="ml5 mr5 color-grey-8">|</span>*/} {/* <span className="ml5 mr5 color-grey-8">|</span>*/}
<span className="reply_praise_count_952"> <span className="reply_praise_count_952">
<Tooltip title={ item.user_praise ? "取消点赞" : "点赞" }> <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)}> <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> <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> </a>
</Tooltip> </Tooltip>
</span> </span>
</p> </p>
{/* __useKindEditor暂时没用到了TODO 可以去掉 */} {/* __useKindEditor暂时没用到了TODO 可以去掉 */}
{ window.__useKindEditor ? <CommentItemKEEditor showReplyEditorFlag={showReplyEditorFlag} {window.__useKindEditor ? <CommentItemKEEditor showReplyEditorFlag={showReplyEditorFlag}
currentReplyComment={currentReplyComment} currentReplyComment={currentReplyComment}
item={item} item={item}
user={user} user={user}
@ -454,7 +448,7 @@ class Comments extends Component {
onCommentBtnClick(comment, childComment, dialogType) { onCommentBtnClick(comment, childComment, dialogType) {
this.comment = comment; this.comment = comment;
this.childComment = childComment; this.childComment = childComment;
this.setState({dialogOpen: true, dialogType: dialogType}) this.setState({ dialogOpen: true, dialogType: dialogType })
} }
handleDialogClose() { handleDialogClose() {
this.setState({ this.setState({
@ -467,18 +461,18 @@ class Comments extends Component {
const { dialogType } = this.state; const { dialogType } = this.state;
if (dialogType === 'delete') { if (dialogType === 'delete') {
deleteComment(this.comment, this.childComment ? this.childComment.id : '') 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 : '') hiddenComment(this.comment, this.childComment ? this.childComment.id : '')
} }
this.setState({dialogOpen: false}) this.setState({ dialogOpen: false })
} }
showGoldRewardDialog(comment, childComment) { showGoldRewardDialog(comment, childComment) {
if (comment.admin === true) { if (comment.admin === true) {
this.comment = comment; this.comment = comment;
this.childComment = childComment; this.childComment = childComment;
this.setState({goldRewardDialogOpen: true}) this.setState({ goldRewardDialogOpen: true })
} }
} }
handleGoldRewardDialogClose() { handleGoldRewardDialogClose() {
@ -490,11 +484,11 @@ class Comments extends Component {
console.log('onGoldRewardDialogOkBtnClick') console.log('onGoldRewardDialogOkBtnClick')
const { goldRewardInput } = this.state; const { goldRewardInput } = this.state;
// || goldRewardInput.indexOf('-') !== -1 // || goldRewardInput.indexOf('-') !== -1
if (!goldRewardInput || goldRewardInput === '0' ) { if (!goldRewardInput || goldRewardInput === '0') {
this.setState({ goldRewardInputError: true}) this.setState({ goldRewardInputError: true })
return; return;
} else { } else {
this.setState({goldRewardDialogOpen: false}) this.setState({ goldRewardDialogOpen: false })
this.props.rewardCode(this.comment, this.childComment, goldRewardInput) 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 { deleteComment, onPaginationChange, comment_count_without_reply, currentPage, comments, usingAntdModal } = this.props;
const { dialogOpen, goldRewardDialogOpen, dialogType, goldRewardInputError } = this.state; const { dialogOpen, goldRewardDialogOpen, dialogType, goldRewardInputError } = this.state;
const goldRewardInputErrorObj = goldRewardInputError ? {'error': 'error'} : {} const goldRewardInputErrorObj = goldRewardInputError ? { 'error': 'error' } : {}
return ( return (
<div className="fit -scroll" style={{ 'overflow-x': 'hidden'}}> <div className="fit -scroll" style={{ 'overflow-x': 'hidden' }}>
{ usingAntdModal ? <Modals {usingAntdModal ? <Modals
modalsType={dialogOpen} modalsType={dialogOpen}
modalsTopval={ modalsTopval={
dialogType === 'delete' ? '确定要删除该条回复吗?' dialogType === 'delete' ? '确定要删除该条回复吗?'
@ -535,7 +529,7 @@ class Comments extends Component {
> >
<DialogTitle id="alert-dialog-title">{"提示"}</DialogTitle> <DialogTitle id="alert-dialog-title">{"提示"}</DialogTitle>
<DialogContent> <DialogContent>
<DialogContentText id="alert-dialog-description" style={{textAlign: 'center'}}> <DialogContentText id="alert-dialog-description" style={{ textAlign: 'center' }}>
{ {
dialogType === 'delete' ? '确定要删除该条回复吗?' dialogType === 'delete' ? '确定要删除该条回复吗?'
: dialogType === 'hidden' ? '确定要隐藏该条回复吗?' : dialogType === 'hidden' ? '确定要隐藏该条回复吗?'
@ -548,7 +542,7 @@ class Comments extends Component {
取消 取消
</Button> </Button>
<Button variant="raised" <Button variant="raised"
onClick={() => this.onDialogOkBtnClick() } color="primary" autoFocus> onClick={() => this.onDialogOkBtnClick()} color="primary" autoFocus>
确定 确定
</Button> </Button>
</DialogActions> </DialogActions>
@ -564,7 +558,7 @@ class Comments extends Component {
<DialogContent> <DialogContent>
<InputNumber placeholder="请输入奖励的金币数量" id="goldReward" type="number" value={this.state.goldRewardInput} <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"> {/* <FormControl { ...goldRewardInputErrorObj } aria-describedby="name-error-text">
<InputLabel htmlFor="goldReward">请输入奖励的金币数量</InputLabel> <InputLabel htmlFor="goldReward">请输入奖励的金币数量</InputLabel>
@ -579,7 +573,7 @@ class Comments extends Component {
取消 取消
</Button> </Button>
<Button variant="raised" <Button variant="raised"
onClick={() => this.onGoldRewardDialogOkBtnClick() } color="primary" autoFocus> onClick={() => this.onGoldRewardDialogOkBtnClick()} color="primary" autoFocus>
确定 确定
</Button> </Button>
</DialogActions> </DialogActions>
@ -592,12 +586,12 @@ class Comments extends Component {
{this.renderComments()} {this.renderComments()}
</div> </div>
{ (comment_count_without_reply > 10 ) ? {(comment_count_without_reply > 10) ?
<div className="paginationSection"> <div className="paginationSection">
<Pagination showQuickJumper onChange={onPaginationChange} current={currentPage} total={comment_count_without_reply} /> <Pagination showQuickJumper onChange={onPaginationChange} current={currentPage} total={comment_count_without_reply} />
</div> </div>
: '' } : ''}
{ (comment_count_without_reply == 0) ? <div> {(comment_count_without_reply == 0) ? <div>
<div className="edu-tab-con-box clearfix edu-txt-center"> <div className="edu-tab-con-box clearfix edu-txt-center">
<img className="edu-nodata-img mb20" <img className="edu-nodata-img mb20"
@ -605,7 +599,7 @@ class Comments extends Component {
<p className="edu-nodata-p mb20">暂时还没有相关数据哦</p> <p className="edu-nodata-p mb20">暂时还没有相关数据哦</p>
</div> </div>
</div> </div>
: '' } : ''}
</div> </div>
</div> </div>

@ -1,5 +1,4 @@
import React from 'react' import React from 'react'
import ReactDOM from 'react-dom'
import axios from 'axios' import axios from 'axios'
import { notification } from 'antd' import { notification } from 'antd'
import update from 'immutability-helper' import update from 'immutability-helper'
@ -74,7 +73,7 @@ export function commentHOC(WrappedComponent) {
login: "p24891375" login: "p24891375"
name: "杨俊男" name: "杨俊男"
user_url: "/users/p24891375" user_url: "/users/p24891375"
*/ */
handleComments(comments, responseData) { handleComments(comments, responseData) {
comments.forEach(element => { comments.forEach(element => {
if (element.children) { if (element.children) {
@ -98,7 +97,7 @@ export function commentHOC(WrappedComponent) {
const { challenge, shixun, match } = this.props; const { challenge, shixun, match } = this.props;
// const url = `/api/v1/shixuns/${shixun.id}/shixun_discusses?page=${page-1}&container_type=Shixun` // const url = `/api/v1/shixuns/${shixun.id}/shixun_discusses?page=${page-1}&container_type=Shixun`
const url = 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` shixun.identifier : match.params.shixunId}&container_type=Shixun`
this.setState({ this.setState({
@ -108,7 +107,7 @@ export function commentHOC(WrappedComponent) {
// test // test
// if (true) { // if (true) {
if (false) { 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({ this.setState({
comments: data.children_list, comments: data.children_list,
@ -135,7 +134,7 @@ export function commentHOC(WrappedComponent) {
currentPage: page, currentPage: page,
loadingComments: false, loadingComments: false,
}, ()=>{ }, () => {
// keditor代码美化 // keditor代码美化
window.prettyPrint() window.prettyPrint()
}) })
@ -172,10 +171,10 @@ export function commentHOC(WrappedComponent) {
// const url = `/api/v1/discusses` // const url = `/api/v1/discusses`
const url = `/discusses.json` const url = `/discusses.json`
if(content != undefined){ if (content != undefined) {
var beforeImage = content.split("<img"); var beforeImage = content.split("<img");
var afterImage = content.split("/>"); var afterImage = content.split("/>");
if(beforeImage[0] == "" && afterImage[1] == ""){ if (beforeImage[0] == "" && afterImage[1] == "") {
window.notice_box('不支持纯图片评论<br/>请在评论中增加文字信息'); window.notice_box('不支持纯图片评论<br/>请在评论中增加文字信息');
return; return;
} }
@ -184,7 +183,7 @@ export function commentHOC(WrappedComponent) {
$("#new_message_submit_btn_" + this.props.challenge.shixun_id).hide(); $("#new_message_submit_btn_" + this.props.challenge.shixun_id).hide();
if (content) { // 去掉尾部的回车换行 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, { axios.post(url, {
@ -220,7 +219,7 @@ export function commentHOC(WrappedComponent) {
} else { } else {
comments = arg_comments; comments = arg_comments;
} }
for(let i = 0; i < comments.length; i++) { for (let i = 0; i < comments.length; i++) {
if (id === comments[i].id) { if (id === comments[i].id) {
return i; return i;
} }
@ -237,7 +236,7 @@ export function commentHOC(WrappedComponent) {
// const url = `/api/v1/discusses/${id}/reply` // const url = `/api/v1/discusses/${id}/reply`
const url = `/discusses/${id}/reply.json` const url = `/discusses/${id}/reply.json`
if (commentContent) { 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) { if (!user.login && user.user_url) {
const loginAr = user.user_url.split('/') const loginAr = user.user_url.split('/')
@ -259,13 +258,13 @@ export function commentHOC(WrappedComponent) {
var commentIndex = this._findCommentById(id); var commentIndex = this._findCommentById(id);
let comment = comments[commentIndex] let comment = comments[commentIndex]
comment = Object.assign({}, comment) comment = Object.assign({}, comment)
if (!comment.children ) { if (!comment.children) {
comment.children = [] comment.children = []
} else { } else {
comment.children = comment.children.slice(0); comment.children = comment.children.slice(0);
} }
// TODO userName iamge_url // TODO userName iamge_url
comment.children.push( { comment.children.push({
"can_delete": true, "can_delete": true,
"content": commentContent, "content": commentContent,
@ -298,7 +297,7 @@ export function commentHOC(WrappedComponent) {
this.setState({ this.setState({
// runTesting: false, // runTesting: false,
comments: comments comments: comments
}, ()=>{ }, () => {
// keditor代码美化 // keditor代码美化
editor.html && window.prettyPrint() editor.html && window.prettyPrint()
}) })
@ -373,7 +372,7 @@ export function commentHOC(WrappedComponent) {
// https://stackoverflow.com/questions/29527385/removing-element-from-array-in-component-state // https://stackoverflow.com/questions/29527385/removing-element-from-array-in-component-state
if (!childCommentId) { if (!childCommentId) {
this.setState((prevState) => ({ this.setState((prevState) => ({
comments: update(prevState.comments, {$splice: [[commentIndex, 1]]}) comments: update(prevState.comments, { $splice: [[commentIndex, 1]] })
})) }))
if (this.state.comments.length <= 5) { if (this.state.comments.length <= 5) {
@ -383,7 +382,7 @@ export function commentHOC(WrappedComponent) {
let comments = this.state.comments; let comments = this.state.comments;
let newComments = Object.assign({}, comments) let newComments = Object.assign({}, comments)
let childCommentIndex = this._findCommentById(childCommentId, newComments[commentIndex].children); 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 }) this.setState({ newComments })
} }
} }
@ -551,12 +550,12 @@ export function commentHOC(WrappedComponent) {
componentDidMount() { componentDidMount() {
// commentsDelegateParent #game_left_contents #tab_con_4 // commentsDelegateParent #game_left_contents #tab_con_4
$(".commentsDelegateParent") $(".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 const imageSrc = event.target.src
// 非回复里的头像图片; 非emoticons // 非回复里的头像图片; 非emoticons
if (imageSrc.indexOf('/images/avatars/User') === -1 && if (imageSrc.indexOf('/images/avatars/User') === -1 &&
imageSrc.indexOf('kindeditor/plugins/emoticons') === -1 ) { imageSrc.indexOf('kindeditor/plugins/emoticons') === -1) {
this.setState({ this.setState({
showImage: true, showImage: true,
imageSrc, imageSrc,
@ -596,7 +595,7 @@ export function commentHOC(WrappedComponent) {
hiddenComment={this.hiddenComment} hiddenComment={this.hiddenComment}
rewardCode={this.rewardCode} rewardCode={this.rewardCode}
onPaginationChange={this.onPaginationChange} onPaginationChange={this.onPaginationChange}
showNotification= { this.showNotification } showNotification={this.showNotification}
newMessage={this.newMessage} newMessage={this.newMessage}
showNewReply={this.showNewReply} showNewReply={this.showNewReply}
></WrappedComponent> ></WrappedComponent>

@ -1,17 +1,12 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import Dialog, { import DialogActions from '@material-ui/core/DialogActions';
DialogActions, import DialogContent from '@material-ui/core/DialogContent';
DialogContent, import DialogTitle from '@material-ui/core/DialogTitle';
DialogContentText, import Dialog from '@material-ui/core/Dialog';
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 Button from '@material-ui/core/Button';
import { InputNumber } from 'antd'
class RewardDialog extends Component { class RewardDialog extends Component {
constructor(props) { constructor(props) {
@ -29,7 +24,7 @@ class RewardDialog extends Component {
if (comment.admin === true) { if (comment.admin === true) {
this.comment = comment; this.comment = comment;
this.childComment = childComment; this.childComment = childComment;
this.setState({goldRewardDialogOpen: true}) this.setState({ goldRewardDialogOpen: true })
} }
} }
@ -44,7 +39,7 @@ class RewardDialog extends Component {
// this.setState({ goldRewardInputError: true}) // this.setState({ goldRewardInputError: true})
return; return;
} else { } else {
this.props.setRewardDialogVisible( false ) this.props.setRewardDialogVisible(false)
this.props.rewardCode(goldRewardInput) this.props.rewardCode(goldRewardInput)
} }
} }
@ -54,13 +49,13 @@ class RewardDialog extends Component {
if (Number.isNaN(number)) { if (Number.isNaN(number)) {
return; return;
} }
this.setState({ goldRewardInput: number , goldRewardInputError: false }); this.setState({ goldRewardInput: number, goldRewardInputError: false });
} }
render() { render() {
const { goldRewardDialogOpen } = this.props; const { goldRewardDialogOpen } = this.props;
const { goldRewardInputError } = this.state; const { goldRewardInputError } = this.state;
const goldRewardInputErrorObj = goldRewardInputError ? {'error': 'error'} : {} const goldRewardInputErrorObj = goldRewardInputError ? { 'error': 'error' } : {}
return ( return (
<Dialog <Dialog
@ -77,23 +72,15 @@ class RewardDialog extends Component {
<DialogTitle id="alert-dialog-title">{"奖励设置"}</DialogTitle> <DialogTitle id="alert-dialog-title">{"奖励设置"}</DialogTitle>
<DialogContent> <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} <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> */}
{/*<DialogContentText id="alert-dialog-description" style={{textAlign: 'center'}}> </DialogContentText>*/}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={this.handleGoldRewardDialogClose} color="primary"> <Button onClick={this.handleGoldRewardDialogClose} color="primary">
取消 取消
</Button> </Button>
<Button variant="raised" <Button variant="raised"
onClick={() => this.onGoldRewardDialogOkBtnClick() } color="primary" autoFocus> onClick={() => this.onGoldRewardDialogOkBtnClick()} color="primary" autoFocus>
确定 确定
</Button> </Button>
</DialogActions> </DialogActions>

@ -1,11 +1,4 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Redirect } from 'react-router';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import PropTypes from 'prop-types';
import classNames from 'classnames'
import axios from 'axios' import axios from 'axios'
@ -13,9 +6,6 @@ import moment from 'moment'
import Comments from '../../comment/Comments' 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 MemoDetailMDEditor from '../../forums/MemoDetailMDEditor'
import { RouteHOC } from './common.js' import { RouteHOC } from './common.js'
@ -24,12 +14,14 @@ import '../../forums/RightSection.css'
import './TopicDetail.css' import './TopicDetail.css'
import '../common/courseMessage.css' import '../common/courseMessage.css'
import { Pagination, Tooltip } from 'antd' 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 SendToCourseModal from '../coursesPublic/modal/SendToCourseModal'
import CBreadcrumb from '../common/CBreadcrumb' import CBreadcrumb from '../common/CBreadcrumb'
import { generateComments, generateChildComments, _findById, handleContentBeforeCreateNew, addNewComment import {
, addSecondLevelComment, NEED_TO_WRITE_CONTENT, handleContentBeforeCreateSecondLevelComment generateComments, generateChildComments, _findById, handleContentBeforeCreateNew, addNewComment
, handleDeleteComment, handleCommentPraise, handleHiddenComment } from '../common/CommentsHelper' , addSecondLevelComment, handleContentBeforeCreateSecondLevelComment
, handleDeleteComment, handleCommentPraise, handleHiddenComment
} from '../common/CommentsHelper'
const $ = window.$ const $ = window.$
const REPLY_PAGE_COUNT = 10 const REPLY_PAGE_COUNT = 10
@ -57,11 +49,11 @@ class TopicDetail extends Component {
pageCount: 1, pageCount: 1,
comments: [], comments: [],
goldRewardDialogOpen: false, goldRewardDialogOpen: false,
author:undefined author: undefined
} }
} }
componentDidMount() { componentDidMount() {
window.$("html,body").animate({"scrollTop":0}) window.$("html,body").animate({ "scrollTop": 0 })
const topicId = this.props.match.params.topicId const topicId = this.props.match.params.topicId
const bid = this.props.match.params.boardId const bid = this.props.match.params.boardId
@ -70,7 +62,7 @@ class TopicDetail extends Component {
this.setState({ this.setState({
memoLoading: true memoLoading: true
}) })
axios.get(memoUrl,{ axios.get(memoUrl, {
}) })
.then((response) => { .then((response) => {
@ -86,8 +78,8 @@ class TopicDetail extends Component {
memo: Object.assign({}, { memo: Object.assign({}, {
...response.data.data, ...response.data.data,
replies_count: response.data.data.total_replies_count replies_count: response.data.data.total_replies_count
}, {...this.state.memo}), }, { ...this.state.memo }),
author:response.data.data.author author: response.data.data.author
}, () => { }, () => {
}) })
@ -126,8 +118,8 @@ class TopicDetail extends Component {
$('body>#root').on('onMemoDelete', (event) => { $('body>#root').on('onMemoDelete', (event) => {
// const val = $('body>#root').data('onMemoDelete') // const val = $('body>#root').data('onMemoDelete')
const val = window.onMemoDelete ; const val = window.onMemoDelete;
this.onMemoDelete( JSON.parse(decodeURIComponent(val)) ) this.onMemoDelete(JSON.parse(decodeURIComponent(val)))
}) })
@ -145,7 +137,8 @@ class TopicDetail extends Component {
onMemoDelete(memo) { onMemoDelete(memo) {
const deleteUrl = `/commons/delete.json`; const deleteUrl = `/commons/delete.json`;
// 获取memo list // 获取memo list
axios.delete(deleteUrl, { data: { axios.delete(deleteUrl, {
data: {
object_id: memo.id, object_id: memo.id,
object_type: 'message' object_type: 'message'
} }
@ -156,7 +149,7 @@ class TopicDetail extends Component {
this.props.showNotification('删除成功'); this.props.showNotification('删除成功');
const props = Object.assign({}, this.props, {}) 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) { } else if (status === -1) {
this.props.showNotification('帖子已被删除'); 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) { if (this.state.memo && this.state.memo.content && prevState.memoLoading === true && this.state.memoLoading === false) {
// md渲染content等xhr执行完即memoLoading变化memo.content更新后初始化md // md渲染content等xhr执行完即memoLoading变化memo.content更新后初始化md
setTimeout(()=>{ setTimeout(() => {
// var shixunDescr = window.editormd.markdownToHTML("memo_content_editorMd", { // var shixunDescr = window.editormd.markdownToHTML("memo_content_editorMd", {
// htmlDecode: "style,script,iframe", // you can filter tags decode // htmlDecode: "style,script,iframe", // you can filter tags decode
// taskList: true, // taskList: true,
@ -186,7 +179,7 @@ class TopicDetail extends Component {
} }
clickPraise(){ clickPraise() {
const { memo } = this.state; const { memo } = this.state;
// const url = `/api/v1/discusses/${memo.id}/plus`; // const url = `/api/v1/discusses/${memo.id}/plus`;
const url = memo.user_praise ? '/praise_tread/unlike.json' : `/praise_tread/like.json`; 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.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.total_praises_count = newMemo.user_praise ? newMemo.total_praises_count - 1 : newMemo.total_praises_count + 1
newMemo.user_praise = !newMemo.user_praise newMemo.user_praise = !newMemo.user_praise
this.setState({memo : newMemo }) this.setState({ memo: newMemo })
}).catch((error) => { }).catch((error) => {
console.log(error) console.log(error)
}) })
@ -245,7 +238,7 @@ class TopicDetail extends Component {
</a> </a>
{/* {fileName && <ConditionToolTip title={fileName} condition={fileName.length > 30 }> </ConditionToolTip>} */} {/* {fileName && <ConditionToolTip title={fileName} condition={fileName.length > 30 }> </ConditionToolTip>} */}
<a href={item.url} title={fileName.length > 30 ? fileName : ''} <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} {fileName}
</a> </a>
@ -285,7 +278,7 @@ class TopicDetail extends Component {
fetchReplies = () => { fetchReplies = () => {
const topicId = this.props.match.params.topicId const topicId = this.props.match.params.topicId
const url = `/messages/${topicId}/reply_list.json?page=${this.state.pageCount}&page_size=${REPLY_PAGE_COUNT}` const url = `/messages/${topicId}/reply_list.json?page=${this.state.pageCount}&page_size=${REPLY_PAGE_COUNT}`
axios.get(url,{ axios.get(url, {
}) })
.then((response) => { .then((response) => {
const { replies, liked, total_replies_count, total_count } = response.data.data const { replies, liked, total_replies_count, total_count } = response.data.data
@ -317,7 +310,7 @@ class TopicDetail extends Component {
// return; // return;
// } // }
if (this.state.memo.id === id ) { // 回复帖子 if (this.state.memo.id === id) { // 回复帖子
this.createNewComment(commentContent, id, editor); this.createNewComment(commentContent, id, editor);
return; return;
} }
@ -350,7 +343,7 @@ class TopicDetail extends Component {
this.setState({ this.setState({
// runTesting: false, // runTesting: false,
comments: addSecondLevelComment(comments, parentComment, commentIndex, newId, commentContent, user, editor) comments: addSecondLevelComment(comments, parentComment, commentIndex, newId, commentContent, user, editor)
}, ()=>{ }, () => {
// keditor代码美化 // keditor代码美化
editor.html && window.prettyPrint() editor.html && window.prettyPrint()
}) })
@ -440,7 +433,7 @@ class TopicDetail extends Component {
*/ */
loadMoreChildComments = (parent) => { loadMoreChildComments = (parent) => {
const url = `/messages/${parent.id}/reply_list.json?page=1&page_size=500` const url = `/messages/${parent.id}/reply_list.json?page=1&page_size=500`
axios.get(url,{ axios.get(url, {
}) })
.then((response) => { .then((response) => {
const { replies, liked, total_replies_count } = response.data.data const { replies, liked, total_replies_count } = response.data.data
@ -477,7 +470,7 @@ class TopicDetail extends Component {
.then((response) => { .then((response) => {
const status = response.data.status const status = response.data.status
if (status === 0) { if (status === 0) {
this.props.showNotification( memo.sticky ? '取消置顶成功' : '置顶成功'); this.props.showNotification(memo.sticky ? '取消置顶成功' : '置顶成功');
memo.sticky = memo.sticky ? false : true memo.sticky = memo.sticky ? false : true
this.setState({ this.setState({
memo: Object.assign({}, memo) memo: Object.assign({}, memo)
@ -515,8 +508,8 @@ class TopicDetail extends Component {
render() { render() {
const { match, history } = this.props const { match, history } = this.props
const { recommend_shixun, current_user,author_info } = this.props; const { recommend_shixun, current_user, author_info } = this.props;
const { memo, comments, hasMoreComments, goldRewardDialogOpen, pageCount, total_count , author } = this.state; const { memo, comments, hasMoreComments, goldRewardDialogOpen, pageCount, total_count, author } = this.state;
const messageId = match.params.topicId const messageId = match.params.topicId
if (this.state.memoLoading || !current_user) { if (this.state.memoLoading || !current_user) {
return <div className="edu-back-white" id="forum_index_list"></div> 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 isCurrentUserTheAuthor = current_user.login == memo.author.login
const isAdmin = this.props.isAdmin() const isAdmin = this.props.isAdmin()
// TODO 图片上传地址 // TODO 图片上传地址
const courseId=this.props.match.params.coursesId; const courseId = this.props.match.params.coursesId;
const boardId = this.props.match.params.boardId; const boardId = this.props.match.params.boardId;
const isCourseEnd = this.props.isCourseEnd(); const isCourseEnd = this.props.isCourseEnd();
document.title=this.props.coursedata&&this.props.coursedata.name; document.title = this.props.coursedata && this.props.coursedata.name;
return ( return (
<div className="edu-back-white edu-class-container edu-position course-message topicDetail" id="yslforum_index_list"> {/* fl with100 */} <div className="edu-back-white edu-class-container edu-position course-message topicDetail" id="yslforum_index_list"> {/* fl with100 */}
<style>{` <style>{`
@ -551,9 +544,9 @@ class TopicDetail extends Component {
} }
`}</style> `}</style>
<CBreadcrumb className={'independent'} items={[ <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 }, { to: `/courses/${courseId}/boards/${boardId}`, name: memo.board_name },
{ name: '帖子详情'} { name: '帖子详情' }
]}></CBreadcrumb> ]}></CBreadcrumb>
<SendToCourseModal <SendToCourseModal
@ -564,37 +557,37 @@ class TopicDetail extends Component {
></SendToCourseModal> ></SendToCourseModal>
<div className="clearfix"> <div className="clearfix">
<div id="forum_list" className="forum_table mh650"> <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"> <div className="font-16 cdefault clearfix pr pr35">
<span className="noteDetailTitle">{memo.subject}</span> <span className="noteDetailTitle">{memo.subject}</span>
{ !!memo.sticky && <span className="btn-cir btn-cir-red ml10" {!!memo.sticky && <span className="btn-cir btn-cir-red ml10"
style={{position: 'relative', bottom: '4px'}}>置顶</span>} style={{ position: 'relative', bottom: '4px' }}>置顶</span>}
{ !!memo.reward && <span className="color-orange font-14 ml15" {!!memo.reward && <span className="color-orange font-14 ml15"
data-tip-down={`获得平台奖励金币:${memo.reward}`} > data-tip-down={`获得平台奖励金币:${memo.reward}`} >
<i className="iconfont icon-gift mr5"></i>{memo.reward} <i className="iconfont icon-gift mr5"></i>{memo.reward}
</span> } </span>}
{/* || current_user.user_id === author_info.user_id */} {/* || current_user.user_id === author_info.user_id */}
{ current_user && (isAdmin || isCurrentUserTheAuthor) && {current_user && (isAdmin || isCurrentUserTheAuthor) &&
<div className="edu-position-hidebox" style={{position: 'absolute', right: '2px',top:'4px'}}> <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> <a href="javascript:void(0);"><i className="fa fa-bars font-16"></i></a>
<ul className="edu-position-hide undis"> <ul className="edu-position-hide undis">
{ ( isCurrentUserTheAuthor || isAdmin ) && {(isCurrentUserTheAuthor || isAdmin) &&
<li><a <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>} >&nbsp;&nbsp;</a></li>}
{ isAdmin && {isAdmin &&
( memo.sticky == true ? (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)}>取消置顶</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> <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={() => <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> &nbsp;&nbsp;</a>
</li> </li>
@ -605,31 +598,31 @@ class TopicDetail extends Component {
</div> </div>
<div className="df mt20"> <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="flex1">
<div className="color-grey-9 lineh-20"> <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> <span className="fl">{moment(memo.created_on).fromNow()} 发布</span>
</div> </div>
<div className="color-grey-9 clearfix"> <div className="color-grey-9 clearfix">
<span className="fl" style={{marginTop: '4px'}}> <span className="fl" style={{ marginTop: '4px' }}>
{/* { current_user.admin && <Tooltip title={ "" }> {/* { current_user.admin && <Tooltip title={ "" }>
<span className="noteDetailNum rightline cdefault" style={{padding: '0 4px', cursor: 'pointer'}}> <span className="noteDetailNum rightline cdefault" style={{padding: '0 4px', cursor: 'pointer'}}>
<i className="iconfont icon-jiangli mr5" onClick={this.showRewardDialog}></i> <i className="iconfont icon-jiangli mr5" onClick={this.showRewardDialog}></i>
</span> </span>
</Tooltip> } */} </Tooltip> } */}
<Tooltip title={"浏览数"}> <Tooltip title={"浏览数"}>
<span className={`noteDetailNum `} style={{paddingLeft: '0px'}}> <span className={`noteDetailNum `} style={{ paddingLeft: '0px' }}>
<i className="iconfont icon-liulanyan mr5"></i> <i className="iconfont icon-liulanyan mr5"></i>
<span style={{ top: "1px", position: "relative" }}>{memo.visits || '1'}</span> <span style={{ top: "1px", position: "relative" }}>{memo.visits || '1'}</span>
</span> </span>
</Tooltip> </Tooltip>
{ !!memo.total_replies_count && {!!memo.total_replies_count &&
<Tooltip title={"回复数"}> <Tooltip title={"回复数"}>
<a href="javascript:void(0)" className="noteDetailNum"> <a href="javascript:void(0)" className="noteDetailNum">
<i className="iconfont icon-huifu1 mr5" onClick={this.showCommentInput}></i> <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> </a>
</Tooltip> </Tooltip>
} }
@ -637,15 +630,15 @@ class TopicDetail extends Component {
<Tooltip title={"点赞数"}> <Tooltip title={"点赞数"}>
<span className={`noteDetailNum `} style={{}}> <span className={`noteDetailNum `} style={{}}>
<i className="iconfont icon-dianzan-xian mr5"></i> <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> </span>
</Tooltip> </Tooltip>
} }
</span> </span>
<div className="fr"> <div className="fr">
{/* || current_user.user_id === author_info.user_id */} {/* || current_user.user_id === author_info.user_id */}
<a className={`task-hide fr return_btn color-grey-6 ${ current_user && (isAdmin <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})) } > ) ? '' : 'no_mr'} `} onClick={() => this.props.toListPage(Object.assign({}, this.props.match.params, { 'coursesId': this.state.memo.course_id }))} >
返回 返回
</a> </a>
</div> </div>
@ -655,7 +648,7 @@ class TopicDetail extends Component {
</div> </div>
<div className="padding30 memoContent new_li" style={{ paddingBottom: '10px'}}> <div className="padding30 memoContent new_li" style={{ paddingBottom: '10px' }}>
{/* <MarkdownToHtml content={memo.content}></MarkdownToHtml> */} {/* <MarkdownToHtml content={memo.content}></MarkdownToHtml> */}
{memo.is_md == true ? {memo.is_md == true ?
<MarkdownToHtml content={memo.content}></MarkdownToHtml> <MarkdownToHtml content={memo.content}></MarkdownToHtml>
@ -663,18 +656,18 @@ class TopicDetail extends Component {
<div dangerouslySetInnerHTML={{ __html: memo.content }}></div> <div dangerouslySetInnerHTML={{ __html: memo.content }}></div>
} }
</div> </div>
<div className="padding30 bor-bottom-greyE" style={{paddingTop: '2px'}}> <div className="padding30 bor-bottom-greyE" style={{ paddingTop: '2px' }}>
<div className="mt10 mb20"> <div className="mt10 mb20">
{/* ${memo.user_praise ? '' : ''} */} {/* ${memo.user_praise ? '' : ''} */}
<Tooltip title={`${memo.liked ? '取消点赞' : '点赞'}`}> <Tooltip title={`${memo.liked ? '取消点赞' : '点赞'}`}>
<p className={`noteDetailPoint ${memo.user_praise ? 'Pointed' : ''}`} onClick={()=>{this.clickPraise()}} > <p className={`noteDetailPoint ${memo.user_praise ? 'Pointed' : ''}`} onClick={() => { this.clickPraise() }} >
<i className="iconfont icon-dianzan"></i><br/> <i className="iconfont icon-dianzan"></i><br />
<span>{memo.praises_count}</span> <span>{memo.praises_count}</span>
</p> </p>
</Tooltip> </Tooltip>
</div> </div>
{ memo.attachments && !!memo.attachments.length && {memo.attachments && !!memo.attachments.length &&
<div> <div>
{this.renderAttachment()} {this.renderAttachment()}
</div> </div>
@ -721,9 +714,9 @@ class TopicDetail extends Component {
</div> </div>
<div className="memoMore" style={{'margin-top': '20px'}}> <div className="memoMore" style={{ 'margin-top': '20px' }}>
{ total_count > REPLY_PAGE_COUNT && {total_count > REPLY_PAGE_COUNT &&
<Pagination showQuickJumper onChange={this.onPaginationChange} current={pageCount} total={total_count} pageSize={10}/> <Pagination showQuickJumper onChange={this.onPaginationChange} current={pageCount} total={total_count} pageSize={10} />
} }
{!isCourseEnd && <div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>} {!isCourseEnd && <div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>}
</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 React, { Component } from "react";
import { Input, InputNumber, Form, Button, Checkbox, Upload, Icon, message, Modal } from "antd"; import { Modal } from "antd";
import axios from 'axios' import axios from 'axios'
import '../css/busyWork.css' import '../css/busyWork.css'
import '../css/Courses.css' import '../css/Courses.css'
import { WordsBtn, getUrl, ConditionToolTip, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll import { appendFileSizeToUploadFileAll } from 'educoder'
, getUploadActionUrl } from 'educoder'
import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
import CBreadcrumb from '../common/CBreadcrumb' import CBreadcrumb from '../common/CBreadcrumb'
import NewWorkForm from './NewWorkForm' import NewWorkForm from './NewWorkForm'
const confirm = Modal.confirm; class NewWork extends Component {
const $ = window.$ constructor(props) {
const MAX_TITLE_LENGTH = 60;
class NewWork extends Component{
constructor(props){
super(props); super(props);
this.contentMdRef = React.createRef(); this.contentMdRef = React.createRef();
this.answerMdRef = React.createRef(); this.answerMdRef = React.createRef();
this.state={ this.state = {
category: {}, category: {},
course_name: '' course_name: ''
} }
} }
componentDidMount () { componentDidMount() {
let {typeId, coursesId, pageType, workId}=this.props.match.params; let { typeId, coursesId, pageType, workId } = this.props.match.params;
const isEdit = pageType === "edit" const isEdit = pageType === "edit"
this.isEdit = isEdit; this.isEdit = isEdit;
if (isEdit) { if (isEdit) {
@ -123,7 +118,7 @@ class NewWork extends Component{
} }
onAttachmentRemove = (file, stateName) => { onAttachmentRemove = (file, stateName) => {
if(!file.percent || file.percent == 100){ if (!file.percent || file.percent == 100) {
this.props.confirm({ this.props.confirm({
content: '是否确认删除?', content: '是否确认删除?',
@ -141,39 +136,41 @@ class NewWork extends Component{
} }
render(){ render() {
let {typeId,coursesId,pageType}=this.props.match.params; let { typeId, coursesId, pageType } = this.props.match.params;
const isGroup = this.props.isGroup() const isGroup = this.props.isGroup()
const moduleName = !isGroup? "普通作业":"分组作业"; const moduleName = !isGroup ? "普通作业" : "分组作业";
const moduleEngName = this.props.getModuleName() const moduleEngName = this.props.getModuleName()
let{ let {
course_name, category course_name, category
}=this.state } = this.state
const { current_user } = this.props const { current_user } = this.props
const courseId = this.state.course_id || coursesId ; const courseId = this.state.course_id || coursesId;
const isEdit = this.isEdit; const isEdit = this.isEdit;
const common = { const common = {
onCancel:this.onCancel, onCancel: this.onCancel,
isGroup: this.props.isGroup, isGroup: this.props.isGroup,
doNew: this.doNew, doNew: this.doNew,
doEdit: this.doEdit, doEdit: this.doEdit,
} }
document.title=this.state.course_name && this.state.course_name document.title = this.state.course_name && this.state.course_name
return( return (
<div className="newMain"> <div className="newMain">
<div className="educontent mt20 mb50"> <div className="educontent mt20 mb50">
<CBreadcrumb items={[ <CBreadcrumb items={[
{ to: current_user && current_user.first_category_url, name: this.state.course_name}, { 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 }, to: `/courses/${courseId}/${moduleEngName}/${category && category.category_id ? category.category_id : ''}`
{ name: `${ this.isEdit ? '编辑' : '新建'}` } , name: category && category.category_name
},
{ name: `${this.isEdit ? '编辑' : '新建'}` }
]}></CBreadcrumb> ]}></CBreadcrumb>
<p className="clearfix mt20 mb20"> <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" <a href="javascript:void(0)" className="color-grey-6 fr font-16 mr2"
onClick={() => this.props.history.goBack()}> onClick={() => this.props.history.goBack()}>
返回 返回
@ -195,7 +192,7 @@ class NewWork extends Component{
{...this.props} {...this.props}
{...this.state} {...this.state}
{...common} {...common}
wrappedComponentRef={(ref) => {this.newWorkFormRef = ref}} wrappedComponentRef={(ref) => { this.newWorkFormRef = ref }}
></NewWorkForm> ></NewWorkForm>
</div> </div>
</div> </div>

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

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

@ -1,67 +1,64 @@
import React,{ Component } from "react"; import React, { Component } from "react";
import { Modal,Checkbox,Select,Input,Tooltip,Spin,Icon} from "antd"; import { Modal, Checkbox, Select, Input, Tooltip, Spin, Icon } from "antd";
import axios from'axios'; import axios from 'axios';
// import Loading from '@icedesign/base/lib/loading';
// import '@icedesign/base/lib/loading/style.js';
const Option = Select.Option;
const Search = Input.Search; const Search = Input.Search;
class ShixunModal extends Component{ class ShixunModal extends Component {
constructor(props){ constructor(props) {
super(props); super(props);
this.state={ this.state = {
Searchvalue:undefined, Searchvalue: undefined,
type:'all', type: 'all',
category_id:0, category_id: 0,
page:1, page: 1,
shixunmodallist:undefined, shixunmodallist: undefined,
hometypepvisible:false, hometypepvisible: false,
newshixunmodallist:undefined, newshixunmodallist: undefined,
} }
} }
componentDidMount() { componentDidMount() {
this.setState({ this.setState({
hometypepvisible:true, hometypepvisible: true,
}) })
let coursesId=this.props.match.params.coursesId; let coursesId = this.props.match.params.coursesId;
let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json"; let url = this.props.shixunsUrl || "/courses/" + coursesId + "/homework_commons/shixuns.json";
axios.get(url).then((result)=>{ axios.get(url).then((result) => {
if(result.status===200){ if (result.status === 200) {
if(result.data.message===undefined){ if (result.data.message === undefined) {
this.setState({ this.setState({
shixunmodallist:result.data, shixunmodallist: result.data,
hometypepvisible:false, hometypepvisible: false,
newshixunmodallist:result.data.shixun_list, newshixunmodallist: result.data.shixun_list,
}) })
} }
} }
}).catch((error)=>{ }).catch((error) => {
console.log(error); console.log(error);
}) })
} }
setupdatalist=(search,type,loading,page)=>{ setupdatalist = (search, type, loading, page) => {
let{newshixunmodallist}=this.state; let { newshixunmodallist } = this.state;
let newshixunmodallists=[] let newshixunmodallists = []
if(page>1){ if (page > 1) {
newshixunmodallists=newshixunmodallist; newshixunmodallists = newshixunmodallist;
} }
this.setState({ this.setState({
hometypepvisible:loading hometypepvisible: loading
}) })
let coursesId=this.props.match.params.coursesId; let coursesId = this.props.match.params.coursesId;
let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json"; let url = this.props.shixunsUrl || "/courses/" + coursesId + "/homework_commons/shixuns.json";
axios.get(url, { axios.get(url, {
params: { params: {
search: search, search: search,
type:type, type: type,
page:page page: page
} }
}).then((result)=>{ }).then((result) => {
if(result.status===200){ if (result.status === 200) {
if(result.data.message===undefined){ if (result.data.message === undefined) {
let shixun_list = result.data.shixun_list; let shixun_list = result.data.shixun_list;
for (var i = 0; i < shixun_list.length; i++) { for (var i = 0; i < shixun_list.length; i++) {
newshixunmodallists.push(shixun_list[i]) newshixunmodallists.push(shixun_list[i])
@ -76,20 +73,20 @@ class ShixunModal extends Component{
} }
} }
}).catch((error)=>{ }).catch((error) => {
console.log(error); console.log(error);
}) })
} }
//勾选实训 //勾选实训
shixunhomeworkedit=(list)=>{ shixunhomeworkedit = (list) => {
let newpatheditarry=[]; let newpatheditarry = [];
if (this.props.singleChoose == true) { if (this.props.singleChoose == true) {
if (list.length > 0) { if (list.length > 0) {
newpatheditarry.push(list[list.length - 1]) newpatheditarry.push(list[list.length - 1])
} }
} else { } else {
for(var i=0; i<list.length;i++){ for (var i = 0; i < list.length; i++) {
newpatheditarry.push(list[i]) newpatheditarry.push(list[i])
} }
} }
@ -100,18 +97,18 @@ class ShixunModal extends Component{
this.props.funpatheditarry(newpatheditarry) this.props.funpatheditarry(newpatheditarry)
} }
contentViewScrolledit=(e)=>{ contentViewScrolledit = (e) => {
const {shixunmodallist}=this.state; const { shixunmodallist } = this.state;
//滑动到底判断 //滑动到底判断
let newscrollTop=parseInt(e.currentTarget.scrollTop); let newscrollTop = parseInt(e.currentTarget.scrollTop);
let allclientHeight=e.currentTarget.clientHeight+newscrollTop; 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) { if (shixunmodallist.shixun_list.length === 0) {
return; return;
} else { } else {
let {Searchvalue, type, page} = this.state; let { Searchvalue, type, page } = this.state;
let newpage = page + 1 let newpage = page + 1
this.setupdatalist(Searchvalue, type, true, newpage) this.setupdatalist(Searchvalue, type, true, newpage)
} }
@ -119,51 +116,51 @@ class ShixunModal extends Component{
} }
//搜索 //搜索
SenttotheValue=(e)=>{ SenttotheValue = (e) => {
this.setState({ this.setState({
Searchvalue:e.target.value Searchvalue: e.target.value
}) })
} }
SenttotheSearch=(value)=>{ SenttotheSearch = (value) => {
let{type}=this.state; let { type } = this.state;
this.setState({ this.setState({
page:1, page: 1,
}) })
this.props.funpatheditarry([]) this.props.funpatheditarry([])
this.setupdatalist(value,type,true,1) this.setupdatalist(value, type, true, 1)
} }
//tag //tag
changeTag=(types)=>{ changeTag = (types) => {
let {Searchvalue}=this.state; let { Searchvalue } = this.state;
this.setState({ this.setState({
type:types, type: types,
page:1, page: 1,
newshixunmodallist:undefined newshixunmodallist: undefined
}) })
this.props.funpatheditarry([]) this.props.funpatheditarry([])
this.setupdatalist(Searchvalue,types,true,1) this.setupdatalist(Searchvalue, types, true, 1)
} }
hidecouseShixunModal=()=>{ hidecouseShixunModal = () => {
this.props.hidecouseShixunModal() this.props.hidecouseShixunModal()
} }
savecouseShixunModal=()=>{ savecouseShixunModal = () => {
this.setState({ 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({ this.setState({
shixunmodelchke:true, shixunmodelchke: true,
chekicmessage:"请先选择实训", chekicmessage: "请先选择实训",
hometypepvisible:false hometypepvisible: false
}) })
return return
@ -172,27 +169,27 @@ class ShixunModal extends Component{
if (this.props.chooseShixun) { if (this.props.chooseShixun) {
this.props.chooseShixun(patheditarry) this.props.chooseShixun(patheditarry)
this.setState({ this.setState({
hometypepvisible:false hometypepvisible: false
}) })
return; return;
} }
let url="/courses/"+coursesId+"/homework_commons/create_shixun_homework.json"; let url = "/courses/" + coursesId + "/homework_commons/create_shixun_homework.json";
axios.post(url, { axios.post(url, {
category_id:this.props.category_id===null||this.props.category_id===undefined?undefined:parseInt(this.props.category_id), category_id: this.props.category_id === null || this.props.category_id === undefined ? undefined : parseInt(this.props.category_id),
shixun_ids:patheditarry, shixun_ids: patheditarry,
} }
).then((response) => { ).then((response) => {
if(response.data.status===-1){ if (response.data.status === -1) {
// this.props.showNotification(response.data.message) // this.props.showNotification(response.data.message)
}else{ } else {
// this.props.courseshomeworkstart(response.data.category_id,response.data.homework_ids) // 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.props.hidecouseShixunModal()
} }
this.setState({ this.setState({
hometypepvisible:false hometypepvisible: false
}) })
// category_id: 3 // category_id: 3
// homework_ids: (5) [9171, 9172, 9173, 9174, 9175] // homework_ids: (5) [9171, 9172, 9173, 9174, 9175]
@ -201,17 +198,17 @@ class ShixunModal extends Component{
}) })
} }
selectCloseList=(value)=>{ selectCloseList = (value) => {
this.setState({ this.setState({
category_id:value category_id: value
}) })
} }
render(){ render() {
let {Searchvalue,type,hometypepvisible,shixunmodallist,newshixunmodallist,}=this.state; let { Searchvalue, type, hometypepvisible, shixunmodallist, newshixunmodallist, } = this.state;
let {visible,patheditarry}=this.props; let { visible, patheditarry } = this.props;
const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />; const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />;
// console.log(patheditarry) // console.log(patheditarry)
return( return (
<div> <div>
<Modal <Modal
@ -282,24 +279,24 @@ class ShixunModal extends Component{
<div className="clearfix mb10 shixun_work_div newshixun_tab_div cdefault" id="shixun_tab_div"> <div className="clearfix mb10 shixun_work_div newshixun_tab_div cdefault" id="shixun_tab_div">
<li className="fl mr5 mt5"> <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> </li>
{ {
shixunmodallist && shixunmodallist.tags.map((item,key)=>{ shixunmodallist && shixunmodallist.tags.map((item, key) => {
return( return (
<li className="fl mr5 mt5" key={key}> <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> </li>
) )
}) })
} }
</div> </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 className="fl color-grey-9 font-16 mt3">
<span></span> <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>个实训</span>
</span> </span>
<div className="fr search-new"> <div className="fr search-new">
@ -308,7 +305,7 @@ class ShixunModal extends Component{
value={Searchvalue} value={Searchvalue}
onInput={this.SenttotheValue} onInput={this.SenttotheValue}
onSearch={(value) => this.SenttotheSearch(value)} onSearch={(value) => this.SenttotheSearch(value)}
style={{width: '115%'}} style={{ width: '115%' }}
/> />
</div> </div>
</div> </div>
@ -360,31 +357,31 @@ class ShixunModal extends Component{
{/*<Loading visible={hometypepvisible} shape="dot-circle" className="newnext-loading" color='#4AC7FF'>*/} {/*<Loading visible={hometypepvisible} shape="dot-circle" className="newnext-loading" color='#4AC7FF'>*/}
<Checkbox.Group style={{ width: '100%' }} value={patheditarry} onChange={this.shixunhomeworkedit}> <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="alltask edu-back-white">
<div className="edu-tab-con-box clearfix edu-txt-center"> <div className="edu-tab-con-box clearfix edu-txt-center">
<img className="edu-nodata-img mb20" src="/images/educoder/nodata.png" /> <img className="edu-nodata-img mb20" src="/images/educoder/nodata.png" />
<p className="edu-nodata-p mb20">暂时还没有相关数据哦</p></div> <p className="edu-nodata-p mb20">暂时还没有相关数据哦</p></div>
</div>:newshixunmodallist.map((item,key)=>{ </div> : newshixunmodallist.map((item, key) => {
return( return (
<div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE" key={key}> <div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE" key={key}>
<li className="fl with40 edu-txt-left task-hide paddingl5 newtaskhide"> <li className="fl with40 edu-txt-left task-hide paddingl5 newtaskhide">
<Checkbox <Checkbox
id={"shixun_input_"+item.shixun_id} id={"shixun_input_" + item.shixun_id}
value={item.shixun_id} value={item.shixun_id}
key={item.shixun_id} key={item.shixun_id}
className=" task-hide edu-txt-left newtaskhide" className=" task-hide edu-txt-left newtaskhide"
style={{"width":"280px"}} style={{ "width": "280px" }}
name="shixun_homework[]" 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> </Checkbox>
</li> </li>
<li className="fl with25 edu-txt-left task-hide paddingl5">{item.school}</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 paddingl10">{item.myshixuns_count}</li>
<li className="fl with11 color-orange-tip paddingl10 pl12">{item.level}</li> <li className="fl with11 color-orange-tip paddingl10 pl12">{item.level}</li>
<Tooltip title="新窗口查看详情"> <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> </Tooltip>
</div> </div>
) )
@ -395,7 +392,7 @@ class ShixunModal extends Component{
</div> </div>
</div> </div>
</Spin> </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"> <div className="mt20 marginauto clearfix edu-txt-center">
<a className="pop_close task-btn mr30 margin-tp26" onClick={this.hidecouseShixunModal}>取消</a> <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> <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 React, { Component } from "react";
import {InputNumber,Table} from "antd"; import { InputNumber, Table } from "antd";
import TPMMDEditor from '../../../../modules/tpm/challengesnew/TPMMDEditor' import { Link } from 'react-router-dom';
import {Link} from 'react-router-dom'; import { UnControlled as CodeMirror } from 'react-codemirror2';
import {UnControlled as CodeMirror} from 'react-codemirror2';
import axios from 'axios' import axios from 'axios'
import update from 'immutability-helper' import update from 'immutability-helper'
import {markdownToHTML} from 'educoder' import { markdownToHTML } from 'educoder'
import ShixunAnswerDetail from './shixunAnswerDetail' import ShixunAnswerDetail from './shixunAnswerDetail'
const $ = window.$; const $ = window.$;
class shixunAnswer extends Component{ class shixunAnswer extends Component {
constructor(props){ constructor(props) {
super(props); super(props);
this.state={ this.state = {
scoreList:[], scoreList: [],
data:[], data: [],
challenge:[], challenge: [],
dataCopy:[] dataCopy: []
} }
} }
componentDidUpdate =(prevState)=>{ componentDidUpdate = (prevState) => {
if(this.props.questionType && !prevState.questionType && prevState.questionType !=this.props.questionType ){ if (this.props.questionType && !prevState.questionType && prevState.questionType != this.props.questionType) {
this.showInfo(); this.showInfo();
} }
} }
componentDidMount =()=>{ componentDidMount = () => {
this.showInfo(); this.showInfo();
} }
showInfo=()=>{ showInfo = () => {
let data =[]; let data = [];
// let details=[{ let challenge = [];
// "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=[];
let details = this.props.questionType.shixun_details; let details = this.props.questionType.shixun_details;
if(details){ if (details) {
for(var i=0;i<details.length;i++){ for (var i = 0; i < details.length; i++) {
for(var j=0;j<details[i].stage_list.length;j++){ for (var j = 0; j < details[i].stage_list.length; j++) {
data.push({ data.push({
part:details[i].stage_list[j].position, part: details[i].stage_list[j].position,
shixunName:details[i].stage_list[j].name, shixunName: details[i].stage_list[j].name,
testCount:details[i].stage_list[j].evaluate_count, testCount: details[i].stage_list[j].evaluate_count,
endTime:details[i].stage_list[j].finished_time, endTime: details[i].stage_list[j].finished_time,
needTime:details[i].stage_list[j].time_consuming, needTime: details[i].stage_list[j].time_consuming,
my_exp:details[i].stage_list[j].myself_experience, my_exp: details[i].stage_list[j].myself_experience,
total_exp:details[i].stage_list[j].experience, total_exp: details[i].stage_list[j].experience,
my_score:details[i].stage_list[j].user_score, my_score: details[i].stage_list[j].user_score,
total_score:details[i].stage_list[j].game_score, total_score: details[i].stage_list[j].game_score,
input_score:details[i].stage_list[j].user_score, input_score: details[i].stage_list[j].user_score,
operation:details[i].shixun_detail && details[i].shixun_detail[0].game_identifier, operation: details[i].shixun_detail && details[i].shixun_detail[0].game_identifier,
id:details[i].shixun_challenge_id id: details[i].shixun_challenge_id
}) })
} }
if(details[i].shixun_detail){ if (details[i].shixun_detail) {
challenge.push(details[i].shixun_detail); challenge.push(details[i].shixun_detail);
} }
} }
} }
this.setState({ this.setState({
data:data, data: data,
dataCopy:data, dataCopy: data,
challenge:challenge challenge: challenge
}) })
// console.log(challenge); // console.log(challenge);
} }
changeThis=(value,index)=>{ changeThis = (value, index) => {
this.setState( this.setState(
(prevState) => ({ (prevState) => ({
data : update(prevState.data, {[index]: { input_score: {$set: value} }}) data: update(prevState.data, { [index]: { input_score: { $set: value } } })
}) })
) )
} }
changeThisScore=(e,c_id,key)=>{ changeThisScore = (e, c_id, key) => {
let url=`/exercise_questions/${this.props.questionType.question_id}/adjust_score.json` let url = `/exercise_questions/${this.props.questionType.question_id}/adjust_score.json`
const list = Object.assign({}, this.state.dataCopy[key]) const list = Object.assign({}, this.state.dataCopy[key])
// console.log("111111111111111111111111"); // console.log("111111111111111111111111");
// console.log(this.props); // console.log(this.props);
// 调分值为0且和第一次的数据相同则不修改 // 调分值为0且和第一次的数据相同则不修改
if(parseInt(e.target.value)==parseInt(list.my_score)){ if (parseInt(e.target.value) == parseInt(list.my_score)) {
return; return;
} }
axios.post((url),{ axios.post((url), {
score:e.target.value, score: e.target.value,
user_id:this.props.id, user_id: this.props.id,
shixun_challenge_id:c_id shixun_challenge_id: c_id
}).then((result)=>{ }).then((result) => {
if(result){ if (result) {
this.props.showNotification('调分成功'); this.props.showNotification('调分成功');
this.setState( this.setState(
(prevState) => ({ (prevState) => ({
data : update(prevState.data, {[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} }}) dataCopy: update(prevState.dataCopy, { [key]: { my_score: { $set: e.target.value } } })
}) })
) )
console.log(this.state.dataCopy) console.log(this.state.dataCopy)
} }
}).catch((error)=>{ }).catch((error) => {
console.log(error); console.log(error);
}) })
} }
scrollToAnchor=(index)=>{ scrollToAnchor = (index) => {
let name="challenge_"+index; let name = "challenge_" + index;
if (index) { if (index) {
// let anchorElement = document.getElementById(name); // let anchorElement = document.getElementById(name);
// if(anchorElement) { anchorElement.scrollIntoView(); } // if(anchorElement) { anchorElement.scrollIntoView(); }
$("html").animate({ scrollTop: $("#challenge_"+index).offset().top - 150 }) $("html").animate({ scrollTop: $("#challenge_" + index).offset().top - 150 })
} }
} }
render(){ render() {
let { let {
questionType , questionType,
exercise, exercise,
user_exercise_status, user_exercise_status,
}=this.props } = this.props
let { let {
data, data,
challenge, challenge,
scoreList, scoreList,
}=this.state } = this.state
let isAdmin= this.props.isAdmin(); let isAdmin = this.props.isAdmin();
let isStudent = this.props.isStudent(); let isStudent = this.props.isStudent();
// 表格 // 表格
let columns = [{ let columns = [{
title: '关卡', title: '关卡',
dataIndex: 'part', dataIndex: 'part',
key: 'part', key: 'part',
className:"edu-txt-center" className: "edu-txt-center"
}, { }, {
title: '任务名称', title: '任务名称',
dataIndex: 'shixunName', dataIndex: 'shixunName',
key: 'shixunName', key: 'shixunName',
className:"edu-txt-left with22 ", className: "edu-txt-left with22 ",
render:(shixunName,item,index)=>{ render: (shixunName, item, index) => {
return( return (
<span className="overflowHidden1" style={{maxWidth: '400px'}} <span className="overflowHidden1" style={{ maxWidth: '400px' }}
title={shixunName && shixunName.length > 25 ? shixunName : ''} title={shixunName && shixunName.length > 25 ? shixunName : ''}
>{shixunName}</span> >{shixunName}</span>
) )
@ -204,59 +148,59 @@ class shixunAnswer extends Component{
title: '评测次数', title: '评测次数',
dataIndex: 'testCount', dataIndex: 'testCount',
key: 'testCount', key: 'testCount',
className:"edu-txt-center", className: "edu-txt-center",
render:(testCount,item,index)=>{ render: (testCount, item, index) => {
return( return (
<span>{ item.testCount ? item.testCount : <span className="color-grey-9">--</span> }</span> <span>{item.testCount ? item.testCount : <span className="color-grey-9">--</span>}</span>
) )
} }
}, { }, {
title: '完成时间', title: '完成时间',
key: 'endTime', key: 'endTime',
dataIndex: 'endTime', dataIndex: 'endTime',
className:"edu-txt-center", className: "edu-txt-center",
render:(endTime,item,index)=>{ render: (endTime, item, index) => {
return( return (
<span>{ item.endTime ? item.endTime : <span className="color-grey-9">--</span> }</span> <span>{item.endTime ? item.endTime : <span className="color-grey-9">--</span>}</span>
) )
} }
}, { }, {
title: '耗时', title: '耗时',
dataIndex: 'needTime', dataIndex: 'needTime',
key: 'needTime', key: 'needTime',
className:"edu-txt-center", className: "edu-txt-center",
render:(needTime,item,index)=>{ render: (needTime, item, index) => {
return( return (
<span>{ item.needTime ? item.needTime : <span className="color-grey-9">--</span> }</span> <span>{item.needTime ? item.needTime : <span className="color-grey-9">--</span>}</span>
) )
} }
}, { }, {
title: '经验值', title: '经验值',
dataIndex: 'exp', dataIndex: 'exp',
key: 'exp', key: 'exp',
className:"edu-txt-center", className: "edu-txt-center",
render:(exp,item,index)=>{ render: (exp, item, index) => {
return( return (
<span><span className="color-green">{item.my_exp}</span>/{item.total_exp}</span> <span><span className="color-green">{item.my_exp}</span>/{item.total_exp}</span>
) )
} }
},{ }, {
title: '得分/满分', title: '得分/满分',
dataIndex: 'score', dataIndex: 'score',
key: 'score', key: 'score',
className: (isAdmin || ( isStudent && exercise && exercise.exercise_status == 3 )) ? "edu-txt-center":"edu-txt-center none", className: (isAdmin || (isStudent && exercise && exercise.exercise_status == 3)) ? "edu-txt-center" : "edu-txt-center none",
render:(score,item,index)=>{ render: (score, item, index) => {
return( return (
<span><span className="color-orange-tip">{item.my_score}</span>/{item.total_score}</span> <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', dataIndex: 'operation',
key: 'operation', key: 'operation',
className: isAdmin ? "edu-txt-left" : "edu-txt-center", className: isAdmin ? "edu-txt-left" : "edu-txt-center",
render:(operation,item,index)=>{ render: (operation, item, index) => {
return( return (
<span> <span>
{ {
this.props.isAdmin() ? this.props.isAdmin() ?
@ -266,25 +210,25 @@ class shixunAnswer extends Component{
step={0.1} step={0.1}
precision={1} precision={1}
value={item.input_score} value={item.input_score}
style={{width:"60px",marginLeft:"5px"}} style={{ width: "60px", marginLeft: "5px" }}
placeholder="请输入分数" placeholder="请输入分数"
onChange={(value)=>{this.changeThis(value,index)}} onChange={(value) => { this.changeThis(value, index) }}
onBlur={(value)=>this.changeThisScore(value,item.id,index)} onBlur={(value) => this.changeThisScore(value, item.id, index)}
className="greyInput" className="greyInput"
></InputNumber> ></InputNumber>
:"" : ""
} }
{ {
item.operation ? 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> </span>
) )
} }
}]; }];
return( return (
<div> <div>
<style> <style>
{` {`
@ -296,27 +240,27 @@ class shixunAnswer extends Component{
} }
`} `}
</style> </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> <div>
<p className="padding20-30 font-16 color-grey-6 pl30">阶段成绩</p> <p className="padding20-30 font-16 color-grey-6 pl30">阶段成绩</p>
<div className={challenge && challenge.length > 0 ? "pl30 pr30 resetTableStyle":"pl30 pr30 resetTableStyle stageTable"}> <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> : "" } {data && data.length > 0 ? <Table columns={columns} dataSource={data} pagination={false}></Table> : ""}
</div> </div>
{ {
challenge && challenge.length > 0 && challenge && challenge.length > 0 &&
<div> <div>
<p className="mt20 pr30 font-16 color-grey-6 pl30">实训详情</p> <p className="mt20 pr30 font-16 color-grey-6 pl30">实训详情</p>
{ {
challenge.map((item,key)=>{ challenge.map((item, key) => {
return( return (
<div className="pl30 pr30 mt20" id={`challenge_${questionType.question_id}${key+1}`}> <div className="pl30 pr30 mt20" id={`challenge_${questionType.question_id}${key + 1}`}>
<p className="clearfix mb20"> <p className="clearfix mb20">
<span className="panel-inner-icon mr15 fl mt3 backgroud4CACFF"> <span className="panel-inner-icon mr15 fl mt3 backgroud4CACFF">
<i className="fa fa-code font-16 color_white"></i> <i className="fa fa-code font-16 color_white"></i>
</span> </span>
<span className="fl mt3 font-16"> <span className="fl mt3 font-16">
<span className="font-bd mr15">{item[0].position}</span> <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> <span className={"font-16"}>{item[0].name}</span>
</Link> </Link>
</span> </span>
@ -325,7 +269,7 @@ class shixunAnswer extends Component{
{...this.props} {...this.state} challenge={item[0].outputs} {...this.props} {...this.state} challenge={item[0].outputs}
></ShixunAnswerDetail> ></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"> <div className="bor-grey-e mt15">
<p className="clearfix pt5 pb5 pl15 pr15 back-f6-grey codebox"> <p className="clearfix pt5 pb5 pl15 pr15 back-f6-grey codebox">
<span className="fl">最近通过的代码</span> <span className="fl">最近通过的代码</span>
@ -353,7 +297,7 @@ class shixunAnswer extends Component{
</li> </li>
</div> </div>
</div> </div>
</div>:""} </div> : ""}
</div> </div>
) )
}) })
@ -364,12 +308,12 @@ class shixunAnswer extends Component{
: :
<div className="pl30 pr30"> <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)=>{ questionType && questionType.shixun && questionType.shixun.map((item, key) => {
return( return (
<p key={key} className="font-16 color-grey-6 mb5"> <p key={key} className="font-16 color-grey-6 mb5">
<span className="mr20">{item.challenge_position} {item.challenge_name}</span> <span className="mr20">{item.challenge_position} {item.challenge_name}</span>
<span>{item.challenge_score}</span> <span>{item.challenge_score}</span>

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

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

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

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

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

@ -6,11 +6,11 @@
* @LastEditors : tangjiang * @LastEditors : tangjiang
* @LastEditTime : 2019-12-27 22:35:14 * @LastEditTime : 2019-12-27 22:35:14
*/ */
import './index.scss'; import './index.less';
import React from 'react'; 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 { detail, language } = props;
const renderError = (detail = {}) => { const renderError = (detail = {}) => {

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

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

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

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

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

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

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

@ -6,15 +6,15 @@
* @LastEditors: tangjiang * @LastEditors: tangjiang
* @LastEditTime: 2019-12-09 17:36:55 * @LastEditTime: 2019-12-09 17:36:55
*/ */
import './index.scss'; import './index.less';
import React from 'react'; import React from 'react';
import { getImageUrl } from 'educoder' import { getImageUrl } from 'educoder'
function UserInfo (props) { function UserInfo(props) {
const {image_url, name} = props.userInfo; const { image_url, name } = props.userInfo;
return ( return (
<div className={'avator_nicker'}> <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'}> <span className={'student_nicker'}>
{name || ''} {name || ''}
</span> </span>

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save