Merge branch 'master' into develop

dev_forum
hjm 5 years ago
commit 1d7330a66f

3
.gitignore vendored

@ -61,5 +61,4 @@ vendor/bundle/
/public/images/avatars
/public/files
/workspace
/log
/log

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

File diff suppressed because it is too large Load Diff

@ -9,7 +9,7 @@ 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 MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const getClientEnvironment = require('./env');
const paths = require('./paths');
@ -28,8 +28,8 @@ const env = getClientEnvironment(publicUrl);
// 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.
devtool: 'cheap-module-source-map',
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.s
devtool: "eval", // 开启调试
// 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.
@ -113,7 +113,6 @@ module.exports = {
// First, run the linter.
// It's important to do this before Babel processes the JS.
// 上线然后要注释回来
// {
// test: /\.(js|jsx|mjs)$/,
// enforce: 'pre',
@ -250,7 +249,8 @@ module.exports = {
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
// You can remove this if you don't use Moment.js:
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
],
new MonacoWebpackPlugin(),
],
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
node: {

@ -1,349 +1,365 @@
'use strict';
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 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 = {
// 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: shouldUseSourceMap ? 'source-map' : 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`.
},
// "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,
}),
// 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$/),
],
// 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',
},
};
'use strict';
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 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 = {
// 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: shouldUseSourceMap ? 'source-map' : 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`.
},
// "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
},
warnings: false,
compress: {
drop_debugger: false,
drop_console: false
}
}
}),
// 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$/),
],
// 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 +1,95 @@
'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());
},
};
};
'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 it is too large Load Diff

@ -3,9 +3,9 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@flatten/array": "^1.1.7",
"@icedesign/base": "^0.2.5",
"antd": "^3.6.5",
"@novnc/novnc": "^1.1.0",
"antd": "^3.20.1",
"array-flatten": "^2.1.2",
"autoprefixer": "7.1.6",
"axios": "^0.18.0",
@ -39,14 +39,15 @@
"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-file-download": "^0.4.7",
"lodash": "^4.17.5",
"loglevel": "^1.6.1",
"material-ui": "^1.0.0-beta.40",
"moment": "^2.23.0",
"monaco-editor": "^0.15.6",
"monaco-editor-webpack-plugin": "^1.7.0",
"npm": "^6.10.1",
"object-assign": "4.1.1",
"postcss-flexbugs-fixes": "3.2.0",
"postcss-loader": "2.0.8",
@ -60,13 +61,13 @@
"rc-select": "^8.0.12",
"rc-tree": "^1.7.11",
"rc-upload": "^2.5.1",
"react": "^16.3.0",
"react": "^16.8.0",
"react-beautiful-dnd": "^10.0.4",
"react-codemirror": "^1.0.0",
"react-codemirror2": "^6.0.0",
"react-content-loader": "^3.1.1",
"react-dev-utils": "^5.0.0",
"react-dom": "^16.3.0-alpha.2",
"react-dom": "^16.8.0",
"react-hot-loader": "^4.0.0",
"react-infinite-scroller": "^1.2.4",
"react-loadable": "^5.3.1",
@ -86,11 +87,12 @@
"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",
"wrap-md-editor": "^0.2.20"
},
"scripts": {
"start": "node --max_old_space_size=8072 scripts/start.js",
"start": "node --max_old_space_size=15360 scripts/start.js",
"build": "node --max_old_space_size=15360 scripts/build.js",
"concat": "node scripts/concat.js",
"gen_stats": "NODE_ENV=production webpack --profile --config=./config/webpack.config.prod.js --json > stats.json",
@ -157,11 +159,10 @@
"port": "3007",
"devDependencies": {
"@babel/runtime": "7.0.0-beta.51",
"antd": "^3.6.5",
"babel-plugin-import": "^1.11.0",
"concat": "^1.0.3",
"happypack": "^5.0.1",
"videojs-for-react": "^0.0.3",
"webpack-bundle-analyzer": "^3.0.3"
"webpack-bundle-analyzer": "^3.0.3",
"webpack-parallel-uglify-plugin": "^1.1.0"
}
}

@ -1799,7 +1799,20 @@ ol.linenums{margin-top:0;margin-bottom:0}li.L1,li.L3,li.L5,li.L7,li.L9{backgroun
.page--body {
margin-top: 54px;
}
#myshixun_top {
display: flex;
height: 54px;
}
.yslflexhome {
display: flex;
flex-direction: row;
}
.yslflexhomes {
display: flex;
flex-direction: row;
}
#games_repository_contents,
.cm-s-railscasts .CodeMirror-gutters,
.split-panel--second {

@ -296,7 +296,7 @@ label.infolabel{display: block;float: left;width: 56px;text-align: right;margin-
.subshaicontent a{float: left;margin-right: 20px;color: #999;cursor: pointer}
.search-new{width: 248px;height:32px;position: relative}
.search-new{width: 248px;height:32px;position: relative;margin-right: 35px;}
.search-span{display: block;position: absolute;width: 100%;height: 100%;left:0px;top:0px;background-color: #F4F4F4;border: 1px solid #EAEAEA; border-radius: 4px;z-index: 1}
.search-new-input{height: 32px;padding-left: 5px;width: 225px;border: none;box-sizing: border-box;background: none;outline: none;position: absolute;left:0px;top:1px;z-index: 2}
.search-new img,.search-new a,.search-new .searchicon{cursor: pointer;position: absolute;right:2px;top:2px;z-index: 2}
@ -455,7 +455,7 @@ li.li-width7{width: 7%;text-align: left}
.top-black-trangle{display: block;border-width: 8px;position: absolute;top: -16px;right: 4px;border-style: dashed solid dashed dashed;border-color: transparent transparent rgba(5,16,26,0.6) transparent;font-size: 0;line-height: 0;}
.right-black-trangle{display: block;border-width: 8px;position: absolute;top: 10px;right: -16px;border-style: dashed solid dashed dashed;border-color: transparent transparent transparent rgba(5,16,26,0.6);font-size: 0;line-height: 0;}
.activity-nav.active{color: #4CACFF!important;}
.yslinvitetip{right: 140px;color: #fff; box-sizing: border-box;width: 170px;text-align: center;border-radius: 2px;background-color: rgba(5,16,26,0.6)}
.courseNewNum{display: block;background: #FF6800;border-radius:30px;padding:0px 2px;color: #fff!important;font-size: 11px;
height: 16px;line-height: 15px;min-width: 12px;text-align: center;margin-top: 17px;}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

@ -19,7 +19,7 @@
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>
<title>EduCoder</title>
<script type="text/javascript">
window.__isR = true;
@ -31,7 +31,7 @@
location.pathname.indexOf("/compatibility") == -1) {
// location.href = './compatibility'
location.href = './compatibility.html'
location.href = '/compatibility.html'
}
</script>
@ -55,7 +55,7 @@
<!-- <link href="/react/build/css/iconfont.css" rel="stylesheet" type="text/css"> -->
<link href="https://testeduplus2.educoder.net/stylesheets/educoder/edu-all.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">-->
@ -67,7 +67,9 @@
<!-- <link rel="stylesheet" type="text/css" href="https://www.educoder.net/stylesheets/css/font-awesome.css?1510652321"> -->
<link rel="stylesheet" type="text/css" href="/stylesheets/educoder/iconfont/iconfont.css">
<!--<link rel="stylesheet" type="text/css" href="http://47.96.87.25:48080/stylesheets/educoder/iconfont/iconfont.css">-->
<!--需要去build js配置-->
<link rel="stylesheet" type="text/css" href="/css/iconfont.css">
<style>
/*<!--去除浏览器点击操作后有蓝色的底块-->*/
@ -146,16 +148,30 @@
<!-- 在tpi js里加载这3个脚本 -->
<script>
(function() { // Scoping function to avoid globals
var href = location.href;
if (href.indexOf('/tasks/') != -1) {
document.write('<script type="text/javascript" src="https://testeduplus2.educoder.net/assets/kindeditor/kindeditor.js"><\/script>');
// build.js中会将这个url附加一个前缀 react/build
document.write('<script type="text/javascript" src="/js/create_kindeditor.js"><\/script>');
document.write('<script type="text/javascript" src="https://testeduplus2.educoder.net/javascripts/educoder/edu_application.js"><\/script>');
} else if (href.indexOf('/paths/') != -1) {
document.write('<script type="text/javascript" src="https://testeduplus2.educoder.net/javascripts/educoder/edu_application.js"><\/script>');
}
var href = location.href;
if(window.location.port === "3007"){
if (href.indexOf('/tasks/') != -1) {
document.write('<script type="text/javascript" src="https://newweb.educoder.net/assets/kindeditor/kindeditor.js"><\/script>');
// build.js中会将这个url附加一个前缀 react/build
document.write('<script type="text/javascript" src="/js/create_kindeditor.js"><\/script>');
document.write('<script type="text/javascript" src="https://newweb.educoder.net/javascripts/educoder/edu_application.js"><\/script>');
} else if (href.indexOf('/paths/') != -1) {
document.write('<script type="text/javascript" src="https://newweb.educoder.net/javascripts/educoder/edu_application.js"><\/script>');
}
}else{
if (href.indexOf('/tasks/') != -1) {
document.write('<script type="text/javascript" src="/assets/kindeditor/kindeditor.js"><\/script>');
// build.js中会将这个url附加一个前缀 react/build
document.write('<script type="text/javascript" src="/js/create_kindeditor.js"><\/script>');
document.write('<script type="text/javascript" src="/javascripts/educoder/edu_application.js"><\/script>');
} else if (href.indexOf('/paths/') != -1) {
document.write('<script type="text/javascript" src="/javascripts/educoder/edu_application.js"><\/script>');
}
}
})();
</script>
<!-- <script type="text/javascript" src="https://testeduplus2.educoder.net/assets/kindeditor/kindeditor.js"></script>

@ -38,7 +38,7 @@
<link rel="stylesheet" type="text/css" href="/css/css_min_all.css">
<link href="https://testeduplus2.educoder.net/stylesheets/educoder/edu-all.css" rel="stylesheet" type="text/css">
<link href="/stylesheets/educoder/edu-all.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" type="text/css" href="//at.alicdn.com/t/font_653600_qa9lwwv74z.css">

File diff suppressed because it is too large Load Diff

@ -0,0 +1,9 @@
/*!
* Cropper.js v1.5.2
* https://fengyuanchen.github.io/cropperjs
*
* Copyright 2015-present Chen Fengyuan
* Released under the MIT license
*
* Date: 2019-06-30T06:01:02.389Z
*/.cropper-container{direction:ltr;font-size:0;line-height:0;position:relative;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.cropper-container img{display:block;height:100%;image-orientation:0deg;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;width:100%}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal,.cropper-wrap-box{bottom:0;left:0;position:absolute;right:0;top:0}.cropper-canvas,.cropper-wrap-box{overflow:hidden}.cropper-drag-box{background-color:#fff;opacity:0}.cropper-modal{background-color:#000;opacity:.5}.cropper-view-box{display:block;height:100%;outline:1px solid #39f;outline-color:rgba(51,153,255,.75);overflow:hidden;width:100%}.cropper-dashed{border:0 dashed #eee;display:block;opacity:.5;position:absolute}.cropper-dashed.dashed-h{border-bottom-width:1px;border-top-width:1px;height:33.33333%;left:0;top:33.33333%;width:100%}.cropper-dashed.dashed-v{border-left-width:1px;border-right-width:1px;height:100%;left:33.33333%;top:0;width:33.33333%}.cropper-center{display:block;height:0;left:50%;opacity:.75;position:absolute;top:50%;width:0}.cropper-center:after,.cropper-center:before{background-color:#eee;content:" ";display:block;position:absolute}.cropper-center:before{height:1px;left:-3px;top:0;width:7px}.cropper-center:after{height:7px;left:0;top:-3px;width:1px}.cropper-face,.cropper-line,.cropper-point{display:block;height:100%;opacity:.1;position:absolute;width:100%}.cropper-face{background-color:#fff;left:0;top:0}.cropper-line{background-color:#39f}.cropper-line.line-e{cursor:ew-resize;right:-3px;top:0;width:5px}.cropper-line.line-n{cursor:ns-resize;height:5px;left:0;top:-3px}.cropper-line.line-w{cursor:ew-resize;left:-3px;top:0;width:5px}.cropper-line.line-s{bottom:-3px;cursor:ns-resize;height:5px;left:0}.cropper-point{background-color:#39f;height:5px;opacity:.75;width:5px}.cropper-point.point-e{cursor:ew-resize;margin-top:-3px;right:-3px;top:50%}.cropper-point.point-n{cursor:ns-resize;left:50%;margin-left:-3px;top:-3px}.cropper-point.point-w{cursor:ew-resize;left:-3px;margin-top:-3px;top:50%}.cropper-point.point-s{bottom:-3px;cursor:s-resize;left:50%;margin-left:-3px}.cropper-point.point-ne{cursor:nesw-resize;right:-3px;top:-3px}.cropper-point.point-nw{cursor:nwse-resize;left:-3px;top:-3px}.cropper-point.point-sw{bottom:-3px;cursor:nesw-resize;left:-3px}.cropper-point.point-se{bottom:-3px;cursor:nwse-resize;height:20px;opacity:1;right:-3px;width:20px}@media (min-width:768px){.cropper-point.point-se{height:15px;width:15px}}@media (min-width:992px){.cropper-point.point-se{height:10px;width:10px}}@media (min-width:1200px){.cropper-point.point-se{height:5px;opacity:.75;width:5px}}.cropper-point.point-se:before{background-color:#39f;bottom:-50%;content:" ";display:block;height:200%;opacity:0;position:absolute;right:-50%;width:200%}.cropper-invisible{opacity:0}.cropper-bg{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")}.cropper-hide{display:block;height:0;position:absolute;width:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed}

File diff suppressed because one or more lines are too long

@ -1,103 +1,103 @@
function Base64() {
// private property
_keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
// public method for encoding
this.encode = function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = _utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
}
return output;
}
// public method for decoding
this.decode = function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = _keyStr.indexOf(input.charAt(i++));
enc2 = _keyStr.indexOf(input.charAt(i++));
enc3 = _keyStr.indexOf(input.charAt(i++));
enc4 = _keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = _utf8_decode(output);
return output;
}
// private method for UTF-8 encoding
_utf8_encode = function (string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
// private method for UTF-8 decoding
_utf8_decode = function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i+1);
c3 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
// private property
_keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
// public method for encoding
this.encode = function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = _utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
}
return output;
}
// public method for decoding
this.decode = function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = _keyStr.indexOf(input.charAt(i++));
enc2 = _keyStr.indexOf(input.charAt(i++));
enc3 = _keyStr.indexOf(input.charAt(i++));
enc4 = _keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = _utf8_decode(output);
return output;
}
// private method for UTF-8 encoding
_utf8_encode = function (string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
// private method for UTF-8 decoding
_utf8_decode = function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i+1);
c3 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,224 +1,225 @@
'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,
});
}
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://cdn-testeduplus2.educoder.net'
cdnHost = ''
var result = data.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}`)
.replace('/css/css_min_all.css', `${cdnHost}/react/build/css/css_min_all.css?v=${newVersion}`)
.replace('/js/create_kindeditor.js', `${cdnHost}/react/build/js/create_kindeditor.js?v=${newVersion}`)
// .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);
'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,
});
}
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 = 'http://cdn.educoder.net'
cdnHost = ''
var result = data.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}`)
.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('/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);
}

@ -35,6 +35,10 @@
.editormd .CodeMirror-linenumbers {
padding: 0;
}
.editormd-html-preview hr, .editormd-preview-container hr {
/* 颜色加深 */
border-top: 1px solid #ccc;
}
/* 重置掉antd的一些样式 */
html, body {

@ -14,6 +14,9 @@ import '@icedesign/base/dist/ICEDesignBase.css';
import '@icedesign/base/index.scss';
import LoginDialog from './modules/login/LoginDialog'
import Notcompletedysl from './modules/user/Notcompletedysl'
import Trialapplicationysl from './modules/login/Trialapplicationysl'
import Trialapplicationreview from './modules/user/Trialapplicationreview'
import Trialapplication from './modules/login/Trialapplication'
import NotFoundPage from './NotFoundPage'
@ -110,6 +113,11 @@ const CoursesIndex = Loadable({
loader: () => import('./modules/courses/Index'),
loading: Loading,
})
const SearchPage = Loadable({
loader: () => import('./search/SearchPage'),
loading: Loading,
})
// 课堂讨论
// const BoardIndex = Loadable({
// loader: () => import('./modules/courses/boards/BoardIndex'),
@ -207,6 +215,12 @@ const UsersInfo = Loadable({
loading: Loading,
})
// 兴趣页面
const Interestpage = Loadable({
loader: () => import('./modules/login/EducoderInteresse'),
loading: Loading,
})
class App extends Component {
constructor(props) {
super(props)
@ -218,7 +232,12 @@ class App extends Component {
componentDidMount() {
// force an update if the URL changes
history.listen(() => this.forceUpdate());
history.listen(() => {
this.forceUpdate()
const $ = window.$
// https://www.trustie.net/issues/21919 可能会有问题
$("html").animate({ scrollTop: $('html').scrollTop() - 0 })
});
initAxiosInterceptors(this.props)
@ -241,12 +260,16 @@ class App extends Component {
render() {
// let {isRenders} = this.state;
return (
<LocaleProvider locale={zhCN}>
<MuiThemeProvider theme={theme}>
<LoginDialog></LoginDialog>
<LoginDialog {...this.props} {...this.state}></LoginDialog>
<Notcompletedysl {...this.props} {...this.state}></Notcompletedysl>
<Trialapplicationysl {...this.props} {...this.state}></Trialapplicationysl>
<Trialapplicationreview {...this.props} {...this.state}></Trialapplicationreview>
{/*{*/}
{/* isRender === true?*/}
{/* <LoginDialog></LoginDialog> : ""*/}
@ -254,7 +277,7 @@ class App extends Component {
{/*{*/}
{/* isRenders === true?*/}
<Trialapplication></Trialapplication>
{/*<Trialapplication></Trialapplication>*/}
{/*:""*/}
{/*}*/}
@ -262,7 +285,7 @@ class App extends Component {
<Switch>
{/*<Route path="/login" component={LoginRegisterPage}/>*/}
{/*认证*/}
{/*<Route path="/account" component={AccountPage}/>*/}
<Route path="/account" component={AccountPage}/>
{/*403*/}
<Route path="/403" component={Shixunauthority}/>
@ -289,7 +312,10 @@ class App extends Component {
<Route
path="/changepassword" component={EducoderLogin}
/>
<Route
path="/interesse" component={Interestpage}
/>
<Route path="/shixuns/new" component={Newshixuns}>
</Route>
@ -307,15 +333,22 @@ class App extends Component {
<Route path="/fork_list" component={TPMshixunfork_listIndexComponent}>
</Route> */}
<Route path="/forums" component={ForumsIndexComponent}>
</Route>
{/*<Route path="/forums" component={ForumsIndexComponent}>*/}
{/*</Route>*/}
{/*实训课程(原实训路径)*/}
<Route path="/paths" component={ShixunPaths}></Route>
<Route path="/search"
render={
(props)=>(<SearchPage {...this.props} {...props} {...this.state}></SearchPage>)
}
></Route>
{/*课堂*/}
<Route path="/courses" component={CoursesIndex} {...this.props}></Route>
{/* 课堂讨论 */}
{/* <Route path="/board" component = {BoardIndex} {...this.props}></Route> */}
@ -323,7 +356,8 @@ class App extends Component {
</Route> */}
{/* <Route path="/myshixuns/:shixunId/stages/:stageId" component={Index}/> */}
{/* 兴趣页面*/}
{/*<Route path="/interest" component={Interestpage}/>*/}
<Route path="/comment" component={CommentComponent}/>
<Route path="/testMaterial" component={TestMaterialDesignComponent}/>

@ -2,22 +2,23 @@ import React from "react";
import axios from 'axios';
import { requestProxy } from "./indexEduplus2RequestProxy";
import { broadcastChannelOnmessage } from 'educoder'
import { broadcastChannelOnmessage ,SetAppModel} from 'educoder';
import { notification } from 'antd';
import './index.css'
broadcastChannelOnmessage('refreshPage', () => {
window.location.reload()
})
function locationurl(list){
if (window.location.port === "3007") {
if (window.location.port === "3007") {
} else {
window.location.replace(list)
}
} else {
window.location.replace(list)
}
}
// TODO 开发期多个身份切换
const debugType = window.location.search.indexOf('debug=t') != -1 ? 'teacher' :
const debugType =window.location.search.indexOf('debug=t') != -1 ? 'teacher' :
window.location.search.indexOf('debug=s') != -1 ? 'student' : 'admin'
window._debugType = debugType;
export function initAxiosInterceptors(props) {
@ -29,7 +30,8 @@ export function initAxiosInterceptors(props) {
var proxy = "http://localhost:3000"
// proxy = "http://testbdweb.trustie.net"
// proxy = "http://testbdweb.educoder.net"
proxy = "https://testeduplus2.educoder.net"
// proxy = "https://testeduplus2.educoder.net"
proxy="http://47.96.87.25:48080"
// 在这里使用requestMap控制避免用户通过双击等操作发出重复的请求
@ -100,6 +102,7 @@ export function initAxiosInterceptors(props) {
if(response===undefined){
return
}
const config = response.config
if (response.data.status === -1) {
// console.error('error:', response.data.message)
// throw new Error()
@ -114,6 +117,9 @@ export function initAxiosInterceptors(props) {
notification.open({
message:"提示",
description: response.data.message || '服务器异常,请联系管理员。',
style: {
zIndex: 99999999
},
});
// notification['error']({
// message:"提示",
@ -138,9 +144,16 @@ export function initAxiosInterceptors(props) {
locationurl('/500');
}
if (response.data.status === 402) {
locationurl(response.data.url);
}
// if (response.data.status === 402) {
// console.log(response.data.status);
// console.log(response.data);
// // locationurl(402);
// }
if (response.data.status === 401) {
return config;
}
// if (response.data.status === 407) {
// 在app js 中解决 Trialapplication
// // </Trialapplication>

@ -1,16 +1,27 @@
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
class Loading extends Component {
render() {
// Loading
return (
<div className="App" style={{minHeight: '800px'}}>
</div>
);
}
}
export default Loading;
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { Spin } from 'antd';
class Loading extends Component {
render() {
// Loading
return (
<div className="App" style={{minHeight: '800px',width:"100%"}}>
<style>
{
`
.margintop{
margin-top:20%;
}
`
}
</style>
<Spin size="large" className={"margintop"}/>
</div>
);
}
}
export default Loading;

@ -1,7 +1,19 @@
/**
EDU_ADMIN = 1 # 超级管理员
EDU_BUSINESS = 2 # 运营人员
EDU_SHIXUN_MANAGER = 3 # 实训管理员
EDU_SHIXUN_MEMBER = 4 # 实训成员
EDU_CERTIFICATION_TEACHER = 5 # 平台认证的老师
EDU_GAME_MANAGER = 6 # TPI的创建者
EDU_TEACHER = 7 # 平台老师,但是未认证
EDU_NORMAL = 8 # 普通用户
*/
export const EDU_ADMIN = 1 // 超级管理员
export const EDU_SHIXUN_MANAGER = 2 // 实训管理员
export const EDU_SHIXUN_MEMBER = 3 // 实训成员
export const EDU_CERTIFICATION_TEACHER = 4 // 平台认证的老师
export const EDU_GAME_MANAGER = 5 // TPI的创建者
export const EDU_TEACHER = 6 // 平台老师,但是未认证
export const EDU_NORMAL = 7 // 普通用户
export const EDU_BUSINESS = 2 // # 运营人员
export const EDU_SHIXUN_MANAGER = 3 // 实训管理员
export const EDU_SHIXUN_MEMBER = 4 // 实训成员
export const EDU_CERTIFICATION_TEACHER = 5 // 平台认证的老师
export const EDU_GAME_MANAGER = 6 // TPI的创建者
export const EDU_TEACHER = 7 // 平台老师,但是未认证
export const EDU_NORMAL = 8 // 普通用户

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

@ -1,5 +1,9 @@
import { bytesToSize } from 'educoder';
export function markdownToHTML(oldContent) {
export function isImageExtension(fileName) {
return fileName ? !!(fileName.match(/.(jpg|jpeg|png|gif)$/i)) : false
}
export function markdownToHTML(oldContent, selector) {
window.$('#md_div').html('')
// markdown to html
var markdwonParser = window.editormd.markdownToHTML("md_div", {
@ -12,6 +16,9 @@ export function markdownToHTML(oldContent) {
sequenceDiagram: true // 默认不解析
});
const content = window.$('#md_div').html()
if (selector) {
window.$(selector).html(content)
}
return content
}

@ -1,6 +1,6 @@
export function bytesToSize(bytes) {
var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
if (bytes == 0) return '0 Byte';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
export function bytesToSize(bytes) {
var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
if (bytes == 0) return '0 Byte';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return parseFloat(bytes / Math.pow(1024, i), 2).toFixed(1) + ' ' + sizes[i];
}

@ -1,40 +1,62 @@
const isDev = window.location.port == 3007;
export function getImageUrl(path) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// const local = 'http://localhost:3000'
const local = 'https://testeduplus2.educoder.net'
if (isDev) {
return `${local}/${path}`
}
return `/${path}`;
}
export function getUrl(path, goTest) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// 如果想所有url定位到测试版可以反注释掉下面这行
//goTest = true
// testbdweb.educoder.net testbdweb.trustie.net
// const local = goTest ? 'https://testeduplus2.educoder.net' : 'http://localhost:3000'
const local = 'https://testeduplus2.educoder.net'
if (isDev) {
return `${local}${path?path:''}`
}
return `${path ? path: ''}`;
}
export function getUploadActionUrl(path, goTest) {
return `${getUrl()}/api/attachments.json${isDev ? `?debug=${window._debugType || 'admin'}` : ''}`
}
export function test(path) {
return `${path}`;
}
export function toPath(path) {
window.open(path, '_blank');
}
const isDev = window.location.port == 3007;
export function getImageUrl(path) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// const local = 'http://localhost:3000'
const local = 'http://47.96.87.25:48080'
if (isDev) {
return `${local}/${path}`
}
return `/${path}`;
}
export function setImagesUrl(path){
const local = 'http://47.96.87.25:48080'
let firstStr=path.substr(0,1);
console.log(firstStr);
if(firstStr=="/"){
return isDev?`${local}${path}`:`${path}`;
}else{
return isDev?`${local}/${path}`:`/${path}`;
}
}
export function getUrl(path, goTest) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// 如果想所有url定位到测试版可以反注释掉下面这行
//goTest = true
// testbdweb.educoder.net testbdweb.trustie.net
// const local = goTest ? 'https://testeduplus2.educoder.net' : 'http://localhost:3000'
// const local = 'https://testeduplus2.educoder.net'
const local = 'http://47.96.87.25:48080'
if (isDev) {
return `${local}${path?path:''}`
}
return `${path ? path: ''}`;
}
export function getUrl2(path, goTest) {
const local = 'http://localhost:3000'
if (isDev) {
return `${local}${path?path:''}`
}
return `${path ? path: ''}`;
}
export function getUploadActionUrl(path, goTest) {
return `${getUrl()}/api/attachments.json${isDev ? `?debug=${window._debugType || 'admin'}` : ''}`
}
export function getUploadActionUrlOfAuth(id) {
return `${getUrl()}/api/users/accounts/${id}/auth_attachments.json${isDev ? `?debug=${window._debugType || 'admin'}` : ''}`
}
export function test(path) {
return `${path}`;
}
export function toPath(path) {
window.open(path, '_blank');
}
// export default queryString

@ -0,0 +1,288 @@
import React, { Component } from 'react';
import { getUrl2, isDev } from 'educoder'
const $ = window.$
let _url_origin = getUrl2()
// let _url_origin = `http://47.96.87.25:48080`;
function save_avatar(){
// if($(img_lg).html().trim() == ""){
// $("#avatar-name").html("请先选择图片上传").css("color", 'red');
// } else {
// $("#avatar-name").html("").css("color", '#333');
const previewId = this.props.previewId
var img_lg = document.getElementById(previewId || 'img-preview');
// 截图小的显示框内的内容
window.html2canvas(img_lg).then(function(canvas) {
// for test
// document.getElementById('canvasWrap').appendChild(canvas);
var dataUrl = canvas.toDataURL("image/jpeg");
console.log(dataUrl)
// TODO upload base64 image data to server
});
return
// 老版接口:
// html2canvas(img_lg, {
// allowTaint: true,
// taintTest: false,
// onrendered: function(canvas) {
// canvas.id = "mycanvas";
// //生成base64图片数据
// var dataUrl = canvas.toDataURL("image/jpeg");
// console.log(dataUrl)
// var newImg = document.getElementById("showImg");
// newImg.src = dataUrl;
// return;
// imagesAjax(dataUrl);
// $(".avatar-save").attr("disabled","true");
// }
// });
// }
}
/**
props 说明
imageId 源图片标签的id
previewId crop后预览dom的id
imageSrc 源图片src
width 数字格式
height 数字格式
*/
class Cropper extends Component {
state = {
};
handleChange = (info) => {
}
componentDidMount() {
this.options = {
aspectRatio: 1,
crop(event) {
// console.log(event.detail.x);
// console.log(event.detail.y);
// console.log(event.detail.width);
// console.log(event.detail.height);
// console.log(event.detail.rotate);
// console.log(event.detail.scaleX);
// console.log(event.detail.scaleY);
},
preview: this.props.previewId ? `#${this.props.previewId}` : '.img-preview',
}
if (!window.Cropper) {
$.ajaxSetup({
cache: true
});
const _isDev = isDev()
let _path = _isDev ? 'public' : 'build'
$('head').append($('<link rel="stylesheet" type="text/css" />')
.attr('href', `${_url_origin}/react/${_path}/js/cropper/cropper.min.css`));
$.getScript(
`${_url_origin}/react/${_path}/js/cropper/cropper.js`,
(data, textStatus, jqxhr) => {
});
$.getScript(
`${_url_origin}/react/${_path}/js/cropper/html2canvas.min.js`,
(data, textStatus, jqxhr) => {
});
}
setTimeout(() => {
const image = document.getElementById(this.props.imageId || '__image');
this.cropper = new window.Cropper(image, this.options);
}, 1000)
}
renew = (image) => {
this.cropper && this.cropper.destroy();
this.cropper = new window.Cropper(image, this.options);
}
render() {
const { width, height, previewId, imageSrc } = this.props;
return (
<div>
{/* This rule is very important, please do not ignore this! */}
<style>{`
.wrapper {
width: ${ width ? (width+'px') : '500px'};
height: ${ height ? (height+'px') : '500px'};
border: 1px solid #eee;
}
img {
max-width: 100%;
}
.preview-lg {
overflow: hidden;
background-color: #fff;
border-radius: 50%;
text-align: center;
}
`}</style>
<div className="wrapper">
{/* http://localhost:3007/images/footNavLogo.png 图片转了后不对
|| "/images/testPicture.jpg"
|| "/images/shixun0.jpg"
*/}
<img id={this.props.imageId || "__image"} src={`${imageSrc }`}></img>
</div>
{/* background: 'aquamarine',
'border-radius': '128px'
*/}
{!previewId && <div id="img-preview" className="img-preview preview-lg" style={{width: '128px', height: '128px', }}>
</div>}
{/* <img id="showImg" src="http://localhost:3007/images/testPicture.jpg"></img> */}
{/* <div id="canvasWrap"></div> */}
{/* <button onClick={save_avatar.bind(this)}>save </button> */}
</div>
);
}
}
export default Cropper;
// function aaa () {
// function showedit_headphoto() {
// var html = `
// <script src=\"../head/jquery.min.js\"><\/script>\n
// <link href=\"../head/cropper.min.css\" rel=\"stylesheet\">\n
// <link href=\"../head/sitelogo.css\" rel=\"stylesheet\">\n
// <script src=\"../head/bootstrap.min.js\"><\/script>\n
// <script src=\"../head/cropper.js\"><\/script>\n
// <script src=\"../head/sitelogo.js\"><\/script>\n
// <script src=\"../head/html2canvas.min.js\" type=\"text/javascript\" charset=\"utf-8\"><\/script>\n\n
// <div class=\"task-popup\" style=\"width: 550px;\">\n <div class=\"task-popup-title clearfix task-popup-bggrey\">上传头像<\/div>\n <div class=\"clearfix\">\n
// <div class=\"modal fade\" style=\"outline: none;\" id=\"avatar-modal\" aria-hidden=\"true\" aria-labelledby=\"avatar-modal-label\" role=\"dialog\" tabindex=\"-1\">\n
// <div class=\"modal-dialog modal-lg\">\n <div class=\"modal-content\">\n <form class=\"avatar-form\">\n <div class=\"modal-body\">\n
// <div class=\"padding20\">\n <div class=\"avatar-upload\">\n <input class=\"avatar-src\" name=\"avatar_src\" type=\"hidden\">\n
// <input class=\"avatar-data\" name=\"avatar_data\" type=\"hidden\">\n\n <span id=\"avatar-name\"><\/span>\n
// <input class=\"avatar-input\" style=\"display:none;\" id=\"avatarInput\" value=\"avatars/User/116\" name=\"avatar_file\" type=\"file\">\n
// <input type=\"hidden\" id=\"source_id\" value=\"116\"/>\n <input type=\"hidden\" id=\"source_type\" value=\"User\"/>\n <\/div>\n
// <div class=\"row clearfix mt20 pl20\">\n <div class=\"task-form-45 fl panel-box-sizing uplaodImg\">\n
// <div class=\"avatar-wrapper\" id=\"wrapper_image_show\">\n <!--<span style=\"display: block;\">\n 选择你要上传的图片<br/>
// \n 仅支持JPG、GIF、PNG且文件小于2M\n <\/span>-->\n <\/div>\n
// <div class=\"row avatar-btns clearfix\">\n <a href=\"javascript:void(0);\" class=\"fl\" type=\"button\" onClick=\"$(\'input[id=avatarInput]\').click();\">重新上传<\/a>\n
// <!--<div class=\"btn-group\">\n <a href=\"javascript:void(0);\" class=\"fa fa-repeat fr mt5 color-grey-9\" data-method=\"rotate\" data-option=\"90\"
// type=\"button\" title=\"Rotate 90 degrees\">\n <\/a>\n <\/div>-->\n <\/div>\n <\/div>\n
// <div class=\"task-form-50 panel-box-sizing fr color-grey pr20\" style=\"width: 128px;\">\n <div class=\"edu-txt-center\">\n
// <div class=\"avatar-preview preview-lg radius\" id=\"imageHead\">\n
// <img alt=\"头像\" height=\"128\" nhname=\"avatar_image\" src=\"/images/avatars/User/116?1556802838\" width=\"128\" />\n <\/div>\n
// <span>头像预览<\/span>\n <\/div>\n
// <p class=\"color-grey-9 font-12 mt110 justify\">仅支持JPG、GIF、PNG且文件小于2M<\/p>\n <\/div>\n <\/div>\n
// <\/div>\n <div class=\"clearfix edu-txt-center mb20 mt10\">\n
// <a href=\"javascript:void(0);\" class=\"task-btn mr20\" onclick=\"hideModal()\">取消<\/a>\n
// <a href=\"javascript:void(0);\" class=\"avatar-save task-btn task-btn-orange\" data-dismiss=\"modal\">确定<\/a>\n
// <\/div>\n <\/div>\n <\/form>\n <\/div>\n <\/div>\n <\/div>\n <\/div>\n<\/div>\n\n<script>\n
// $(function () {\n new CropAvatar($(\'#crop-avatar\'), 1/1);\n\n //---------------------------头像上传-----------------------------//\n //做个下简易的验证 大小 格式\n $(\'#avatarInput\').on(\'change\', function(e) {\n var filemaxsize = 1024 * 5;//5M\n var target = $(e.target);\n var Size = target[0].files[0].size / 1024;\n if(Size > filemaxsize) {\n alert(\'图片过大,请重新选择!\');\n $(\".avatar-wrapper\").children().remove;\n return false;\n }\n if(!this.files[0].type.match(/image.*/)) {\n alert(\'请选择正确的图片!\')\n } else {\n /*var filename = document.querySelector(\"#avatar-name\");*/\n var texts = document.querySelector(\"#avatarInput\").value;\n var teststr = texts; //你这里的路径写错了\n testend = teststr.match(/[^\\\\]+\\.[^\\(]+/i); //直接完整文件名的\n /*filename.innerHTML = testend;\n $(filename).css(\"color\", \'#333\');*/\n $(\".avatar-save\").removeClass(\"task-btn-grey\").addClass(\"task-btn-orange\");\n $(\".avatar-save\").on(\"click\", save_avatar);\n }\n\n });\n });\n\n function save_avatar(){\n var img_lg = document.getElementById(\'imageHead\');\n if($(img_lg).html().trim() == \"\"){\n $(\"#avatar-name\").html(\"请先选择图片上传\").css(\"color\", \'red\');\n } else {\n $(\"#avatar-name\").html(\"\").css(\"color\", \'#333\');\n // 截图小的显示框内的内容\n html2canvas(img_lg, {\n allowTaint: true,\n taintTest: false,\n onrendered: function(canvas) {\n canvas.id = \"mycanvas\";\n //生成base64图片数据\n var dataUrl = canvas.toDataURL(\"image/jpeg\");\n var newImg = document.createElement(\"img\");\n newImg.src = dataUrl;\n imagesAjax(dataUrl);\n $(\".avatar-save\").attr(\"disabled\",\"true\");\n }\n });\n }\n }\n\n function imagesAjax(src) {\n var data = {};\n data.img = src;\n data.source_id = $(\'#source_id\').val();\n data.source_type = $(\'#source_type\').val();\n data.is_direct = 0;\n $.ajax({\n url: \"/upload_avatar\",\n beforeSend: function(xhr) {xhr.setRequestHeader(\'X-CSRF-Token\', $(\'meta[name=\"csrf-token\"]\').attr(\'content\'))},\n data: data,\n type: \"POST\",\n success: function (re) {\n console.log(re);\n console.log(1562050370);\n if(re){\n var o = JSON.parse(re);\n if (o.status !=0 ){\n console.log(o.message);\n } else {\n var imgSpan = $(\"img[nhname=\'avatar_image\']\");\n imgSpan.attr({\"src\": o.url + \'?1562050370\'});\n $(\"#user_code\").html(o.grade);\n notice_box_redirect(\"/users/shitou\", \"上传成功\");\n }\n } else {\n notice_box(\"上传出错\");\n }\n\n },\n error: function (e) {\n alert(e);\n }\n });\n }\n
// <\/script>`;
// pop_box_new(html, 550, 510);
// $("#imageHead img").attr({"src": $("#user_avatar_show").attr("src")});
// $("#wrapper_image_show img").attr({"src": $("#user_avatar_show").attr("src")});
// }
// $(function () {
// new CropAvatar($('#crop-avatar'), 1/1);
// //---------------------------头像上传-----------------------------//
// //做个下简易的验证 大小 格式
// $('#avatarInput').on('change', function(e) {
// var filemaxsize = 1024 * 5;//5M
// var target = $(e.target);
// var Size = target[0].files[0].size / 1024;
// if(Size > filemaxsize) {
// alert('图片过大,请重新选择!');
// $(".avatar-wrapper").children().remove;
// return false;
// }
// if(!this.files[0].type.match(/image.*/)) {
// alert('请选择正确的图片!')
// } else {
// /*var filename = document.querySelector("#avatar-name");*/
// var texts = document.querySelector("#avatarInput").value;
// var teststr = texts; //你这里的路径写错了
// testend = teststr.match(/[^\\\\]+\\.[^\\(]+/i); //直接完整文件名的
// /*filename.innerHTML = testend; $(filename).css("color", '#333');*/
// $(".avatar-save").removeClass("task-btn-grey").addClass("task-btn-orange");
// $(".avatar-save").on("click", save_avatar);
// }
// });
// });
// function save_avatar(){
// var img_lg = document.getElementById('imageHead');
// if($(img_lg).html().trim() == ""){
// $("#avatar-name").html("请先选择图片上传").css("color", 'red');
// } else {
// $("#avatar-name").html("").css("color", '#333');
// // 截图小的显示框内的内容
// html2canvas(img_lg, {
// allowTaint: true,
// taintTest: false,
// onrendered: function(canvas) {
// canvas.id = "mycanvas";
// //生成base64图片数据
// var dataUrl = canvas.toDataURL("image/jpeg");
// var newImg = document.createElement("img");
// newImg.src = dataUrl;
// imagesAjax(dataUrl);
// $(".avatar-save").attr("disabled","true");
// }
// });
// }
// }
// function imagesAjax(src) {
// var data = {};
// data.img = src;
// data.source_id = $('#source_id').val();
// data.source_type = $('#source_type').val();
// data.is_direct = 0;
// $.ajax({
// url: "/upload_avatar",
// beforeSend: function(xhr) {
// xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
// },
// data: data,
// type: "POST",
// success: function (re) {
// console.log(re);
// // console.log(1562050370);
// if(re){
// var o = JSON.parse(re);
// if (o.status !=0 ){
// console.log(o.message);
// } else {
// var imgSpan = $("img[nhname='avatar_image']");
// imgSpan.attr({"src": o.url + '?1562050370'});
// $("#user_code").html(o.grade);
// notice_box_redirect("/users/shitou", "上传成功");
// }
// } else {
// notice_box("上传出错");
// }
// },
// error: function (e) {
// alert(e);
// }
// });
// }
// }

@ -0,0 +1,114 @@
import React, { Component } from 'react';
const $ = window.jQuery
const jQuery = $;
if (!$.drag) {
(function($){
$.fn.dragValidator = function(options){
var x, drag = this, isMove = false, defaults = {
};
var options = $.extend(defaults, options);
//添加背景,文字,滑块
var html = '<div class="drag_bg"></div>'+
'<div class="drag_text" onselectstart="return false;" unselectable="on">拖动滑块验证</div>'+
'<div class="handler handler_bg"></div>';
this.append(html);
var handler = drag.find('.handler');
var drag_bg = drag.find('.drag_bg');
var text = drag.find('.drag_text');
var maxWidth = text.width() - handler.width(); //能滑动的最大间距
//鼠标按下时候的x轴的位置
handler.mousedown(function(e){
isMove = true;
x = e.pageX - parseInt(handler.css('left'), 10);
});
//鼠标指针在上下文移动时移动距离大于0小于最大间距滑块x轴位置等于鼠标移动距离
$(document).mousemove(function(e){
var _x = e.pageX - x;
var handler_offset = handler.offset();
var lastX = e.clientX -x;
lastX = Math.max(0,Math.min(maxWidth,lastX));
if(isMove){
if(_x > 0 && _x <= maxWidth){
handler.css({'left': lastX});
drag_bg.css({'width': lastX});
}
else if(lastX > maxWidth - 5 && lastX < maxWidth + 5 ){ //鼠标指针移动距离达到最大时清空事件
dragOk();
}
}
});
handler.mouseup(function(e){
isMove = false;
var _x = e.pageX - x;
if(text.text() != '验证通过' && _x < maxWidth){ //鼠标松开时,如果没有达到最大距离位置,滑块就返回初始位置
handler.animate({'left': 0});
drag_bg.animate({'width': 0});
}
});
//清空事件
function dragOk(){
options.dragOkCallback && options.dragOkCallback()
var kuaiwidth=drag.width() - handler.width() - 2;
handler.removeClass('handler_bg').addClass('handler_ok_bg');
handler.css({'left':kuaiwidth+'px'})
text.css({'width':kuaiwidth+'px'});
text.text('验证通过');
drag.css({'color': '#fff'});
drag_bg.css({'width':kuaiwidth+'px'})
handler.unbind('mousedown');
$(document).unbind('mousemove');
$(document).unbind('mouseup');
$("#user_verification_notice").html("");
$('#user_verification_notice').parent().hide();
}
};
})(jQuery);
}
class DragValidator extends Component {
componentDidMount () {
// if($("#reg-drag").length>0 && IsPC()){
$("#reg-drag").dragValidator({
height: this.props.height,
dragOkCallback: () => {
this.props.dragOkCallback && this.props.dragOkCallback()
}
});
// }else{
// $("#reg-drag").empty();
// }
}
empty() {
$("#reg-drag").empty();
}
render() {
const height = this.props.height || 45;
const className = this.props.className
const successGreenColor = this.props.successGreenColor || '#29bd8b'
// newMain clearfix
return (
<div id="reg-drag" className={`drag_slider ${className}`}>
<style>{`
.drag_slider .handler {
height: 100%;
}
.drag_slider {
height: ${height}px;
line-height: ${height}px;
}
.drag_slider .drag_bg {
height: ${height}px;
background-color: ${successGreenColor};
}
`}</style>
</div>
);
}
}
export default ( DragValidator );

@ -0,0 +1,48 @@
import React, { Component } from 'react';
import { Modal} from 'antd';
import axios from 'axios';
import '../../modules/user/common.css';
//完善个人资料
class Notcompleted extends Component {
constructor(props) {
super(props);
}
modalCancel=()=>{
window.location.href = "/";
}
setDownload=()=>{
window.location.href ='/account/profile';
}
render() {
console.log(this.props)
return(
<Modal
keyboard={false}
closable={false}
footer={null}
destroyOnClose={true}
title="提示"
centered={true}
visible={this.props.modalsType===undefined?false:this.props.modalsType}
width="530px"
>
<div className="educouddiv">
<div className={"tabeltext-alignleft mt10"}><p>您尚未完善个人资料</p></div>
<div className={"tabeltext-alignleft mt10"}><p>请在完成资料后提交试用申请</p></div>
<div className="clearfix mt30 edu-txt-center">
<a className="task-btn mr30" onClick={()=>this.modalCancel()}>取消</a>
<a className="task-btn task-btn-orange" onClick={()=>this.setDownload()}>立即完善资料</a>
</div>
</div>
</Modal>
)
}
}
export default Notcompleted;

@ -0,0 +1,51 @@
import React, { Component } from 'react';
import { Modal } from 'antd';
export function SetAppModel(options={}) {
return function wrap(WrappedComponent) {
return class Wrapper extends Component {
constructor(props) {
super(props);
this.state = {
}
}
modalCancel=()=>{
window.location.href = "/";
}
setDownload=()=>{
window.location.href ='/account/profile';
}
componentDidMount(){
console.log(this.props)
}
render() {
const { titlemessage, Modallisttype, Modallist, singleButton } = this.state;
return (
<Modal
keyboard={false}
closable={false}
footer={null}
destroyOnClose={true}
title="提示"
centered={true}
visible={true}
width="530px"
>
<div className="educouddiv">
<div className={"tabeltext-alignleft mt10"}><p>您尚未完善个人资料</p></div>
<div className={"tabeltext-alignleft mt10"}><p>请在完成资料后提交试用申请</p></div>
<div className="clearfix mt30 edu-txt-center">
<a className="task-btn mr30" onClick={()=>this.modalCancel()}>取消</a>
<a className="task-btn task-btn-orange" onClick={()=>this.setDownload()}>立即完善资料</a>
</div>
</div>
</Modal>
)
}
}
}
}

@ -1719,6 +1719,10 @@ const options = [{
label: '其他'
}],
}];
function filter(inputValue, path) {
return path.some(option => option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1);
}
class City extends Component{
constructor(props){
super(props);
@ -1739,11 +1743,16 @@ class City extends Component{
}
}
render(){
const { defaultValue } = this.props
const { defaultValue, matchInputWidth, className, popupClassName } = this.props
const { value } = this.state
// 这里用请选择所在省市的话会触发chrome的地址选择
return(
<Cascader allowClear size="large" options={options} placeholder="请选择所在省市" onChange={this.onChange}
<Cascader allowClear size="large" options={options} placeholder="请选择所在地" onChange={this.onChange}
matchInputWidth={matchInputWidth}
value={value}
showSearch={{ filter }}
className={className}
popupClassName={popupClassName}
></Cascader>
)
}

@ -1,72 +1,83 @@
import React,{ Component } from "react";
import TPMMDEditor from '../../../modules/tpm/challengesnew/TPMMDEditor'
import {markdownToHTML} from 'educoder'
import './DMDEditor.css'
// 需要父组件通过toShowMode、toMDMode 来控制一次只能打开一个DMDEditor
class DMDEditor extends Component{
constructor(props){
super(props);
this.mdRef = React.createRef()
this.state={
mdMode: false,
// value: this.props.initValue
}
}
componentDidUpdate(prevProps, prevState) {
}
componentDidMount() {
// if(this.props.initValue != this.mdRef.current.getValue()) {
// this.mdRef.current.setValue(this.props.initValue)
// }
}
toMDMode = () => {
this.setState({mdMode: true}, () => {
this.mdRef.current.resize()
this.mdRef.current.setValue(this.props.initValue)
})
this.props.toMDMode(this)
}
toShowMode = () => {
this.setState({mdMode: false})
this.props.toShowMode && this.props.toShowMode(this)
}
onCMBlur = () => {
this.toShowMode()
}
onChange = (val) => {
// this.setState({ value: val })
this.props.onChange(val)
}
render(){
const { mdMode } = this.state;
const { initValue } = this.props;
return(
<React.Fragment>
<style>{`
`}</style>
<div id="content_editorMd_show" className="new_li content_editorMd_show"
style={{display: mdMode == true ? 'none' : '', color: initValue? '': '#999', alignItems: 'center', wordBreak: 'break-all'}}
dangerouslySetInnerHTML={{__html: initValue ? markdownToHTML(initValue):this.props.placeholder}}
onClick={this.toMDMode}
>
</div>
{/*
onCMBlur={this.onCMBlur} */}
<TPMMDEditor
ref={this.mdRef}
{...this.props}
initValue={initValue}
className={`${this.props.className} ${mdMode == true ? '' : 'hideMd'}`}
onChange={this.onChange}
></TPMMDEditor>
</React.Fragment>
)
}
}
import React,{ Component } from "react";
import TPMMDEditor from '../../../modules/tpm/challengesnew/TPMMDEditor'
import {markdownToHTML} from 'educoder'
import './DMDEditor.css'
// 需要父组件通过toShowMode、toMDMode 来控制一次只能打开一个DMDEditor
class DMDEditor extends Component{
constructor(props){
super(props);
this.mdRef = React.createRef()
this.state={
mdMode: false,
// value: this.props.initValue
}
}
componentDidUpdate(prevProps, prevState) {
}
componentDidMount() {
// if(this.props.initValue != this.mdRef.current.getValue()) {
// this.mdRef.current.setValue(this.props.initValue)
// }
}
toMDMode = () => {
this.setState({mdMode: true}, () => {
this.mdRef.current.resize()
this.mdRef.current.setValue(this.props.initValue)
})
this.props.toMDMode(this)
}
toShowMode = () => {
this.setState({mdMode: false})
this.props.toShowMode && this.props.toShowMode(this)
}
onCMBlur = () => {
this.toShowMode()
}
onChange = (val) => {
// this.setState({ value: val })
this.props.onChange(val)
if (this.state.showError == true) {
this.setState({showError: false})
}
}
showError = () => {
this.mdRef.current.showError()
this.setState({showError: true})
}
render(){
const { mdMode, showError } = this.state;
const { initValue } = this.props;
let _style = {}
if (showError) {
_style.border = '1px solid red'
}
_style = Object.assign(_style, {display: mdMode == true ? 'none' : '', color: initValue? '': '#999', alignItems: 'center', wordBreak: 'break-all'})
return(
<React.Fragment>
<style>{`
`}</style>
<div id="content_editorMd_show" className="new_li content_editorMd_show markdown-body"
style={_style}
dangerouslySetInnerHTML={{__html: initValue ? markdownToHTML(initValue):this.props.placeholder}}
onClick={this.toMDMode}
>
</div>
{/*
onCMBlur={this.onCMBlur} */}
<TPMMDEditor
ref={this.mdRef}
{...this.props}
initValue={initValue}
className={`${this.props.className} ${mdMode == true ? '' : 'hideMd'}`}
onChange={this.onChange}
></TPMMDEditor>
</React.Fragment>
)
}
}
export default DMDEditor;

@ -6,40 +6,23 @@ class MarkdownToHtml extends Component{
this.state={
}
}
// componentDidUpdate = (prevProps) => {
// if (this.props.content) {
// if ( prevProps.content != this.props.content ) {
// if (!this.shixunDescr) {
// this.shixunDescr = window.editormd.markdownToHTML("memo_content_editorMd", {
// markdown: this.props.content,
// htmlDecode: "style,script,iframe", // you can filter tags decode
// taskList: true,
// tex: true, // 默认不解析
// flowChart: true, // 默认不解析
// sequenceDiagram: true // 默认不解析
// });
// } else {
// this.shixunDescr.html(this.props.content)
// }
// }
// }
// }
// componentDidMount () {
// if (!this.shixunDescr) {
// this.shixunDescr = window.editormd.markdownToHTML("memo_content_editorMd", {
// markdown: this.props.content,
// htmlDecode: "style,script,iframe", // you can filter tags decode
// taskList: true,
// tex: true, // 默认不解析
// flowChart: true, // 默认不解析
// sequenceDiagram: true // 默认不解析
// });
// }
// }
componentDidUpdate = (prevProps) => {
if (this.props.content) {
if ( prevProps.content != this.props.content ) {
markdownToHTML(this.props.content, `.markdown_to_html_${this.props.selector || ''}`)
}
}
}
componentDidMount () {
this.props.content && markdownToHTML(this.props.content, `.markdown_to_html_${this.props.selector || ''}`)
}
render(){
return(
<div id="memo_content_editorMd" className="new_li markdown-body" dangerouslySetInnerHTML={{__html: markdownToHTML(this.props.content)}}>
<div id="memo_content_editorMd" className={`new_li markdown-body ${this.props.className} markdown_to_html_${this.props.selector || ''}`}
// dangerouslySetInnerHTML={{__html: markdownToHTML(this.props.content)}}
>
</div>
)
}

@ -0,0 +1,17 @@
import React from 'react'
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
foreground_select: '#4CACFF'
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext(
themes.light // default value
);

@ -1,7 +1,9 @@
import React, { Component } from 'react';
import {Link} from 'react-router-dom'
const map={"blue":"blueFull","greyBack":"greyBack","grey":"greyWidthFixed","green":"greenBack"}
const map={"blue":"blueFull","greyBack":"greyBack","grey":"greyWidthFixed","green":"greenBack",
'colorBlue': 'colorBlue', // 蓝字白底
}
class ActionBtn extends Component {
constructor(props) {
super(props);

@ -1,49 +1,57 @@
import { from } from '_array-flatten@2.1.2@array-flatten';
// export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil';
export { getImageUrl as getImageUrl, getUrl as getUrl, getUploadActionUrl as getUploadActionUrl } from './UrlTool';
export { default as queryString } from './UrlTool2';
export { SnackbarHOC as SnackbarHOC } from './SnackbarHOC';
export { trigger as trigger, on as on, off as off
, broadcastChannelPostMessage, broadcastChannelOnmessage } from './EventUtil';
export { updatePageParams as updatePageParams } from './RouterUtil';
export { bytesToSize as bytesToSize } from './UnitUtil';
export { markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll } from './TextUtil'
export { handleDateString, getNextHalfHourOfMoment,formatDuring } from './DateUtil'
export { isDev as isDev } from './Env'
export { toStore as toStore, fromStore as fromStore } from './Store'
export { trace_collapse, trace, debug, info, warn, error, trace_c, debug_c, info_c, warn_c, error_c } from './LogUtil'
export { EDU_ADMIN, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER
, EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL} from './Const'
export { ModalHOC } from './components/ModalHOC'
export { default as ConditionToolTip } from './components/ConditionToolTip'
export { default as DragValidator } from './components/DragValidator'
export { default as PopInstruction } from './components/instruction/PopInstruction'
export { default as City } from './components/form/City'
// course
export { default as WordsBtn } from './course/WordsBtn'
export { default as ActionBtn } from './course/ActionBtn'
export { default as MarkdownToHtml } from './components/markdown/MarkdownToHtml'
export { default as DMDEditor } from './components/markdown/DMDEditor'
import { from } from '_array-flatten@2.1.2@array-flatten';
// export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil';
export { getImageUrl as getImageUrl, getUrl as getUrl, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth } from './UrlTool';
export { default as queryString } from './UrlTool2';
export { SnackbarHOC as SnackbarHOC } from './SnackbarHOC';
export { trigger as trigger, on as on, off as off
, broadcastChannelPostMessage, broadcastChannelOnmessage } from './EventUtil';
export { updatePageParams as updatePageParams } from './RouterUtil';
export { bytesToSize as bytesToSize } from './UnitUtil';
export { markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension } from './TextUtil'
export { handleDateString, getNextHalfHourOfMoment,formatDuring } from './DateUtil'
export { isDev as isDev } from './Env'
export { toStore as toStore, fromStore as fromStore } from './Store'
export { trace_collapse, trace, debug, info, warn, error, trace_c, debug_c, info_c, warn_c, error_c } from './LogUtil'
export { EDU_ADMIN, EDU_BUSINESS, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER
, EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL} from './Const'
export { themes, ThemeContext } from './context/ThemeContext'
export { ModalHOC } from './components/ModalHOC'
export { SetAppModel } from './components/SetAppModel'
export { default as Cropper } from './components/Cropper'
export { default as ConditionToolTip } from './components/ConditionToolTip'
export { default as DragValidator } from './components/DragValidator'
export { default as PopInstruction } from './components/instruction/PopInstruction'
export { default as City } from './components/form/City'
// course
export { default as WordsBtn } from './course/WordsBtn'
export { default as ActionBtn } from './course/ActionBtn'
export { default as MarkdownToHtml } from './components/markdown/MarkdownToHtml'
export { default as DMDEditor } from './components/markdown/DMDEditor'
export { default as ImageLayerHook } from './hooks/ImageLayerHook'

@ -0,0 +1,48 @@
import React, { useState, useEffect, memo } from 'react';
import ImageLayer from '../../modules/page/layers/ImageLayer';
import { isImageExtension } from 'educoder';
const $ = window.$;
function ImageLayerHook(props) {
const [showImage, setShowImage] = useState(false)
const [imageSrc, setImageSrc] = useState('')
const { parentSel, childSel, watchPropsArray } = props
const onImageLayerClose = () => {
setShowImage(false)
setImageSrc('')
}
const onDelegateClick = (event) => {
const imageSrc = event.target.src || event.target.getAttribute('src') || event.target.getAttribute('href')
// 判断imageSrc是否是图片
const fileName = event.target.innerHTML.trim()
if (isImageExtension(imageSrc.trim()) || isImageExtension(fileName) || event.target.tagName == 'IMG' || imageSrc.indexOf('base64,') != -1) {
// 非回复里的头像图片; 非emoticons
if (imageSrc.indexOf('/images/avatars/User') === -1 &&
imageSrc.indexOf('kindeditor/plugins/emoticons') === -1 ) {
setShowImage(true)
setImageSrc(imageSrc)
}
event.stopPropagation()
event.preventDefault && event.preventDefault()
event.originalEvent.preventDefault()
// event.originalEvent.stopPropagation()
// event.originalEvent.cancelBubble = true
return false;
}
}
useEffect(() => {
$(parentSel)
.delegate(childSel, "click", onDelegateClick);
return () => {
$(parentSel).undelegate(childSel, "click", onDelegateClick )
}
})
return (
<ImageLayer showImage={showImage} imageSrc={imageSrc} onImageLayerClose={onImageLayerClose}></ImageLayer>
)
}
export default memo(ImageLayerHook)

@ -17,7 +17,16 @@ class EvaluateSuccessEffectDisplay extends Component {
}
componentDidMount() {
if (this.props.type == 'html') {
const iframe = document.getElementById('_displayIframe')
if (iframe && iframe.contentWindow) {
iframe.contentWindow.open()
iframe.contentWindow.document.write(this.props.iframe_src);
iframe.contentWindow.document.close();
} else {
console.error('not mounted')
}
}
}
hidepicture = () => {
window.$('#picture_display').hide();
@ -26,7 +35,7 @@ class EvaluateSuccessEffectDisplay extends Component {
// qrcode
// const type = 'image' // 'qrcode'
const { type, qrcode_str,
answer_picture, orignal_picture, user_picture } = this.props;
answer_picture, orignal_picture, user_picture, contents } = this.props;
if (type == 'qrcode') {
// 单张图片比如安卓评测完显示qrcode
return (
@ -51,16 +60,16 @@ class EvaluateSuccessEffectDisplay extends Component {
</div>
<div className="clearfix" id="picture-content">
<div className="fl with33 mr03precent pt10 mb50">
<img alt="Icon"
src={orignal_picture[0].pic_url}/>
{orignal_picture[0] && <img alt="Icon"
src={ orignal_picture[0].pic_url}/>}
</div>
<div className="fl with33 mr03precent pt10 mb50">
<img alt="Icon"
src={user_picture[0].pic_url}/>
{user_picture[0] && <img alt="Icon"
src={ user_picture[0].pic_url }/>}
</div>
<div className="fl with33 mr03precent pt10 mb50">
<img alt="Icon"
src={answer_picture[0].pic_url}/>
{ answer_picture[0] && <img alt="Icon"
src={ answer_picture[0].pic_url}/> }
</div>
</div>
</div>
@ -69,12 +78,16 @@ class EvaluateSuccessEffectDisplay extends Component {
if (type == "txt") {
return (
<div className="task-popup-content clearfix">
<div className="with49" style={{margin: '0 auto'}}>
<div className="with80" style={{margin: '0 auto'}}>
<p className="color-blue font-18 mb20 edu-txt-center">实际输出</p>
<textarea className="output-txt" readonly="" defaultValue={content}></textarea>
<textarea className="output-txt" readonly="" defaultValue={contents}></textarea>
</div>
</div>
)
} else if (type == "html") {
return (
<iframe id="_displayIframe"></iframe>
)
}
/* <div className="with49 fr">
@ -95,12 +108,17 @@ class EvaluateSuccessEffectDisplay extends Component {
height: 100%;
box-sizing: border-box;
}
iframe#_displayIframe {
width: 100%;
height: 100%;
}
`}
</style>
<div className="photo_display">
<div className="task-popup">
<div className="task-popup-title clearfix">
<h3 className="fl color-grey3">查看效果</h3>
<h3 className="fl color-grey3 mt4">查看效果</h3>
<a href="javascript:void(0);" onClick={this.hidepicture}
data-tip-left="关闭查看效果" className="pop_close fr">
<i className="fa fa-times-circle font-18 link-color-grey mt5"></i>

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

@ -33,4 +33,8 @@ body {
}
.anticon anticon-paper-clip{
color: #29bd8b !important;
}
.MuiModal-root-15{
z-index: 1000 !important;
}

@ -1,46 +1,46 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import './indexPlus.css';
import App from './App';
// 加之前main.js 18.1MB
// import { message } from 'antd';
import message from 'antd/lib/message';
import 'antd/lib/message/style/css';
import { AppContainer } from 'react-hot-loader';
import registerServiceWorker from './registerServiceWorker';
import { configureUrlQuery } from 'react-url-query';
import history from './history';
// link the history used in our app to url-query so it can update the URL with it.
configureUrlQuery({ history });
// ----------------------------------------------------------------------------------- 请求配置
window.__useKindEditor = false;
const render = (Component) => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.getElementById('root')
);
}
// ReactDOM.render(
// ,
// document.getElementById('root'));
// registerServiceWorker();
render(App);
if (module.hot) {
module.hot.accept('./App', () => { render(App) });
}
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import './indexPlus.css';
import App from './App';
// 加之前main.js 18.1MB
// import { message } from 'antd';
import message from 'antd/lib/message';
import 'antd/lib/message/style/css';
import { AppContainer } from 'react-hot-loader';
import registerServiceWorker from './registerServiceWorker';
import { configureUrlQuery } from 'react-url-query';
import history from './history';
// link the history used in our app to url-query so it can update the URL with it.
configureUrlQuery({ history });
// ----------------------------------------------------------------------------------- 请求配置
window.__useKindEditor = false;
const render = (Component) => {
ReactDOM.render(
<AppContainer {...this.props} {...this.state}>
<Component {...this.props} {...this.state}/>
</AppContainer>,
document.getElementById('root')
);
}
// ReactDOM.render(
// ,
// document.getElementById('root'));
// registerServiceWorker();
render(App);
if (module.hot) {
module.hot.accept('./App', () => { render(App) });
}

@ -1,639 +0,0 @@
import React, {Component} from 'react';
import {Link} from "react-router-dom";
import axios from 'axios';
import {getImageUrl, trigger} from 'educoder';
import { Tooltip, message,Popover} from 'antd';
import CoursesListType from '../coursesPublic/CoursesListType';
import Addcourses from '../coursesPublic/Addcourses';
import '../css/Courses.css';
import Modals from "../../modals/Modals";
import AddStudentModal from '../members/modal/AddStudentModal'
import AddTeacherModal from '../members/modal/AddTeacherModal'
// 点击按钮复制功能
// function jsCopy(){
// var e = document.getElementById("copy_invite_code");
// e.select();
// document.execCommand("Copy");
// codesuccess()
// }
// 点击按钮复制功能
function jsCopy() {
var e = document.getElementById("copy_invite_code");
e.select();
document.execCommand("Copy");
codesuccess()
}
function codesuccess() {
message.success('复制成功');
};
class CoursesBanner extends Component {
constructor(props) {
super(props)
this.state = {
show: false,
Addcoursestypes: false,
modalsType: false,
modalsTopval: "",
loadtype: false,
metype: 0,
modalsBottomval: "",
antIcon:false,
coursedata:undefined
}
}
componentDidMount() {
this.updatabanner()
}
updatabanner=()=>{
let courseId = this.props.match.params.coursesId;
let url = "/courses/" + courseId + "/top_banner.json"
axios.get(url).then((result) => {
let data = result.data;
this.setState({
coursedata: data
})
// console.log(data)
})
}
showeditmenu = () => {
this.setState({
show: true,
})
}
hideeditmenu = () => {
this.setState({
show: false
})
}
tojoinclass = (val) => {
if (val === 1) {
this.setState({
Addcoursestypes: true,
})
} else {
this.setState({
Addcoursestypes: false,
})
}
}
showActionPoll=(i,s,ss)=>{
this.setState({
modalsType: true,
modalsTopval: s,
loadtype: false,
metype: i,
modalsBottomval: ss,
})
}
ActionPoll = (i) => {
let {coursedata}=this.state;
var s = "";
var ss = "";
if (i === 1) {
s = "课堂删除后数据将无法恢复,是否确定删除?";
this.showActionPoll(i,s)
}
if (i === 2) {
s = "您确定要设置为私有?";
this.showActionPoll(i,s)
}
if (i === 3) {
s = "您确定要设置为公开?";
this.showActionPoll(i,s)
}
if(i===4){
if(coursedata.code_halt === true){
var url = `/courses/${this.props.match.params.coursesId}/set_invite_code_halt.json`
axios.post(url, {}).then((result) => {
try {
if (result.data.status === 0){
this.updatabanner()
}
} catch (e) {
}
})
}else{
s = "邀请码停用后,用户不能主动加入该课堂了";
ss = "您是否确认停用?";
this.showActionPoll(i,s,ss)
}
}
if (i ===5) {
s = "复制将在后台执行,作业、资源、试卷都将复制到新课堂平台";
ss = "将为你创建一个新的同名课堂,请问是否继续?";
this.showActionPoll(i,s,ss)
}
}
//取消
modalCancel = () => {
this.setState({
modalsType: false,
modalsTopval: "",
modalsBottomval:"",
loadtype: false,
antIcon:false
})
}
// 确定
ModalAction = () => {
let {coursedata}=this.state;
var push = this.props.history;
let id = this.props.match.params.coursesId;
//删除
if (this.state.metype === 1) {
console.log("删除");
this.modalCancel();
var url = `/courses/${id}.json`
axios
.delete(url, {})
.then(function (response) {
console.log(response.data.status)
if (response.data.status === 0) {
message.success("删除成功", 1)
push.push(`/courses`)
}
})
}
//设为私有的
if (this.state.metype === 2) {
this.modalCancel();
var state = this.state;
var url = `/courses/${id}/set_public_or_private.json`
axios.post(url, {}).then((result) => {
if (result.data.status === 0) {
message.success("设为私有的成功", 1);
state.coursedata.is_public = false;
this.setState({
coursedata: state.coursedata,
})
}
})
}
//设为公有的
if (this.state.metype === 3) {
this.modalCancel();
var state = this.state;
var url = `/courses/${id}/set_public_or_private.json`
axios.post(url, {}).then((result) => {
if (result.data.status === 0) {
message.success("设为公有的成功", 1);
state.coursedata.is_public = true;
this.setState({
coursedata: state.coursedata,
})
}
})
}
//停用邀请码
if (this.state.metype === 4) {
this.modalCancel();
var url = `/courses/${id}/set_invite_code_halt.json`
axios.post(url, {}).then((result) => {
try {
if (result.data.status === 0) {
message.success(coursedata.code_halt === true?"启用用邀请码成功":"停用邀请码成功", 1);
this.updatabanner()
}
} catch (e) {
}
})
}
if (this.state.metype ===5) {
this.setState({
antIcon: true,
})
var url = `/courses/${id}/duplicate_course.json`
axios.post(url).then((response) => {
// window.location.href = "/courses/" + response.data.new_course_id;
window.location.href = "/courses/" + response.data.new_course_id+"/students";
})
}
if(this.state.metype===6){
this.setState({
antIcon: true,
})
var url =`/courses/${id}/exit_course.json`;
axios.post(url).then((response) => {
if(response.data.status===0){
window.location.href = "/users/" + this.props.current_user.login;
}
})
}
}
addTeacher = (isTeacher) => {
this.setState({ isTeacher }, () => {
this.refs.addTeacherModal.setVisible(true)
})
}
addStudent = () => {
this.refs.addStudentModal.setVisible(true)
}
addTeacherSuccess = (params) => {
trigger('addTeacherSuccess', JSON.stringify(params))
this.updatabanner()
}
addStudentSuccess = (params) => {
trigger('addStudentSuccess', JSON.stringify(params))
this.updatabanner()
}
//退出课堂按钮
exitclass=()=>{
this.setState({
modalsType: true,
modalsTopval: "退出后您将不再是本课题的成员,作品将全部被删除,",
modalsBottomval:"确定要退出该课堂吗?",
metype:6
})
}
//切换身份
switchidentity=(sum)=>{
let newurl=this.props.match.url;
let id = this.props.match.params.coursesId;
if(sum===1){
let url =`/courses/${id}/switch_to_student.json`;
axios.post(url).then((response) => {
if(response.data.status===0){
// window.location.href = "/users/" + this.props.current_user.login;
// this.props.history.replace(newurl);
window.location.href=newurl
}
})
}
if(sum===2){
let url =`/courses/${id}/switch_to_teacher.json`;
axios.post(url).then((response) => {
if(response.data.status===0){
// window.location.href = "/users/" + this.props.current_user.login;
// this.props.history.replace(newurl);
window.location.href=newurl
}
})
}
if(sum===3){
let url =`/courses/${id}/switch_to_assistant.json`;
axios.post(url).then((response) => {
if(response.data.status===0){
// window.location.href = "/users/" + this.props.current_user.login;
// this.props.history.replace(newurl);
window.location.href=newurl
}
})
}
}
postsettings=()=>{
window.location.href = "/courses/" + this.props.match.params.coursesId + "/settings";
}
render() {
let { Addcoursestypes, coursedata, modalsType, modalsTopval, loadtype,modalsBottomval,antIcon} = this.state;
return (
coursedata === undefined || coursedata.status===401? <div id="course_info_1309" className="courseHead" style={{height: '206px'}}></div>:<div id="course_info_1309" className="courseHead" style={{height: '206px'}}>
{Addcoursestypes === true ? <Addcourses
Addcoursestype={Addcoursestypes}
hideAddcoursestype={() => this.tojoinclass(2)}
/> : ""}
<Modals
modalsType={modalsType}
modalsTopval={modalsTopval}
loadtype={loadtype}
modalsBottomval={modalsBottomval}
modalCancel={this.modalCancel}
modalSave={this.ModalAction}
antIcon={antIcon}
></Modals>
<AddTeacherModal ref="addTeacherModal"
{...this.props}
isTeacher={this.state.isTeacher}
moduleName={this.state.isTeacher ? "教师" : "助教"}
addTeacherSuccess={this.addTeacherSuccess}
></AddTeacherModal>
<AddStudentModal ref="addStudentModal"
{...this.props}
moduleName="学生"
addStudentSuccess={this.addStudentSuccess}
></AddStudentModal>
<div className="educontent clearfix educontentTop">
<div className="color-white clearfix mb10">
{
coursedata===undefined || coursedata.status===401 || coursedata.status===407?"":
<Tooltip placement="bottom" title={coursedata&&coursedata.name.length<38?"":coursedata.name}>
<span className="font-24 fl bannername">{coursedata.name}</span>
</Tooltip>
}
{/*访
公开公开课堂非课堂成员可以访问*/}
<span className={"TabsWarp"}>
<CoursesListType
typelist={coursedata.course_end === true ? ["已结束"] : coursedata.is_public === true ? ["公开"] : ["私有"]}
typesylename={"mt10"} tipval={coursedata.is_public === true?"":"私有课堂,非课堂成员不能访问"}/>
</span>
</div>
<div className="clearfix ">
<div className="fl fl mr40 mb20">
<a href={"/users/" + coursedata.teacher_login} className="fl">
<img alt="头像" className="radius fl mt3 bannerimgname"
src={getImageUrl(`images/` + coursedata.teacher_img)}/>
</a>
<div className="fl mt13">
<p className="color-white">
<a href={"/users/" + coursedata.teacher_login}
className="color-white bannnerusername">{coursedata.teacher_name}</a>
</p>
</div>
<div className="fl mt13">
<p className="color-white bannnerusernames">{coursedata.teacher_school}</p>
</div>
</div>
<div>
{coursedata.switch_to_student === true ?
<Tooltip placement="bottom" title={"切换至学生可进行提交作品、答题等操作"}>
<a className="fr user_default_btn user_blue_btn mr20 font-18"
onClick={()=>this.switchidentity(1)}
> 切换为学生 </a>
</Tooltip>
:""}
{coursedata.switch_to_teacher === true ?
<Tooltip placement="bottom" title={"由学生身份切换至教师"}>
<a className="fr user_default_btn user_blue_btn mr20 font-18"
onClick={()=>this.switchidentity(2)}
> 切换为老师 </a>
</Tooltip>:""}
{coursedata.switch_to_assistant === true ?
<Tooltip placement="bottom" title={"由学生身份切换至助教"}>
<a className="fr user_default_btn user_blue_btn mr20 font-18"
onClick={()=>this.switchidentity(3)}
> 切换为助教 </a>
</Tooltip>:""}
{coursedata.course_identity === 6&&coursedata.educoder_teacher===false?
<a className="fr user_default_btn task-btn-orange font-18 mr20" id="shixun_operation"
onClick={() => this.tojoinclass(1)}>加入课堂</a>: ""}
{coursedata.course_identity === 6&&coursedata.educoder_teacher===true?
<a className="fr user_default_btn task-btn-orange font-18 mr20" id="shixun_operation"
onClick={() => this.tojoinclass(1)}>加入课堂</a>: ""}
{coursedata.course_identity === 6&&coursedata.educoder_teacher===true?
<a className="fr user_default_btn user_blue_btn mr20 font-18" onClick={() => this.ActionPoll(5)}> 复制课堂 </a>: ""}
{this.props.isStudent()?<a className="fr user_default_btn user_blue_btn mr20 font-18"
onClick={() => this.exitclass()}
> 退出课堂 </a>:""}
</div>
<div className="clearfix clearfixborder">
<ul className="fl color-grey-eb pathInfo pathInfobox mt10">
<li className={"mt7"}>
<Link to={"/courses/"+this.props.match.params.coursesId+"/teachers"}>
<span className="color-grey-c fl font-16">教师</span>
<span
className="color-white fl font-16 bannerurli">{coursedata.teacher_count}</span>
</Link>
</li>
<li className={"mt7"}>
<Link to={"/courses/"+this.props.match.params.coursesId+"/students"}>
<span className="color-grey-c fl font-16">学生</span>
<span
className={coursedata.credit===null?"color-white fl font-16":"color-white fl font-16 bannerurli"}>{coursedata.student_count}</span>
</Link>
</li>
{/*<li className={"mt7"}>*/}
{/*<a>*/}
{/*<span className="color-grey-c fl font-16">分班</span>*/}
{/*<span className="color-white fl font-16 bannerurli">{coursedata.course_group_count}</span>*/}
{/*</a>*/}
{/*</li>*/}
{coursedata.credit===null?"":<li className={"mt7"}>
<a>
<span className="color-grey-c fl font-16 mr10">学分</span>
<span className="color-white fl font-16 "
>{coursedata.credit}</span>
</a>
</li>}
{/*{coursedata.course_end===true? <li className={"mt7"}>*/}
{/*<span className="color-grey-c fl font-16">已结束</span>*/}
{/*</li>:<li className={"mt7"}>*/}
{/*<span className="color-grey-c fl font-16"> 结束</span>*/}
{/*<span className="color-white fl font-16"*/}
{/*style={{*/}
{/*marginLeft:coursedata.deadline===null?"":'8px'*/}
{/*}}*/}
{/*>{coursedata.deadline===null?"--":coursedata.deadline}</span>*/}
{/*</li>}*/}
</ul>
{this.props.isAdmin()? <ul className="fr color-grey-eb pathInfo pathInfobox mt10"
style={{
position: "relative"
}}
>
<li className={"mt7 mr10im"}>
<a onClick={()=>this.addTeacher(true)}>
<span className="color-white fl font-16 bannerurli width100f">添加老师</span>
</a>
</li>
<li className={"mt7 mr10im"}>
<a onClick={()=>this.addTeacher(false)}>
<span className="color-white fl font-16 bannerurli width100f">添加助教</span>
</a>
</li>
<li className={"mt7 mr10im"}>
<a onClick={()=>this.addStudent()}>
<span className="color-white fl font-16 bannerurli width100f">添加学生</span>
</a>
</li>
<li className={"mt7 mr10im ml10"} style={{overflow:"hidden"}}>
<a>
<span className="color-grey-c fl font-16">邀请码</span>
<span
className={coursedata.code_halt === true? "color-white fl font-16 bannerurli width75f" : "color-white fl font-16 bannerurli width107f marleftf10 color-orange-tip"}>
{coursedata.code_halt === true? "已停用" : coursedata.invite_code}
{coursedata.code_halt === true ? "" :
<Tooltip placement="bottom" title={
<pre>
成员可以通过邀请码主动加入课堂<br/>
点击立刻复制邀请码
</pre>
}>
<i className="iconfont icon-fuzhi color-white font-14 ml10"
onClick={() => {
jsCopy()
}}></i>
</Tooltip>
}
<input id="copy_invite_code" value={coursedata.invite_code}/>
</span>
</a>
</li>
<li className={"mt7 ml10 mr0 "}>
<style>
{
`
.defaults{cursor:default}
`
}
</style>
<Popover placement="bottom" content={
<ul className="sandianbox" style={{
display: 'block',
right: "-113px",
top: "20px"
}}>
{coursedata.is_public === true?coursedata.course_identity <3?
<div className={"defaults"} onClick={() => this.ActionPoll(2)}>设为私有</div>: "" : ""}
{coursedata.is_public === false?coursedata.course_identity <3?
<div className={"defaults"} onClick={() => this.ActionPoll(3)}>设为公开</div> : "": ""}
{coursedata.course_identity <3? <div className={"defaults"} onClick={() => this.ActionPoll(4)}>
{coursedata.code_halt === true ?"启用邀请码":"停用邀请码"}
</div>:""}
<div className={"defaults"} onClick={this.postsettings}>设置</div>
<div className={"defaults"} onClick={() => this.ActionPoll(5)}>复制
</div>
{coursedata.is_admin===true?coursedata.course_identity <3?<div className={"defaults"} onClick={() => this.ActionPoll(1)}>删除</div>
:"":""}
</ul>
} trigger="hover">
<i className="iconfont icon-weibiaoti12 color-white font-14 relative"></i>
</Popover>
</li>
</ul>:""}
</div>
</div>
</div>
</div>
)
}
}
export default CoursesBanner;
// let id=this.props.match.params.coursesId;
//
// let url="/courses/"+id+"/top_banner.json"
// axios.get(url).then((result)=>{
// if(result.status===200){
// let data=result.data;
// this.setState({
// coursebannerlist:result.data,
// name: result.data.name,
// teacher_name: result.data.teacher_name,
// teacher_login: result.data.teacher_login,
// teacher_img: result.data.teacher_img,
// teacher_school: result.data.teacher_school,
// teacher_count: result.data.teacher_count,
// student_count: result.data.student_count,
// course_group_count: result.data.course_group_count,
// credit: result.data.credit,
// course_end: result.data.course_end,
// deadline: result.data.deadline,
// is_teacher: result.data.is_teacher,
// is_student: result.data.is_student,
// is_admin: result.data.is_admin,
// is_public: result.data.is_public,
// code_halt: result.data.code_halt,
// invite_code: result.data.invite_code,
// switch_to_student: result.data.switch_to_student,
// switch_to_teacher: result.data.switch_to_teacher,
// join_course: result.data.join_course,
// copy_course: result.data.copy_course,
// })
// }
// coursebannerlist:undefined,
// name: undefined,
// teacher_name: undefined,
// teacher_login: undefined,
// teacher_img: undefined,
// teacher_school: undefined,
// teacher_count: undefined,
// student_count: undefined,
// course_group_count: undefined,
// credit: undefined,
// course_end: undefined,
// deadline: undefined,
// is_teacher: undefined,
// is_student: undefined,
// is_admin: undefined,
// is_public: undefined,
// code_halt: undefined,
// invite_code:undefined,
// switch_to_student: undefined,
// switch_to_teacher: undefined,
// join_course: undefined,
// copy_course: undefined,
// }).catch((error)=>{
// console.log(error);
// })

@ -1,355 +0,0 @@
import React,{Component} from "React";
import { Form, Select, Input, Button,Checkbox,Upload,Icon,message,Modal} from "antd";
import {Link} from 'react-router-dom';
import TPMMDEditor from '../../../tpm/challengesnew/TPMMDEditor';
import { WordsBtn,getUrl} from 'educoder';
import axios from 'axios';
import Modals from '../../../modals/Modals';
import '../../css/Courses.css';
const { Option} = Select;
const CheckboxGroup = Checkbox.Group;
const confirm = Modal.confirm;
let GraduationTasksnewtype=true;
class GraduationTasksnew extends Component{
constructor(props){
super(props)
this.state={
coursename:"",
coursesearch:"",
title_num:60,
title_value:"",
fileList: [],
contents: [{val:"",id:1}],
type:true
}
}
componentDidMount(){
// const query =this.props.location.search;
//
// const type = query.split('&');
// let name = type[1].split("name=")
// name = String(name).split(",")
// name = decodeURI(name[1])
//
// this.setState({
// coursename:name,
// coursesearch:this.props.location.search
// })
}
scrollToAnchors=(anchorName)=>{
this.setState({
anchor:anchorName
})
}
handleSubmit=(e) => {
let {fileList}=this.state;
let listid=[]
for(var list of fileList){
listid.push(list.response.id)
}
e.preventDefault();
if( GraduationTasksnewtype===true){
this.props.form.validateFields((err, values) => {
if (!err) {
if(values.tasktype===undefined){
this.scrollToAnchors("tasktypes");
return
}
if(values.name===undefined){
this.scrollToAnchors("nametypes");
return
}
if(values.description===undefined){
this.scrollToAnchors("descriptiontypes");
return
}else if(values.description.length>5000){
this.scrollToAnchors("descriptiontypes");
return
}
console.log('Received values of form: ', values);
console.log(fileList);
const course_id=this.props.match.params.coursesId;
let url="/courses/"+course_id+"/graduation_tasks.json"
axios.post(url, {
task_type:parseInt(values.tasktype),
name:values.name,
description:values.description,
attachment_ids:listid,
}
).then((response) => {
if(response.status===200) {
GraduationTasksnewtype=false;
// this.goback();
this.props.history.push("/courses/"+this.props.match.params.coursesId+"/graduation_tasks/"+this.props.match.params.category_id+"/"+response.data.task_id+"/setting");
}
}).catch((error) => {
console.log(error)
})
}
});
}
}
goback=()=>{
let courseId=this.props.match.params.coursesId;
let category_id=this.props.match.params.category_id;
window.location.href="/courses/"+courseId+"/graduation_tasks/"+category_id;
}
// 输入title
changeTitle=(e)=>{
this.setState({
title_num:60-parseInt(e.target.value.length),
title_value:e.target.value
})
}
// 附件相关 START
handleChange = (info) => {
let fileList = info.fileList;
// for(var list of fileList ){
// console.log(list)
// }
this.setState({ fileList });
}
onAttachmentRemove = (file) => {
// confirm({
// title: '确定要删除这个附件吗?',
// okText: '确定',
// cancelText: '取消',
// // content: 'Some descriptions',
// onOk: () => {
// this.deleteAttachment(file)
// },
// onCancel() {
// console.log('Cancel');
// },
// });
// return false;
this.setState({
Modalstype:true,
Modalstopval:'确定要删除这个附件吗?',
ModalSave: ()=>this.deleteAttachment(file),
ModalCancel:this.cancelAttachment
})
return false;
}
cancelAttachment=()=>{
this.setState({
Modalstype:false,
Modalstopval:'确定要删除这个附件吗?',
ModalSave:"",
ModalCancel:""
})
}
deleteAttachment = (file) => {
const url = `/attachments/${file.response ? file.response.id : file.uid}.json`
axios.delete(url, {
})
.then((response) => {
if (response.data) {
const { status } = response.data;
if (status == 0) {
console.log('--- success')
this.setState((state) => {
const index = state.fileList.indexOf(file);
const newFileList = state.fileList.slice();
newFileList.splice(index, 1);
return {
fileList: newFileList,
};
});
}
}
})
.catch(function (error) {
console.log(error);
});
}
//滚动
ifHasAnchorJustScorll() {
// let anchor = this.getURLStuff("anchor");
let anchor = this.state.anchor;
console.log("anchor ", anchor);
// 对应id的话, 滚动到相应位置
if (!!anchor) {
let anchorElement = document.getElementById(anchor);
if (anchorElement) {
window.scrollTo(0, anchorElement.offsetTop - window.innerHeight / 2);
}
}
// 没有的话,滚动到头部
else {
document.body.scrollTop = document.documentElement.scrollTop = 0;
}
}
render(){
const { getFieldDecorator } = this.props.form;
let {coursename,coursesearch,title_num,title_value,pageType,fileList,contents,type,
Modalstype,Modalstopval,ModalCancel,ModalSave} =this.state;
let {coursedata}=this.props;
let courseId=this.props.match.params.coursesId;
let position=this.props.match.params.position;
let category_id=this.props.match.params.category_id;
const uploadProps = {
width: 600,
fileList,
multiple: true,
// https://github.com/ant-design/ant-design/issues/15505
// showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。
// showUploadList: false,
action: `${getUrl()}/api/attachments.json`,
onChange: this.handleChange,
onRemove: this.onAttachmentRemove,
beforeUpload: (file) => {
console.log('beforeUpload', file.name);
const isLt150M = file.size / 1024 / 1024 < 150;
if (!isLt150M) {
message.error('文件大小必须小于150MB!');
}
return isLt150M;
},
};
this.ifHasAnchorJustScorll();
// console.log(this.props.current_user.course_name)
return(
<React.Fragment>
<div>
{/*提示*/}
<Modals
modalsType={Modalstype}
modalsTopval={Modalstopval}
modalCancel={ModalCancel}
modalSave={ModalSave}
/>
<div className="newMain clearfix">
<div className={"educontent mb20"}>
<p className="clearfix mt10">
<WordsBtn style="grey" className="fl"> <Link to={"/courses/"+courseId+"/students"} className="color-grey-6">{this.props.current_user&&this.props.current_user.course_name}</Link></WordsBtn>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<WordsBtn style="grey" className="fl"> <Link to={"/courses/"+courseId+"/graduation_tasks/"+category_id} className="color-grey-6">毕设任务</Link></WordsBtn>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<span>{"新建"}</span>
</p>
<div style={{ width:'100%',height:'75px'}} >
<p className=" fl color-black mt25 summaryname">新建毕设任务</p>
<a className="color-grey-6 fr font-16 ml30 mt10 mr20" onClick={this.goback}>返回</a>
</div>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 12 }} onSubmit={GraduationTasksnewtype===true?this.handleSubmit:""} >
{/*内容*/}
<div className="stud-class-set bor-bottom-greyE pd20 edu-back-white">
<Form.Item label="类型">
{getFieldDecorator('tasktype', {
rules: [{ required: true, message: "请选择任务类型" }],
})(<Select className={"greyInput"}
style={{width:'20%'}}
placeholder="请选择任务类型">
<Option value="1">普通</Option>
<Option value="2">分组</Option>
</Select>)}
<input type="hidden" id='tasktypes' />
<span className={"newcoursestitle"}>选择确认后无法修改</span>
</Form.Item>
<Form.Item label="任务标题" >
{getFieldDecorator('name', {
rules: [{ required: true, message: "不能为空" }],
})(<Input placeholder="请输入任务名称最大限制60个字符" value={title_value} onInput={this.changeTitle} className="searchView searchViewAfter" style={{"width":"100%"}} maxLength="60" addonAfter={String(title_num)}/>)}
</Form.Item>
<input type="hidden" id='nametypes' />
</div>
<div className="stud-class-set pd20 coursenavbox edu-back-white">
<style>{`
.uploadBtn.ant-btn {
border: none;
color: #4CACFF;
box-shadow: none;
background: transparent;
padding: 0 6px;
}
.ant-upload-list-item:hover .ant-upload-list-item-info{
background-color:#fff;
}
.upload_1 .ant-upload-list {
width: 350px;
}
.ant-form-item{
margin-bottom:0px
}
`}</style>
<Form.Item
label="内容"
>
{getFieldDecorator('description', {
rules: [{
required: true, message: '请输入帖子内容',
}, {
max: 5000, message: '最大限制为5000个字符',
}],
})(
<TPMMDEditor ref={this.mdRef} placeholder={'请输入任务内容说明最大限制5000个字符'}
mdID={'courseMessageMD'} className="courseMessageMD"></TPMMDEditor>
)}
</Form.Item>
<input type="hidden" id='descriptiontypes' />
<Upload {...uploadProps} className="upload_1 ml5">
<Button className="uploadBtn">
<Icon type="upload" /> 上传附件
</Button>
(单个文件150M以内)
</Upload>
</div>
<Form.Item>
<div className="clearfix mt30 mb30">
<Button type="primary" htmlType="submit" className="defalutSubmitbtn fl mr20">提交</Button>
<a onClick={this.goback} className="defalutCancelbtn fl">取消</a>
</div>
</Form.Item>
</Form>
</div>
</div>
</div>
</React.Fragment>
)
}
}
const GraduationTasksnewApp = Form.create({ name: 'coursesNew' })(GraduationTasksnew);
export default GraduationTasksnewApp;

@ -1,967 +0,0 @@
import React, {Component} from "react";
import CoursesListType from '../coursesPublic/CoursesListType';
import {WordsBtn, ActionBtn} from 'educoder';
import {
Table,
Pagination,
} from "antd";
import {Link} from 'react-router-dom';
import axios from 'axios';
import moment from 'moment';
import '../css/members.css'
import '../css/busyWork.css'
import '../poll/pollStyle.css'
import {getImageUrl} from 'educoder';
import TraineetraininginformationModal from "./TraineetraininginformationModal";
import Startshixuntask from "../coursesPublic/Startshixuntask";
//GraduationTaskssetting.js
//作品列表(学生)
class Listofworksstudentone extends Component {
//unifiedsetting 统一设置
//allowreplenishment 允许补交
//completionefficiencyscore 完成效率评分占比
//level级别
//proportion 比例
constructor(props) {
super(props);
// course_group_info 老师身份显示的分班情况
//task_status 老师身份显示的提交情况
//要提交的作品状态checkedValuesine
//要提交的分班状态checkedValuesineinfo
//searchtext 输入的姓名和学号
//order 排序时间
this.state = {
jobsettingsdata: undefined,
endTime: "2018/11/10 17:10:00",
type: "day",
props: props,
data: [],
datas: [],
page: 1,
pages: 1,
limit: 20,
loadingstate: true,
order: "updated_at",
search: null,
day: 0,
hour: 0,
minute: 0,
second: 0,
userids: 0,
viewtrainingdata: {},
teacherdata: undefined,
task_status: [],
visibles: false,
course_group_info: [],
styletable: {
"display": "none"
},
student_works: [],
startbtn: false
}
//
}
componentDidMount() {
var homeworkid = this.props.match.params.homeworkid;
this.Getalistofworks(homeworkid);
let query = this.props.location.pathname;
const type = query.split('/');
this.setState({
shixuntypes: type[3]
})
}
//卸载组件取消倒计时
componentWillUnmount() {
// clearInterval(this.timer);
}
// 获取作品列表
Getalistofworks = (homeworkid) => {
// console.log("获取作品列表");
let urll = `/homework_commons/${homeworkid}/works_list.json`;
var data = {
search: "",
order: "",
b_order: "",
work_status: "",
course_group: "",
}
axios.post(urll, data).then((result) => {
if (result.status === 200) {
this.setState({
teacherdata: result.data,
task_status: result.data.task_status,
course_group_info: result.data.course_group_info,
student_works: result.data.student_works,
jobsettingsdata: result,
publish_immediately: result.data.publish_immediately,
end_immediately: result.data.end_immediately,
id: result.data.id,
})
if (result.data.student_works === undefined || result.data.student_works === null || JSON.stringify(result.data.student_works) === "[]") {
this.seacthdata();
} else {
this.seacthdatas();
}
}
}).catch((error) => {
console.log(error)
})
}
// 获取作品列表
Getalistofworkstwo = (ordervlue, checkedValuesine, checkedValuesineinfo, searchtext, page, limit) => {
// console.log("获取作品列表");
var homeworkid = this.props.match.params.homeworkid;
let urll = `/homework_commons/${homeworkid}/works_list.json`;
// console.log(homeworkid);
// search:搜索关键字
// order:排序方式更新时间update_time最终成绩work_score学号student_id
// b_order:desc倒序 asc顺序
// work_status:0:未提交, 1:按时提交, 2:延时提交,“”不限
// course_group:分班情况 [232, 231] []:不限(空数组)
var order = "asc";
if (ordervlue === "updated_at") {
order = "desc";
}
var data = {
search: "",
order: ordervlue,
b_order: order,
work_status: "",
course_group: "",
page: page,
limit: limit,
}
axios.post(urll, data).then((result) => {
if (result.status === 200) {
// console.log("学生未截至未公开的作品列表")
// console.log(JSON.stringify(result))
this.setState({
teacherdata: result.data,
task_status: result.data.task_status,
course_group_info: result.data.course_group_info,
student_works: result.data.student_works,
})
if (result.data.student_works === undefined || result.data.student_works === null || JSON.stringify(result.data.student_works) === "[]") {
this.seacthdata();
} else {
this.seacthdatas();
}
}
}).catch((error) => {
console.log(error)
this.setState({
loadingstate:false
})
})
}
TablePagination = (e) => {
// console.log(e.current);
this.setState({
page: e.current
})
}
seacthdatas = () => {
let {page, limit} = this.state;
let datalist = [];
let datalists = [];
var styletable = {"display": "none"}
// console.log("seacthdata设置数据3")
var teacherlist = undefined;
var teacherlists = undefined;
if (this.state.teacherdata !== undefined) {
// console.log("seacthdata设置数据")
// console.log(this.state.teacherdata.id )
if (this.state.teacherdata.id === undefined) {
this.setState({
data: [],
teacherlist: undefined,
loadingstate: false,
styletable: styletable,
})
} else {
console.log(this.state.teacherdata)
if (this.state.teacherdata.id !== undefined || this.state.teacherdata.id !== null || this.state.teacherdata.id !== "") {
// console.log("seacthdata设置数据1")
// console.log(this.state.teacherdata )
var timedata = moment(this.state.teacherdata.update_time).format('YYYY-MM-DD HH:mm');
datalist.push({
myid: this.state.teacherdata.id,
number: 1,
name: this.state.teacherdata.user_name,
stduynumber: this.state.teacherdata.student_id,
classroom: this.state.teacherdata.group_name,
submitstate: this.state.teacherdata.work_status === 0 ? "未提交" : this.state.teacherdata.work_status === 1 ? "按时提交" : this.state.teacherdata.work_status === 2 ? "延时提交" : "未提交",
// updatetime:this.state.teacherdata.student_works[i].update_time,
// updatetime:"",
updatetime: timedata === "Invalid date" ? "--" : timedata,
completion: this.state.teacherdata.complete_count === 4 ? "4/4" : this.state.teacherdata.complete_count === 3 ? "3/4" : this.state.teacherdata.complete_count === 2 ? "2/4" : this.state.teacherdata.complete_count === 1 ? "1/4" : this.state.teacherdata.complete_count === 0 ? "0" : 0,
levelscore: this.state.teacherdata.final_score,
efficiencyscore: this.state.teacherdata.eff_score,
finalscore: this.state.teacherdata.work_score,
operating: "查看",
})
// }
var teacherlist = { //分页
total: this.state.teacherdata.student_works.length, //数据总数量
pageSize: this.state.teacherdata.student_works.length, //一页显示几条
current: this.state.page,
}
styletable = {"display": "block",}
} else {
// console.log("seacthdata设置数据2")
teacherlist = undefined;
}
}
}
if (this.state.student_works !== undefined) {
for (var i = 0; i < this.state.student_works.length; i++) {
var timedata = moment(this.state.student_works[i].update_time).format('YYYY-MM-DD HH:mm');
datalists.push({
myid: this.state.student_works[i].id,
number: (parseInt(page) - 1) * parseInt(limit) + (i + 1),
name: this.state.student_works[i].user_name,
stduynumber: this.state.student_works[i].student_id,
classroom: this.state.student_works[i].group_name,
submitstate: this.state.student_works[i].work_status === 0 ? "未提交" : this.state.student_works[i].work_status === 1 ? "按时提交" : this.state.student_works[i].work_status === 2 ? "延时提交" : "未提交",
// updatetime:this.state.teacherdata.student_works[i].update_time,
// updatetime:"",
updatetime: timedata === "Invalid date" ? "--" : timedata,
completion: this.state.student_works[i].complete_count === 4 ? "4/4" : this.state.student_works[i].complete_count === 3 ? "3/4" : this.state.student_works[i].complete_count === 2 ? "2/4" : this.state.student_works[i].complete_count === 1 ? "1/4" : this.state.student_works[i].complete_count === 0 ? "0" : 0,
levelscore: this.state.student_works[i].final_score,
efficiencyscore: this.state.student_works[i].eff_score,
finalscore: this.state.student_works[i].work_score,
operating: "查看",
})
}
/*teacherlists = { //分页
total: this.state.student_works.length, //数据总数量
pageSize: 10, //一页显示几条
current: this.state.pages,
}*/
}
this.setState({
data: datalist,
datas: datalists,
teacherlist: teacherlist,
teacherlists: teacherlists,
loadingstate: false,
styletable: styletable,
})
}
// 设置数据
seacthdata = () => {
let datalist = [];
if (this.state.teacherdata !== undefined) {
// console.log("seacthdata设置数据")
// console.log(this.state.teacherdata.id )
if (this.state.teacherdata.id === undefined) {
this.setState({
data: [],
teacherlist: undefined,
loadingstate: false,
})
return
}
// console.log(this.state.teacherdata )
if (this.state.teacherdata.id !== undefined || this.state.teacherdata.id !== null || this.state.teacherdata.id !== "") {
// console.log("seacthdata设置数据1")
// console.log(this.state.teacherdata )
var timedata = moment(this.state.teacherdata.update_time).format('YYYY-MM-DD HH:mm');
datalist.push({
myid: this.state.teacherdata.id,
number: 1,
name: this.state.teacherdata.user_name,
stduynumber: this.state.teacherdata.student_id,
classroom: this.state.teacherdata.group_name,
submitstate: this.state.teacherdata.work_status === 0 ? "未提交" : this.state.teacherdata.work_status === 1 ? "按时提交" : this.state.teacherdata.work_status === 2 ? "延时提交" : "未提交",
// updatetime:this.state.teacherdata.student_works[i].update_time,
// updatetime:"",
updatetime: timedata === "Invalid date" ? "--" : timedata,
completion: this.state.teacherdata.complete_count === 4 ? "4/4" : this.state.teacherdata.complete_count === 3 ? "3/4" : this.state.teacherdata.complete_count === 2 ? "2/4" : this.state.teacherdata.complete_count === 1 ? "1/4" : this.state.teacherdata.complete_count === 0 ? "0" : 0,
levelscore: this.state.teacherdata.final_score,
efficiencyscore: this.state.teacherdata.eff_score,
finalscore: this.state.teacherdata.work_score,
operating: "查看",
})
// }
var teacherlist = { //分页
total: this.state.teacherdata.student_works.length, //数据总数量
pageSize: this.state.teacherdata.student_works.length, //一页显示几条
current: this.state.page,
}
} else {
// console.log("seacthdata设置数据2")
var teacherlist = undefined;
}
} else {
// console.log("seacthdata设置数据3")
var teacherlist = undefined;
}
console.log("datalistdatalist文件");
console.log(datalist);
this.setState({
data: datalist,
teacherlist: teacherlist,
loadingstate: false,
})
}
// 查看学员实训信息
Viewstudenttraininginformation = (e) => {
// console.log("Listofworksstudentone.js");
// console.log(e);
this.setState({
userids: e.myid,
})
this.viewtraining(e.myid);
}
viewtraining = (userids) => {
// console.log("viewtraining")
// console.log(userids)
// console.log(JSON.stringify(this.props.user))
var url = `/student_works/${userids}/shixun_work.json`;
axios.get(url).then((result) => {
if (result.status === 200) {
// console.log("Listofworksstudentone.js")
// console.log(JSON.stringify(result))
let datalist = [];
var game_list = result.data.game_list
for (var i = 0; i < game_list.length; i++) {
datalist.push({
number: "第" + game_list[i].position + "关",
name: moment(game_list[i].end_time).format('YYYY-MM-DD HH:mm'),
stduynumber: game_list[i].cost_time,
classroom: game_list[i].score,
complete_status: game_list[i].complete_status,
})
}
// console.log("viewtraining");
// console.log(datalist);
// console.log(JSON.stringify(datalist));
this.setState({
viewtrainingdata: result.data,
visibles: true,
game_list: datalist
})
}
}).catch((error) => {
})
}
// 关闭调分
cancelModulationModels = () => {
this.setState({visibles: false})
}
//排序
funorder = (e) => {
if (e === "updated_at") {
// 时间
// 时间排序是从小到大
this.setState({
order: "updated_at",
loadingstate: true,
})
this.Getalistofworkstwo(e, "", "", "", this.state.page, this.state.limit);
}
if (e === "work_score") {
// 成绩
//成绩排序是从大到小
this.setState({
order: "work_score",
loadingstate: true,
})
this.Getalistofworkstwo(e, "", "", "", this.state.page, this.state.limit);
}
if (e === "student_id") {
//学号
//学号排序是从大到小
this.setState({
order: "student_id",
loadingstate: true,
})
this.Getalistofworkstwo(e, "", "", "", this.state.page, this.state.limit);
}
}
Startsorting = (ordervlue, checkedValuesine, checkedValuesineinfo, searchtext, page, limit) => {
// console.log("获取作品列表Listofworksstudenttwo");
var homeworkid = this.props.match.params.homeworkid;
let urll = `/homework_commons/${homeworkid}/works_list.json`;
// console.log(homeworkid);
// search:搜索关键字
// order:排序方式更新时间update_time最终成绩work_score学号student_id
// b_order:desc倒序 asc顺序
// work_status:0:未提交, 1:按时提交, 2:延时提交,“”不限
// course_group:分班情况 [232, 231] []:不限(空数组)
var order = "asc";
if (ordervlue === "updated_at") {
order = "desc";
}
var data = {
search: "",
order: ordervlue,
b_order: order,
work_status: "",
course_group: "",
page: page,
limit: limit,
}
axios.post(urll, data).then((result) => {
if(result !== undefined){
// console.log("学生公开的作品列表")
// console.log(JSON.stringify(result))
this.setState({
teacherdata: result.data,
task_status: result.data.task_status,
course_group_info: result.data.course_group_info,
student_works: result.data.student_works,
loadingstate: false
})
this.seacthdata();
}
}).catch((error) => {
console.log(error)
this.setState({
loadingstate: false
})
})
}
TablePagination = (e) => {
// console.log(e.current);
var teacherlists = { //分页
total: this.state.student_works.length, //数据总数量
pageSize: 10, //一页显示几条
current: e.current,
}
this.setState({
page: e.current,
teacherlists: teacherlists
})
}
paginationonChanges = (pageNumber) => {
this.setState({
page: pageNumber,
loadingstate: true,
})
this.Getalistofworkstwo(this.state.order, "", "", "", pageNumber, this.state.limit);
}
render() {
let {visibles, game_list, limit, viewtrainingdata, teacherdata,page, data, jobsettingsdata,styletable, datas, order, loadingstate} = this.state;
let columns = [
{
title: '序号',
dataIndex: 'number',
key: 'number',
align: "center",
width:'96px',
render: (text, record) => (
<span>
<a style={{
"color": '#07111B',
"text-align": "center"
}}>{record.number === undefined ? "--" : record.number === "" ? "--" : record.number}</a>
</span>
),
},
{
title: '姓名',
dataIndex: 'name',
key: 'name',
align: "center",
width:'147px',
render: (text, record) => (
<span>
<a style={{
"color": '#07111B',
"text-align": "center"
}}>{record.name === undefined ? "--" : record.name === "" ? "--" : record.name === null ? "--" : record.name}</a>
</span>
),
},
{
title: '学号',
dataIndex: 'stduynumber',
key: 'stduynumber',
align: "center",
width:'200px',
render: (text, record) => (
<span>
<a style={{
"color": '#9A9A9A',
"text-align": "center"
}}>{record.stduynumber === undefined ? "--" : record.stduynumber === null ? "--" : record.stduynumber === "" ? "--" : record.stduynumber}</a>
</span>
),
},
{
title: '分班',
key: 'classroom',
dataIndex: 'classroom',
align: "center",
render: (text, record) => (
<span>
<a style={{
"color": '#9A9A9A',
"text-align": "center"
}}>{record.classroom === undefined ? "--" : record.classroom === "" ? "--" : record.classroom === null ? "--" : record.classroom}</a>
</span>
),
},
{
title: '提交状态',
dataIndex: 'submitstate',
key: 'submitstate',
align: "center",
render: (text, record) => (
<span>
<a style={record.submitstate === "延时提交" ? {
"color": '#DD1717',
"text-align": "center"
} : record.submitstate === "按时提交" ? {"color": '#29BD8B', "text-align": "center"} : {
"color": '#747A7F',
"text-align": "center"
}}>{record.submitstate === undefined ? "--" : record.submitstate === "" ? "--" : record.submitstate === null ? "--" : record.submitstate}</a>
</span>
),
},
{
title: '更新时间',
dataIndex: 'updatetime',
key: 'updatetime',
align: "center",
render: (text, record) => (
<span>
<a style={{
"color": '#9A9A9A',
"text-align": "center"
}}>{record.updatetime === undefined ? "--" : record.updatetime === "" ? "--" : record.updatetime}</a>
</span>
),
},
{
title: '完成情况',
dataIndex: 'completion',
key: 'completion',
align: "center",
render: (text, record) => (
<span>
<a style={{
"color": '#9A9A9A',
"text-align": "center"
}}>{record.completion === undefined ? "--" : record.completion === "" ? "--" : record.completion}</a>
</span>
),
},
{
title: '最终成绩',
dataIndex: 'levelscore',
key: 'levelscore',
align: "center",
render: (text, record) => (
<span>
<a style={parseInt(record.levelscore) > 90 ? {
"color": '#DD1717',
"text-align": "center"
} : parseInt(record.levelscore) <= 90 ? {
"color": '#FF6800',
"text-align": "center",
"margin-left": "20px"
} : parseInt(record.levelscore) <= 60 ? {
"color": '#747A7F',
"text-align": "center"
} : {"color": '#747A7F', "text-align": "center"}}>{record.levelscore}</a>
</span>
),
},
{
title: '操作',
dataIndex: 'operating',
key: 'operating',
align: "center",
width:'96px',
render: (text, record) => (
<span>
{
record.submitstate === "未提交" ? "--"
:
<a style={{"text-align": "center"}}
className="color-blue"
onClick={() => this.Viewstudenttraininginformation(record)}>{record.operating}</a>
}
</span>
),
},
];
// console.log("teacherdatateacherdatateacherdata");
// console.log(teacherdata);
// console.log("teacherdata.work_count");
// console.log(teacherdata&&teacherdata.work_count);
return (
teacherdata === undefined || teacherdata.student_works === undefined || teacherdata.student_works === null || JSON.stringify(teacherdata.student_works) === "[]" ?
// 学生不能查看别人的
<div className="newMain clearfix ">
{visibles === true ?
<div>
<style>
{
`
body {
overflow: hidden !important;
}
`
}
</style>
<TraineetraininginformationModal
homeworkid={this.props.match.params.homeworkid}
coursesId={this.props.match.params.coursesId}
userids={this.state.userids}
viewtrainingdata={viewtrainingdata}
game_list={game_list}
visible={visibles}
Cancel={() => this.cancelModulationModels()}
/>
</div>
: ""
}
<div className={"educontent mb20"}>
<div className="educontent mb30">
<p className="clearfix mb20 mt10">
<ActionBtn className=" btn colorgrey fl hovercolorblue "
to={`/courses/${this.props.match.params.coursesId}/students`}>{jobsettingsdata === undefined ? "" : jobsettingsdata.data.course_name}</ActionBtn>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<ActionBtn
className=" btn colorgrey fl hovercolorblue "
to={`/courses/${this.props.match.params.coursesId}/${this.state.shixuntypes}/${jobsettingsdata === undefined ? "" : jobsettingsdata.data.category.category_id===undefined?"" :jobsettingsdata.data.category.category_id}`}>{jobsettingsdata === undefined ? "" : jobsettingsdata.data.category.category_name}</ActionBtn>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<WordsBtn className="fl">作业详情</WordsBtn>
</p>
</div>
<div className="educontent mb30">
<p className=" fl color-black summaryname">
{teacherdata === undefined ? "" : teacherdata.homework_name}
</p>
<CoursesListType
typelist={teacherdata === undefined ? [""] : teacherdata.homework_status}
/>
<a className="color-grey-9 fr font-16 summaryname ml20 mr20"
href={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${jobsettingsdata === undefined ? "" :jobsettingsdata.data.category.category_id}`}>返回</a>
<p className="color-grey-9 fr font-16"></p>
</div>
<div className="edu-back-white">
<div className="stud-class-set bor-bottom-greyE ">
<div className=" clearfix edu-back-white poll_list">
<Link className="active"
to={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${this.state.props.match.params.homeworkid}/openlist`}>作品列表</Link>
<Link
to={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${this.state.props.match.params.homeworkid}/questions`}>作业问答</Link>
<Link
to={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${this.state.props.match.params.homeworkid}/settings`}
>设置</Link>
<Link className="fr color-blue font-16" target={"_blank"}
to={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${teacherdata === undefined ? "" : teacherdata.id}/shixun_work_report`}>
查看实训报告
</Link>
{/*<a className="fr color-blue font-16">查看实训报告</a>*/}
{
teacherdata === undefined ? ""
: teacherdata.commit_des === null || teacherdata.commit_des === undefined ? "" :
<a className="fr color-blue font-16"
href={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${teacherdata === undefined ? "" : teacherdata.id}/commitsummary/${this.state.props.match.params.homeworkid}`}>{teacherdata.commit_des}</a>
}
{teacherdata === undefined ? "" : <Startshixuntask
{...this.props}
data={teacherdata}
/>}
</div>
</div>
{JSON.stringify(data) !== "[]" ?
<div>
<div id="graduation_work_list"
style={{
"padding": '0px 20px 10px 20px',
"margin-top": "20px",
"margin-bottom": "10px"
}}>
<div className="clearfix">
<span className="fl color-grey-6 font-12"><span
className="color-orange-tip">{teacherdata === undefined ? "" : teacherdata.commit_count === undefined ? "" : teacherdata.commit_count}</span><span
className="ml10">{teacherdata === undefined ? "" : teacherdata.uncommit_count}</span><span></span>
{teacherdata === undefined ? "" : teacherdata.left_time === undefined ? "" :teacherdata.left_time === null ? "" :
<span className="ml20">{teacherdata.left_time.status}</span>
}
{teacherdata === undefined ? "0" : teacherdata.left_time === undefined ? "0" : teacherdata.left_time === null ? "0" :
<span className="ml20" style={{"color": '#FF6800'}}>{teacherdata.left_time.time}</span>
}
</span>
</div>
</div>
<div className={"justify break_full_word new_li edu-back-white"}
style={{minHeight: "480px"}}>
<style>{`
.ant-spin-nested-loading > div > .ant-spin .ant-spin-dot {
top: 72%;}
}
`}</style>
<div className="edu-table edu-back-white ">
{data === undefined ? "" : <Table
dataSource={data}
columns={columns}
pagination={false}
loading={false}
/>}
</div>
</div>
</div>
:
<div id="forum_list" className="forum_table">
<div className="mh650 edu-back-white">
<div className="edu-tab-con-box clearfix edu-txt-center">
<img className="edu-nodata-img mb20"
src={getImageUrl("images/educoder/nodata.png")}/>
<p className="edu-nodata-p mb30">没有数据可以显示</p>
</div>
</div>
</div>
}
</div>
</div>
</div>
:
// 学生能查看别人的
<div className="newMain clearfix ">
{visibles === true ?
<TraineetraininginformationModal
homeworkid={this.props.match.params.homeworkid}
coursesId={this.props.match.params.coursesId}
userids={this.state.userids}
viewtrainingdata={viewtrainingdata}
game_list={game_list}
visible={visibles}
Cancel={() => this.cancelModulationModels()}
/> : ""
}
<div className={"educontent mb20"}>
<div className="educontent mb30">
<p className="clearfix mb20 mt10">
<ActionBtn className=" fl "
to={`/courses/${this.props.match.params.coursesId}`}>{jobsettingsdata === undefined ? "" : jobsettingsdata.data.course_name}</ActionBtn>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<ActionBtn
className=" fl "
to={`/courses/${this.props.match.params.coursesId}/${this.state.shixuntypes}/${jobsettingsdata === undefined ? "" : jobsettingsdata.data.category.category_id}`}>{jobsettingsdata === undefined ? "" : jobsettingsdata.data.category.category_name}</ActionBtn>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<WordsBtn className="fl">作业详情</WordsBtn>
</p>
</div>
<div className="educontent mb30">
<p className=" fl color-black summaryname">
{jobsettingsdata === undefined ? "" : jobsettingsdata.data.homework_name}
</p>
<CoursesListType
typelist={jobsettingsdata === undefined ? [""] : jobsettingsdata.data.homework_status}
/>
<p className="color-grey-6 fr font-16 summaryname ml20"
onClick={() => this.props.history.goBack()}>返回</p>
<p className="color-grey-6 fr font-16"></p>
</div>
<div className="edu-back-white">
<div className="stud-class-set bor-bottom-greyE ">
<div className=" clearfix edu-back-white poll_list">
<Link className="active"
to={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${this.state.props.match.params.homeworkid}/openlist`}>作品列表</Link>
<Link
to={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${this.state.props.match.params.homeworkid}/questions`}>作业问答</Link>
<Link
to={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${this.state.props.match.params.homeworkid}/settings`}
>设置</Link>
<Link className="fr color-blue font-16" target={"_blank"}
to={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${this.state.props.match.params.homeworkid}/shixun_work_report`}>
查看实训报告
</Link>
{
teacherdata === undefined ? ""
: teacherdata.commit_des === null || teacherdata.commit_des === undefined ? "" :
<a className="fr color-blue font-16"
href={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${teacherdata === undefined ? "" : teacherdata.id}/commitsummary/${this.state.props.match.params.homeworkid}`}>{teacherdata.commit_des}</a>
}
{teacherdata === undefined ? "" : <Startshixuntask
{...this.props}
data={teacherdata}
/>}
</div>
</div>
{/*<div id="graduation_work_list" style={{padding: '0px 40px 10px 40px'}}>*/}
{/* <div className="clearfix">*/}
{/* <span className="fl color-grey-6 font-12"><span className="color-orange-tip">89</span>已交<span*/}
{/* className="ml10">9000</span><span>未交</span> <span className="ml20">剩余提交时间:</span><span*/}
{/* className="ml20">{this.state.day}天 {this.state.hour}:{this.state.minute}:{this.state.second}</span></span>*/}
{/* </div>*/}
{/*</div>*/}
<div className="edu-table edu-back-white ">
{data === undefined ? "" : <Table
style={styletable}
dataSource={data}
columns={columns}
pagination={false}
loading={false}
showHeader={false}
scroll={{y: 240}}
/>}
</div>
{JSON.stringify(datas) !== "[]" ?
<div>
<div id="graduation_work_list" style={{
"padding": '0px 20px 10px 20px',
"margin-top": "20px",
"margin-bottom": "10px"
}}>
<div className="clearfix">
<span className="fl color-grey-6 font-12"><span
className="color-orange-tip">{teacherdata === undefined ? "" : teacherdata.commit_count === undefined ? "" : teacherdata.commit_count}</span><span
className="ml10">{teacherdata === undefined ? "" : teacherdata.uncommit_count}</span><span></span>
{teacherdata === undefined ? "" : teacherdata.left_time === undefined ? "" : teacherdata.left_time === null ? "" :<span className="ml20">{teacherdata.left_time.status}</span>}
{teacherdata === undefined ? "0" : teacherdata.left_time === undefined ? "0" :teacherdata.left_time === null ? "0" :<span className="ml20" style={{"color": '#FF6800'}}>{teacherdata.left_time.time}</span> }
</span>
<div className="fr color-grey-6 edu-menu-panel">
<ul>
<li className="edu-position edu-position-hidebox">
<a className="font-12 color-grey-6">
{order === "updated_at" ? "时间" : order === "work_score" ? "成绩" : order === "student_id" ? "学号" : ""}排序</a>
<i className="iconfont icon-xiajiantou ml5 font-12 color-grey-6"></i>
<ul className="edu-position-hide undis mt10">
<li> <a onClick={(e) => this.funorder("updated_at")} data-remote="true" className="color-grey-6 font-12" style={{"text-align": "center "}}>更新时间</a></li>
<li> <a onClick={(e) => this.funorder("work_score")} data-remote="true" className="color-grey-6 font-12" style={{"text-align": "center "}}>最终成绩</a></li>
<li> <a onClick={(e) => this.funorder("student_id")} data-remote="true" className="color-grey-6 font-12" style={{"text-align": "center "}}>学生学号</a></li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<div className={"justify break_full_word new_li edu-back-white"}
style={{minHeight: "480px"}}>
<style>{`
.ant-spin-nested-loading > div > .ant-spin .ant-spin-dot {
top: 72%;}
}
`}</style>
<div className="edu-table edu-back-white ">
{datas === undefined ? "" : <Table
dataSource={datas}
columns={columns}
pagination={false}
loading={loadingstate}
onChange={this.TablePagination}
/>}
</div>
{
teacherdata && teacherdata.work_count && teacherdata.work_count > limit ?
<div className="edu-txt-center mt30 mb20">
<Pagination showQuickJumper current={page}
onChange={this.paginationonChanges} pageSize={limit}
total={teacherdata.work_count}></Pagination>
</div>
: ""
}
</div>
</div>
:
<div id="forum_list" className="forum_table">
<div className="mh650 edu-back-white">
<div className="edu-tab-con-box clearfix edu-txt-center">
<img className="edu-nodata-img mb20"
src={getImageUrl("images/educoder/nodata.png")}/>
<p className="edu-nodata-p mb30">没有数据可以显示</p>
</div>
</div>
</div>
}
{/*///*/}
</div>
</div>
</div>
)
}
}
export default Listofworksstudentone;

@ -1,272 +0,0 @@
import React,{ Component } from "react";
import { Modal,Checkbox,notification} from "antd";
import axios from 'axios';
class ShixunWorkModal extends Component{
constructor(props){
super(props);
this.state={
course_groups:undefined,
limit:10,
page:1,
group_ids:undefined,
group_list:undefined
}
}
componentDidMount() {
let url="/homework_commons/"+this.props.match.params.homeworkid+"/group_list.json";
axios.get(url,{params:{
limit:10,
page:1,
}
}).then((response) => {
if(response.data.group_list===undefined){
this.setState({
course_groups:response.data,
group_list:undefined
})
}else{
this.setState({
course_groups:response.data,
group_list:response.data.group_list
})
}
}).catch((error) => {
console.log(error)
});
}
//勾选实训
shixunhomeworkedit=(checkedValues)=>{
let{group_list}=this.state;
if(checkedValues.length===group_list.length){
this.setState({
onChangetype:true,
group_ids:checkedValues
})
}else{
this.setState({
group_ids:checkedValues,
onChangetype:false
})
}
}
contentViewScroll=(e)=>{
//滑动到底判断
if(e.currentTarget.scrollHeight-e.currentTarget.scrollTop===e.currentTarget.clientHeight){
let {page,limit,group_list}=this.state;
let newpage=page+1;
let newgroup_list=group_list;
let url="/homework_commons/"+this.props.match.params.homeworkid+"/group_list.json";
axios.get(url,{params:{
limit:limit,
page:newpage,
}
}).then((response) => {
response.data. course_groups.group_list&&response.data.group_list.map((item,key)=>{
newgroup_list.push(item)
})
this.setState({
course_groups:response.data,
group_list:newgroup_list,
page:newpage
})
}).catch((error) => {
console.log(error)
});
}
}
onChange=(e)=>{
let{group_list}=this.state;
let {data}=this.props;
if(e.target.checked===true){
if(data&&data.length===0){
let id=[]
group_list.forEach((item,key)=>{
id.push(item.id)
})
this.setState({
group_ids:id,
onChangetype:e.target.checked
})
}else{
let id=[]
group_list.forEach((item,key)=>{
id.push(item.id)
})
this.setState({
group_ids:id,
onChangetype:e.target.checked
})
}
}else{
this.setState({
group_ids:[],
onChangetype:e.target.checked
})
}
}
isSave=()=>{
let{group_ids}=this.state;
let url="/homework_commons/"+this.props.match.params.homeworkid+"/homework_code_repeat.json";
axios.post(url, {
group_ids: group_ids,
})
.then((response) => {
if (response.data.status === 0) {
this.props.updatas()
this.props.issCancel()
notification.open({
message:"提示",
description: response.data.message
});
console.log(this.props)
}else if(response.data.status === -1){
notification.open({
message:"提示",
description: response.data.message
});
}else if(response.data.status === -2){
notification.open({
message:"提示",
description: response.data.message
});
}else if(response.data.status === -3){
notification.open({
message:"提示",
description: response.data.message
});
}else if(response.data.status === -4){
notification.open({
message:"提示",
description: response.data.message
});
}
})
.catch(function (error) {
console.log(error);
});
}
issCancel=()=>{
this.props.issCancel()
}
render(){
let {course_groups,group_ids,onChangetype,group_list}=this.state;
// let {data}=this.props;
// console.log(group_list)
// console.log(course_groups)
return(
<div>
<Modal
keyboard={false}
className={"HomeworkModal"}
title={this.props.modalname}
visible={this.props.visible}
closable={false}
footer={null}
destroyOnClose={true}
>
<div className="task-popup-content">
<style>{`
.greybackHead{
padding:0px 30px;
}
.fontlefts{text-align: left;}
`}</style>
<ul className="clearfix edu-txt-center">
<li className="fl paddingleft22 fontlefts" style={{width:'150px'}}>分班名称</li>
<li className="fl edu-txt-left" style={{width:'150px'}}>有效作品数</li>
<li className="fl" style={{width:'100px'}}>上次查重时间</li>
</ul>
{course_groups===undefined?"":
<ul className="upload_select_box fl clearfix mt10 mb10" tyle={{"overflow-y":"auto"}}id="search_not_members_list"
onScroll={this.contentViewScroll}
>
<Checkbox.Group style={{ width: '100%' }} onChange={this.shixunhomeworkedit} value={group_ids}>
{
group_list===undefined?
<div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE">
<li className="fl" style={{width: '100px'}}>
<Checkbox
className="fl task-hide edu-txt-left"
name="shixun_homework[]"
value={course_groups.ungroup_list.id}
>
<label style={{"textAlign": "left", "color": "#05101A"}}
className="task-hide color-grey-name" title="frerere">{course_groups.ungroup_list.name}</label>
</Checkbox>
</li>
<li className="fl" style={{width: '150px'}}>
{course_groups.ungroup_list.works_count}
</li>
<li className="fl" style={{width: '160px'}}>
{course_groups.ungroup_list.last_review_time}
</li>
</div>
:
group_list&&group_list.map((item,key)=>{
return(
<div className="clearfix edu-txt-center lineh-40 bor-bottom-greyE" key={key}>
<li className="fl" style={{width: '100px'}}>
<Checkbox
className="fl task-hide edu-txt-left"
name="shixun_homework[]"
value={item.id}
>
<label style={{"textAlign": "left", "color": "#05101A"}}
className="task-hide color-grey-name" title="frerere">{item.name}</label>
</Checkbox>
</li>
<li className="fl" style={{width: '150px'}}>
{item.works_count}
</li>
<li className="fl" style={{width: '160px'}}>
{item.last_review_time}
</li>
</div>
)
})
}
</Checkbox.Group>
</ul>
}
<div className={"clearfix"}>
<Checkbox checked={onChangetype} onChange={this.onChange} className={"ml10"}>{onChangetype===true?"清除":"全选"}</Checkbox>
</div>
<div className="clearfix mt30 edu-txt-center mb10">
<a className="task-btn color-white mr30" onClick={this.issCancel}>取消</a>
<a className="task-btn task-btn-orange" onClick={this.isSave}>确认</a>
</div>
</div>
</Modal>
</div>
)
}
}
export default ShixunWorkModal;

@ -1,195 +0,0 @@
import React, {Component} from "react";
import axios from 'axios';
import moment from 'moment';
import {Link} from 'react-router-dom';
import 'moment/locale/zh-cn';
import delay from '../../../images/delay.png'
import invalid from '../../../images/invalid.png'
import {
Form,
Select,
Input,
Button,
Checkbox,
Upload,
Icon,
message,
Modal,
Table,
Divider,
InputNumber,
Tag,
DatePicker,
Radio,
Tooltip
} from "antd";
import '../css/members.css'
import "../common/formCommon.css"
import '../css/Courses.css'
import './style.css'
import ShixunModal from "../coursesPublic/ShixunModal";
class TraineetraininginformationModal extends Component {
constructor(props) {
super(props);
this.setState({
props: this.props,
userids: this.props.userids,
game_list:this.props.game_list,
})
// console.log("TraineetraininginformationModal")
// console.log(JSON.stringify(this.props))
}
Cancel = () => {
this.props.Cancel()
}
componentDidMount() {
// this.seacthdata();
}
// 设置数据
// seacthdata = () => {
//
// console.log(datalist)
// }
render() {
let columns = [
{
title: '关卡',
dataIndex: 'number',
key: 'number',
width: 150,
align: "center",
render: (text, record) => (
<span >
<a style={{"color":'#07111B', "text-align": "center"}}>{record.number}</a>
</span>
),
},
{
title: '完成时间',
dataIndex: 'name',
key: 'name',
width: 150,
align: "center",
render: (text, record) => (
<span >
<a style={{"color":'#989898', "text-align": "center"}} >{record.name==='Invalid date'?"--":record.name}</a>
</span>
),
},
{
title: '',
dataIndex: 'complete_status',
key: 'complete_status',
width: 150,
align: "center",
render: (text, record) => (
<span>
{record.complete_status===2?<img src={delay}/>:record.complete_status===3?<img src={invalid}/>:""}
</span>
),
},
{
title: '耗时',
dataIndex: 'stduynumber',
key: 'stduynumber',
width: 150,
align: "center",
render: (text, record) => (
<span>
<a style={{"color":'#989898', "text-align": "center"}}>{record.stduynumber}</a>
</span>
),
},
{
title: '经验值',
key: 'classroom',
width: 150,
dataIndex: 'classroom',
align: "center",
render: (text, record) => (
<span>
<a style={{"color":'#29BD8B', "text-align": "center"}}>{record.classroom}</a>
</span>
),
}
];
return (
<div>
<Modal
keyboard={false}
className="HomeworkModal"
title={"学员实训信息"}
visible={this.props.visible}
footer={null}
onCancel={this.Cancel}
>
<div style={{width:"100%" }}className="login_register_content" >
<div style={{"width": "100%","text-align": "center"}}>
<a style={{"text-align": "center"}}>{this.props.viewtrainingdata === undefined ? "" : this.props.viewtrainingdata.shixun_name}</a>
<a className="ml20 " style={{"text-align": "center","color":'#29BD8B'}} >经验值<span style={{"color":'#29BD8B'}}> {this.props.viewtrainingdata === undefined ? "" : this.props.viewtrainingdata.shixun_score}</span></a>
{/*<Button type="primary" className="ml30" >实训报告</Button>*/}
<a className="ml30 color-blue " style={{"text-align": "center"}} target={"_blank"} href={`/courses/${this.props.coursesId}/shixun_homeworks/${this.props.viewtrainingdata.work_id}/shixun_work_report`}>
实训报告
</a>
{/*这里到时候要做判断*/}
</div>
</div>
<div className=" bor-bottom-greyE mt10"></div>
<div className="fl edu-back-white ml10 ">
<img alt="头像" className="radius mt10" height="70" id="nh_user_logo" name="avatar_image"
src={this.props.viewtrainingdata === undefined ? "" : "https://www.educoder.net/images/" + `${this.props.viewtrainingdata.image_url}`}
width="70"/>
</div>
<div className="fl edu-back-white ml20 mt10">
<li>{this.props.viewtrainingdata === undefined ? "" :this.props.viewtrainingdata.username}<span style={{"color":"#323232"}}> 通关</span><span style={{"color": '#FF6800'}}>{this.props.viewtrainingdata === undefined ? "" :this.props.viewtrainingdata.complete_count}/{this.props.viewtrainingdata === undefined ? "" :this.props.viewtrainingdata.challenges_count}</span></li>
<li><span style={{"color":"#989898"}} >完成效率</span><span style={{"color":"#4C4C4C"}}>{this.props.viewtrainingdata === undefined ? "" :this.props.viewtrainingdata.efficiency}</span></li>
<li><span style={{"color":"#989898"}}>通关时间</span> <span style={{"color":"#4C4C4C"}}>{this.props.viewtrainingdata === undefined ? "":moment(this.props.viewtrainingdata.passed_time).format('YYYY-MM-DD HH:mm')==="Invalid date"?"--":moment(this.props.viewtrainingdata.passed_time).format('YYYY-MM-DD HH:mm')}</span> </li>
</div>
<div className="fl edu-back-white ml20 mt10">
<li className="mt20"> <span style={{"color":"#989898"}}>课堂最高完成效率</span> <span style={{"color":"#4C4C4C"}}>{this.props.viewtrainingdata === undefined ? "" :this.props.viewtrainingdata.max_efficiency} </span> </li>
<li><span style={{"color":"#989898"}}>总耗时:</span> <span style={{"color":"#4C4C4C"}}> {this.props.viewtrainingdata === undefined ? "" :this.props.viewtrainingdata.total_spend_time}</span> </li>
</div>
{
this.props.game_list === undefined?"" : this.props.game_list.length<4?
<style>
{
` .ant-table-body{
overflow: hidden !important;
}`
}
</style>
:""
}
<div className={"both"}></div>
{this.props.game_list === undefined ? "" : <Table
className="mt20"
dataSource={this.props.game_list}
columns={columns}
pagination={{ //分页
total: this.props.game_list.length, //数据总数量
pageSize: this.props.game_list.length, //一页显示几条
current: 1,
}}
loading={false}
pagination={false}
onChange={this.TablePagination}
scroll={{ y: 300 }}
/>}
</Modal>
</div>
)
}
}
export default TraineetraininginformationModal;

@ -1,511 +0,0 @@
import React, {Component} from "react";
import CoursesListType from '../coursesPublic/CoursesListType';
import {WordsBtn,ActionBtn,markdownToHTML} from 'educoder';
import GraduateTopicReply from '../../courses/graduation/topics/GraduateTopicReply'
import MemoDetailMDEditortwo from '../../forums/MemoDetailMDEditortwo'
import {
Form,
Select,
Input,
Button,
Checkbox,
Upload,
Icon,
message,
Modal,
Table,
Divider,
InputNumber,
Tag,
DatePicker,
Radio,
Tooltip,
notification
} from "antd";
import {Link, Switch, Route, Redirect} from 'react-router-dom';
import axios from 'axios';
import '../css/members.css'
import "../common/formCommon.css"
import '../css/Courses.css'
import './style.css'
import 'antd/lib/pagination/style/index.css';
import './Challenges.css'
import CommonReply from "../common/comments/CommonReply";
import Homeworddescription from "../shixunHomework/Homeworddescription";
import ShixunWorkModal from './Shixunworkdetails/ShixunWorkModal';
import HomeworkModal from "../coursesPublic/HomeworkModal";
// import Homeworddescription from "../shixunHomework/Homeworddescription";
const TextArea = Input.TextArea
//GraduationTaskssetting.js
//作业问答页面
class Workquestionandanswer extends Component {
//unifiedsetting 统一设置
//allowreplenishment 允许补交
//completionefficiencyscore 完成效率评分占比
//level级别
//proportion 比例
constructor(props) {
super(props);
// this.props.form.setFieldsValue({
// radiogroup:1,
//
// });
this.state ={
// namestring:"JFinal是基于Java语言的极速web开发框架其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展、`Restful`。在拥有Java语言所有优势的同时再拥有`ruby`、`python`等动态语言的开发效率。\r\n\r\n在本实训中我们将基于JFinal框架搭建一个在线商城。我们会学习到如何合理设计`Model`来进行数据表映射和数据操作、如何设计`Controller`对请求进行合理的处理…… 通过本实训,您不仅能收获到具体框架和技术的使用经验,也能对项目架构设计等知识有所了解或巩固。\r\n\r\n<div align=\"center\">\r\n\t<img src=\"/attachments/download/170838\" />\r\n</div>\r\n\r\n本实训聚焦一个在线商城项目的核心业务逻辑实现。你将在这一过程中收获Java Web项目设计的基本思想也能得到编程能力的一次跃升。",
props: props,
starttimetype: false,
endtimetype: false,
latetimetype: false,
allowlate: 1,
latepenaltytype: false,
unifiedsetting: false,
allowreplenishment: undefined,
completionefficiencyscore: false,
proportion: undefined,
level: undefined,
ealuation: false,
latededuction: undefined,
latedeductiontwo: undefined,
Showupdateinstructions:false,
database: false,
datasheet: false,
databasetwo: undefined,
datasheettwo: undefined,
publicwork: undefined,
memo: {id: "94", user_id: 1},
polls_descriptiontest: "作业说明...",
jobdescriptiondisplay:"none",
score_open:false,
code_review:false
}
}
componentDidMount() {
var homeworkid = this.props.match.params.homeworkid;
// console.log(homeworkid)
this.Gettitleinformation(homeworkid)
let query = this.props.location.pathname;
const type = query.split('/');
this.setState({
shixuntypes:type[3]
})
}
isupdatas=()=>{
var homeworkid = this.props.match.params.homeworkid;
this.Gettitleinformation(homeworkid)
}
//获取题目信息
Gettitleinformation = (homeworkid) => {
// console.log("获取题目信息");
let url = `/homework_commons/${homeworkid}.json`;
axios.get(url).then((result) => {
if (result.status === 200) {
// console.log(url)
// console.log("设置页")
// console.log(JSON.stringify(result))
this.setState({
jobsettingsdata:result,
...result.data
})
}
}).catch((error) => {
console.log(error)
})
}
jobdescriptiondisplaybj =()=>{
this.setState({
Showupdateinstructions:true,
})
}
//统一设置
onChange = (e) => {
this.setState({
unifiedsetting: e.target.checked,
})
// console.log(e.target.checked);
}
//立即发布
homeworkstart = () => {
let homeworkid=this.props.match.params.homeworkid;
let url="/homework_commons/"+homeworkid+"/publish_groups.json";
axios.get(url).then((response) => {
if (response.status === 200) {
let starttime = this.props.getNowFormatDates(1);
let endtime = this.props.getNowFormatDates(2);
this.setState({
modalname: "立即发布",
modaltype: response.data.course_groups === null || response.data.course_groups.length === 0 ? 2 : 1,
visible: true,
Topval: "本操作只对“未发布”的对象生效",
Botvalleft: "暂不发布",
Botval: "则通过后续手动设置,定时发布",
starttime: "发布时间:" + starttime,
endtime: "截止时间:" + endtime,
Cancelname: "暂不发布",
Savesname: "立即发布",
Cancel: this.homeworkhide,
Saves: this.homeworkstartend,
course_groups: response.data.course_groups,
starttimes:starttime,
typs:"start",
})
}
}).catch((error) => {
console.log(error)
});
}
//立即截止
homeworkends = () => {
let homeworkid=this.props.match.params.homeworkid;
let url="/homework_commons/"+homeworkid+"/end_groups.json";
axios.get(url).then((response) => {
if (response.status === 200) {
this.setState({})
this.setState({
modalname: "立即截止",
modaltype: response.data.course_groups === null || response.data.course_groups.length === 0 ? 2 : 1,
visible: true,
Topval: "本操作只对“提交中”的对象生效",
Botvalleft: "暂不截止",
Botval: "则将根据已设置的截止时间,定时截止",
Cancelname: "暂不截止",
Savesname: "立即截止",
Cancel: this.homeworkhide,
Saves: this.coursetaskend,
starttime: undefined,
endtime: undefined,
course_groups: response.data.course_groups,
typs:"end",
})
}
}).catch((error) => {
console.log(error)
});
}
// 立即发布
homeworkstartend = (ds,endtime) => {
var homeworkid = this.props.match.params.homeworkid;
let {course_groupslist} = this.state;
let coursesId = this.props.match.params.coursesId;
let url = "/courses/" + coursesId + "/homework_commons/publish_homework.json";
axios.post(url, {
homework_ids: [homeworkid],
group_ids: course_groupslist,
end_time:endtime,
}).then((result) => {
if (result.status === 200) {
if (result.data.status === 0) {
notification.open({
message:"提示",
description:result.data.message
});
this.homeworkhide();
}
}
}).catch((error) => {
console.log(error);
})
}
//立即截止确定按钮
coursetaskend = () => {
var homeworkid = this.props.match.params.homeworkid;
let {course_groupslist} = this.state;
const cid = this.props.match.params.coursesId;
let url = "/courses/" + cid + "/homework_commons/end_homework.json";
axios.post(url, {
group_ids: course_groupslist,
homework_ids: [homeworkid],
})
.then((response) => {
if (response.data.status == 0) {
notification.open({
message:"提示",
description:response.data.message
});
this.homeworkhide()
}
})
.catch(function (error) {
console.log(error);
});
}
ReleaseNotes=(explanations)=>{
var homeworkid = this.props.match.params.homeworkid;
let url=`/homework_commons/${homeworkid}/update_explanation.json`;
axios.post((url), {
explanation: explanations
})
.then((result)=>{
if(result){
this.props.showNotification(`${result.data.message}`);
this.setState({
Showupdateinstructions:false
})
var homeworkid = this.props.match.params.homeworkid;
// console.log(homeworkid)
this.Gettitleinformation(homeworkid)
}
}).catch((error)=>{
console.log(error);
})
}
NOReleaseNotes=()=>{
this.setState({
Showupdateinstructions:false,
})
}
workshowmodel=()=>{
this.setState({
showmodel:true
})
}
hideshowmodel=()=>{
this.setState({
showmodel:false
})
}
homeworkhide=()=>{
this.isupdatas()
this.setState({
modalname:undefined,
modaltype:undefined,
visible:false,
Topval:undefined,
Topvalright:undefined,
Botvalleft:undefined,
Botval:undefined,
starttime:undefined,
endtime:undefined,
Cancelname:undefined,
Savesname:undefined,
Cancel:undefined,
Saves:undefined,
StudentList_value:undefined,
addname:undefined,
addnametype:false,
addnametab:undefined,
typs:undefined,
starttimes:undefined,
})
}
getcourse_groupslist=(id)=>{
this.setState({
course_groupslist:id
})
}
render() {
const dateFormat = 'YYYY-MM-DD HH:mm:ss';
let {starttimetype, endtimetype, latetimetype, allowlate, latepenaltytype, jobsettingsdata,score_open,Showupdateinstructions
, homework_id} = this.state;
const radioStyle = {
display: 'block',
height: '30px',
lineHeight: '30px',
};
const formItemLayout = {
labelCol: {span: 6},
wrapperCol: {span: 14},
};
let coursesId = this.props.match.params.coursesId;
return (
<div className="newMain clearfix ">
{this.state.showmodel===true?<ShixunWorkModal
{...this.props}
visible={this.state.showmodel}
modalname={"代码查重"}
data={[]}
issCancel={()=>this.hideshowmodel()}
updatas={()=>this.isupdatas()}
/>:""}
{/*立即发布*/}
<HomeworkModal
modaltype={this.state.modaltype}
modalname={this.state.modalname}
visible={this.state.visible}
Topval={this.state.Topval}
Topvalright={this.state.Topvalright}
Botvalleft={this.state.Botvalleft}
Botval={this.state.Botval}
starttime={this.state.starttime}
endtime={this.state.endtime}
Cancelname={this.state.Cancelname}
Savesname={this.state.Savesname}
Cancel={this.state.Cancel}
Saves={this.state.Saves}
course_groups={this.state.course_groups}
getcourse_groupslist={(id)=>this.getcourse_groupslist(id)}
starttimes={this.state.starttimes}
typs={this.state.typs}
/>
<div className={"educontent mb20"}>
<div className="educontent mb30">
<p className="clearfix mb20 mt10">
<ActionBtn className=" btn colorgrey fl hovercolorblue "
to={"/courses/"+this.props.match.params.coursesId+"/students"}>{jobsettingsdata === undefined ? "" : jobsettingsdata.data.course_name}</ActionBtn>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<ActionBtn
className=" btn colorgrey fl hovercolorblue "
to={`/courses/${this.props.match.params.coursesId}/${this.state.shixuntypes}/${jobsettingsdata===undefined?"":jobsettingsdata.data.category.category_id}`}>{jobsettingsdata === undefined ? "" : jobsettingsdata.data.category.category_name}</ActionBtn>
<span className="color-grey-9 fl ml3 mr3">&gt;</span>
<WordsBtn className="fl">作业详情</WordsBtn>
</p>
</div>
<div className="educontent mb30">
<p className=" fl color-black summaryname">
{jobsettingsdata === undefined ? "" : jobsettingsdata.data.homework_name}
</p>
<CoursesListType
typelist={jobsettingsdata === undefined ? [""] : jobsettingsdata.data.homework_status}
/>
<a className="color-grey-9 fr font-16 summaryname ml20 mr20" href={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${jobsettingsdata === undefined ? "" :jobsettingsdata.data.category.category_id}`}>返回</a>
<a className="color-grey-9 fr font-16 mr20" href={`/shixuns/${jobsettingsdata===undefined?"":jobsettingsdata.data.shixun_identifier}/challenges`} target={"_blank"}>实训详情</a>
</div>
<div className="edu-back-white">
<div className="stud-class-set bor-bottom-greyE ">
<div className=" clearfix edu-back-white poll_list">
{this.props.isAdmin() === true? <Link
to={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${this.state.props.match.params.homeworkid}/list`}>作品列表</Link>:
<Link to={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${this.state.props.match.params.homeworkid}/openlist`}>作品列表</Link>
// :<Link
// to={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${this.state.props.match.params.homeworkid}/noopenlist`}>作品列表(学生完成)</Link>
}
<Link
className="active"
to={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${this.state.props.match.params.homeworkid}/questions`}>作业问答</Link>
{this.props.isAdmin()?
this.state.code_review===false?"":<Link
// to={`/courses/${this.state.props.match.params.coursesId}/${this.state.props.match.params.homeworkid}/student_work`}
to={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${this.state.props.match.params.homeworkid}/student_work`}>
代码查重</Link>:""}
<Link
to={`/courses/${this.state.props.match.params.coursesId}/${this.state.shixuntypes}/${this.state.props.match.params.homeworkid}/settings`}
>设置</Link>
{/*<a className="fr color-blue font-16" href={`/api/homework_commons/${this.props.match.params.coursesId}/works_list.xls`}>导出成绩</a>*/}
{this.props.isAdmin() ? <a
className="fr color-blue font-16"
href={`/api/homework_commons/${this.props.match.params.coursesId}/works_list.xls`}
>导出</a> : ""}
{this.props.isAdmin() ?jobsettingsdata&&jobsettingsdata.data.end_immediately===true?
<a className="fr color-blue font-16" onClick={this.homeworkends}>立即截止</a>:"" : ""}
{this.props.isAdmin() ?jobsettingsdata&&jobsettingsdata.data.publish_immediately===true?
<a className="fr color-blue font-16" onClick={this.homeworkstart}>立即发布</a> :"": ""}
{this.props.isAdmin()?
this.state.code_review===true?
<a className="fr color-blue font-16" onClick={this.workshowmodel}>代码查重</a>
:"":""}
</div>
</div>
{jobsettingsdata === undefined|| jobsettingsdata.data.description===null? "" : <div className=" clearfix edu-back-white poll_list mt20 mr20 ">
<span>
<div className={"font-16 color-dark fl pl20 "}>
<div dangerouslySetInnerHTML={{__html: markdownToHTML(jobsettingsdata.data.description).replace(/▁/g,"▁▁▁")}}></div>
{/* /!*{}}></div>
{/* /!*{jobsettingsdata.data.description}*!/*/}
{/* <textarea>*/}
{/* {*/}
{/* this.state.namestring*/}
{/* }*/}
{/* </textarea>*/}
</div>
{/* <div className="justify break_full_word new_li markdown-body"*/}
{/* id="challenge_editorMd_description">*/}
{/* <p id="ReactMarkdown" style={{overflow:'hidden'}}>*/}
{/* /!*{ChallengesDataList === undefined ? "" :ChallengesDataList.description===null?""*!/*/}
{/* <textarea className="w200">*/}
{/* {jobsettingsdata.data.description}*/}
{/* </textarea>*/}
{/* /!*}*!/*/}
{/* </p>*/}
{/*</div>*/}
</span>
</div>}
<div className=" clearfix edu-back-white poll_list pd10">
<div className="font-16 color-green fl pl20 mt10">作业说明:</div>
{
this.props.isAdmin()&&this.props.isAdmin()===true ?
<Tooltip placement="top" title="编辑"><i
className="color-green font-18 iconfont icon-bianjidaibeijing fr pr20 " onClick={()=>this.jobdescriptiondisplaybj()} ></i></Tooltip>
:""
}
</div>
<span>
<div className="font-16 color-dark break_word flex1 pl20 " style={{"padding":"10px 10px 10px 20px"}}>
{jobsettingsdata === undefined ? "" : jobsettingsdata === null ? "" : jobsettingsdata === "null" ? "" :
<div dangerouslySetInnerHTML={{__html:markdownToHTML(jobsettingsdata.data.explanation).replace(/▁/g,"▁▁▁")}}></div>
}
</div>
</span>
</div>
{/* <style>*/}
{/* {*/}
{/* `.mockInputWrapper {*/}
{/* display: flex;*/}
{/* padding: 30px 20px 30px 20px;*/}
{/*}`*/}
{/* }*/}
{/* </style>*/}
{/* <div className="edu-back-white mb20 graduateTopic course-message"> */}
{/*<GraduateTopicReply memo={{id: graduation_topic_id, user_id: topicInfo && topicInfo.user_id}} course_id={course_id} {...this.props}></GraduateTopicReply>*/}
{/* </div> */}
{ Showupdateinstructions&& Showupdateinstructions === true?
<div >
<Homeworddescription {...this.props} ReleaseNotes={this.ReleaseNotes} NOReleaseNotes ={this.NOReleaseNotes} ></Homeworddescription>
</div>
:""
}
{ homework_id && <CommonReply
memo={{
id: homework_id,
}}
course_id={coursesId} {...this.props}
apiRouteName={'homework_commons'}
jour_type={'HomeworkCommon'}
></CommonReply>
}
</div>
</div>
)
}
}
export default Workquestionandanswer;

@ -106,6 +106,7 @@
position: absolute;
top: -30px;
left: -30px;
left: -24px;
z-index: 999;
}
@ -236,6 +237,8 @@
/* line-height: 14px; */
width: 100%;
word-wrap: break-word;
margin-bottom: 4px;
margin-top: 4px;
}
.childComment .break_word_comments{
line-height: 22px;

@ -24,6 +24,22 @@
.panel-comment_item .editor__resize {
transform: translateX(-2%);
position: absolute;
width: 120px;
height: 4px;
left: 54%;
transform: translateX(-50%);
margin-top: 2px;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
cursor: row-resize;
text-indent: 110%;
white-space: nowrap;
overflow: hidden;
text-transform: capitalize;
box-sizing: border-box;
}
/*帖子回復按鈕*/
@ -31,6 +47,11 @@ a.commentsbtn.task-btn-blue {
background: #4CACFF !important;
}
.commentTab a.commentsbtn.task-btn-blue {
margin-right: 22px;
margin-top: 6px;
}
.editormd-grid-table-row a.editormd-emoji-btn.selected {
border-bottom: 2px solid #4CACFF!important;

@ -96,7 +96,7 @@ class CommentItemMDEditor extends Component {
}
render() {
const { match, history, item, user } = this.props
const { match, history, item, user, buttonText } = this.props
if (!item) {
return <div></div>
}
@ -111,7 +111,7 @@ class CommentItemMDEditor extends Component {
</a>
</div>
<div id={`reply_message_${item.id}`} className="reply_to_message commentItemMDEditor"
style={{ paddingTop: '0px', paddingBottom: '20px', marginTop: '36px' }}
style={{ paddingTop: '0px', paddingBottom: '0px', marginTop: '36px' }}
>
<div id={`reply_message_editorMd_${item.id}`} className="editorMD" style={{ marginBottom: '0px'}}>
<textarea style={{'display': 'none'}}>
@ -119,11 +119,14 @@ class CommentItemMDEditor extends Component {
</div>
<div className="editor__resize" href="javascript:void(0);" style={{display: ''}}>调整高度</div>
<a id={`commitBtn_${item.id}`} href="javascript:void(0)"
onClick={this.onCommit} style={{ marginRight: '44px' }}
className="commentsbtn task-btn task-btn-blue fr " style={{display: ''}}>
发送
</a>
<div class="clearfix">
<a id={`commitBtn_${item.id}`} href="javascript:void(0)"
onClick={this.onCommit} style={{ marginRight: '44px' }}
className="commentsbtn task-btn task-btn-blue fr " style={{display: ''}}>
{ buttonText || '发送'}
</a>
</div>
</div>
</div>
);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,88 +1,89 @@
import React, { Component } from 'react';
import Dialog, {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from 'material-ui/Dialog';
import Button from 'material-ui/Button';
import { FormControl, FormHelperText } from 'material-ui/Form';
import Input, { InputLabel } from 'material-ui/Input';
class RewardDialog extends Component {
constructor(props) {
super(props)
this.handleGoldRewardDialogClose = this.handleGoldRewardDialogClose.bind(this)
this.state = {
// goldRewardDialogOpen: false,
goldRewardInput: '',
}
}
showGoldRewardDialog(comment, childComment) {
if (comment.admin === true) {
this.comment = comment;
this.childComment = childComment;
this.setState({goldRewardDialogOpen: true})
}
}
handleGoldRewardDialogClose() {
this.props.setRewardDialogVisible(false)
}
onGoldRewardDialogOkBtnClick() {
console.log('onGoldRewardDialogOkBtnClick')
const { goldRewardInput } = this.state;
if (!goldRewardInput || goldRewardInput === '0' || goldRewardInput.indexOf('-') !== -1) {
this.setState({ goldRewardInputError: true})
return;
} else {
this.props.setRewardDialogVisible( false )
this.props.rewardCode(goldRewardInput)
}
}
onGoldRewardInputChange(event) {
this.setState({ goldRewardInput: event.target.value, goldRewardInputError: false });
}
render() {
const { goldRewardDialogOpen } = this.props;
const { goldRewardInputError } = this.state;
const goldRewardInputErrorObj = goldRewardInputError ? {'error': 'error'} : {}
return (
<Dialog
open={goldRewardDialogOpen}
onClose={this.handleGoldRewardDialogClose}
>
<DialogTitle id="alert-dialog-title">{"奖励设置"}</DialogTitle>
<DialogContent>
<FormControl { ...goldRewardInputErrorObj } aria-describedby="name-error-text">
<InputLabel htmlFor="goldReward">请输入奖励的金币数量</InputLabel>
<Input id="goldReward" type="number" value={this.state.goldRewardInput} onChange={(e) => this.onGoldRewardInputChange(e)} />
{ goldRewardInputError ? <FormHelperText id="name-error-text">奖励金币不能为空或负数</FormHelperText> : ''}
</FormControl>
{/*<DialogContentText id="alert-dialog-description" style={{textAlign: 'center'}}> </DialogContentText>*/}
</DialogContent>
<DialogActions>
<Button onClick={this.handleGoldRewardDialogClose} color="primary">
取消
</Button>
<Button variant="raised"
onClick={() => this.onGoldRewardDialogOkBtnClick() } color="primary" autoFocus>
确定
</Button>
</DialogActions>
</Dialog>
);
}
}
export default RewardDialog;
import React, { Component } from 'react';
import Dialog, {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from 'material-ui/Dialog';
import Button from 'material-ui/Button';
import { FormControl, FormHelperText } from 'material-ui/Form';
import Input, { InputLabel } from 'material-ui/Input';
class RewardDialog extends Component {
constructor(props) {
super(props)
this.handleGoldRewardDialogClose = this.handleGoldRewardDialogClose.bind(this)
this.state = {
// goldRewardDialogOpen: false,
goldRewardInput: '',
}
}
showGoldRewardDialog(comment, childComment) {
if (comment.admin === true) {
this.comment = comment;
this.childComment = childComment;
this.setState({goldRewardDialogOpen: true})
}
}
handleGoldRewardDialogClose() {
this.props.setRewardDialogVisible(false)
}
onGoldRewardDialogOkBtnClick() {
console.log('onGoldRewardDialogOkBtnClick')
const { goldRewardInput } = this.state;
if (!goldRewardInput || goldRewardInput === '0' || goldRewardInput.indexOf('-') !== -1) {
this.setState({ goldRewardInputError: true})
return;
} else {
this.props.setRewardDialogVisible( false )
this.props.rewardCode(goldRewardInput)
}
}
onGoldRewardInputChange(event) {
this.setState({ goldRewardInput: event.target.value, goldRewardInputError: false });
}
render() {
const { goldRewardDialogOpen } = this.props;
const { goldRewardInputError } = this.state;
const goldRewardInputErrorObj = goldRewardInputError ? {'error': 'error'} : {}
return (
<Dialog
open={goldRewardDialogOpen}
disableEscapeKeyDown={true}
onClose={this.handleGoldRewardDialogClose}
>
<DialogTitle id="alert-dialog-title">{"奖励设置"}</DialogTitle>
<DialogContent>
<FormControl { ...goldRewardInputErrorObj } aria-describedby="name-error-text">
<InputLabel htmlFor="goldReward">请输入奖励的金币数量</InputLabel>
<Input id="goldReward" type="number" value={this.state.goldRewardInput} onChange={(e) => this.onGoldRewardInputChange(e)} />
{ goldRewardInputError ? <FormHelperText id="name-error-text">奖励金币不能为空或负数</FormHelperText> : ''}
</FormControl>
{/*<DialogContentText id="alert-dialog-description" style={{textAlign: 'center'}}> </DialogContentText>*/}
</DialogContent>
<DialogActions>
<Button onClick={this.handleGoldRewardDialogClose} color="primary">
取消
</Button>
<Button variant="raised"
onClick={() => this.onGoldRewardDialogOkBtnClick() } color="primary" autoFocus>
确定
</Button>
</DialogActions>
</Dialog>
);
}
}
export default RewardDialog;

@ -6,6 +6,8 @@ import Loading from '../../Loading';
import axios from 'axios';
import { TPMIndexHOC } from '../tpm/TPMIndexHOC';
import { CNotificationHOC } from './common/CNotificationHOC'
import {ImageLayerOfCommentHOC} from '../page/layers/ImageLayerOfCommentHOC'
import "./css/Courses.css"
//引入对应跳转的组件
@ -71,6 +73,10 @@ const WrappedCoursesNewApp= Loadable({
loading: Loading,
})
const ShixunHomeworkPage =Loadable({
loader: () => import('./shixunHomework/ShixunHomeworkPage'),
loading: Loading,
})
//实训作业
const ShixunHomework= Loadable({
loader: () => import('./shixunHomework/shixunHomework'),
@ -83,17 +89,12 @@ const Trainingjobsetting= Loadable({
loading: Loading,
})
//实训作业列表教师
const Listofworks= Loadable({
loader: () => import('./shixunHomework/Listofworks'),
loading: Loading,
})
// //实训作业列表学生未完成的
// const Studentnotcompleted= Loadable({
// loader: () => import('./shixunHomework/Listofworksstudentone'),
// loading: Loading,
// })
//实训作业列表完成的
const Studenthascompleted= Loadable({
loader: () => import('./shixunHomework/Listofworksstudentone'),
@ -442,16 +443,21 @@ class CoursesIndex extends Component{
<Switch {...this.props}>
{/* 资源列表页 */}
<Route path="/courses/:coursesId/file/:Id"
<Route path="/courses/:coursesId/file/:Id" exact
render={
(props) => (<Resourcelist {...this.props} {...props} {...this.state} />)
(props) => (<ListPageIndex {...this.props} {...props} {...this.state} />)
}
></Route>
<Route path="/courses/:coursesId/files/:main_id"
render={
(props) => (<Resourcelist {...this.props} {...props} {...this.state} />)
(props) => (<ListPageIndex {...this.props} {...props} {...this.state} />)
}
></Route>
<Route exact path="/courses/:coursesId/boards/:boardId"
render={
(props) => (<ListPageIndex {...this.props} {...props} {...this.state} />)
}
></Route>
{/*课堂讨论*/}
<Route path="/courses/:coursesId/boards/:boardId"
render={
@ -486,9 +492,9 @@ class CoursesIndex extends Component{
></Route>
{/* 毕设选题列表 */}
<Route path="/courses/:coursesId/graduation_topics/:Id"
<Route path="/courses/:coursesId/graduation_topics/:Id" exact
render={
(props) => (<GraduationTopics {...this.props} {...props} {...this.state} />)
(props) => (<ListPageIndex {...this.props} {...props} {...this.state} />)
}></Route>
@ -554,9 +560,9 @@ class CoursesIndex extends Component{
{/* 毕设任务列表 https://www.trustie.net/issues/19981 */}
<Route path="/courses/:coursesId/graduation_tasks/:Id"
<Route path="/courses/:coursesId/graduation_tasks/:Id" exact
render={
(props) => (<GraduationTasks {...this.props} {...props} {...this.state} />)
(props) => (<ListPageIndex {...this.props} {...props} {...this.state} />)
}
></Route>
@ -591,16 +597,29 @@ class CoursesIndex extends Component{
(props) => (<ListPageIndex {...this.props} {...props} {...this.state} />)
}
></Route>
{/* 普通作业 */}
<Route path="/courses/:coursesId/common_homeworks/:category_id" exact
render={
(props) => (<ListPageIndex {...this.props} {...props} {...this.state} />)
}
></Route>
{/* 分组作业 */}
<Route path="/courses/:coursesId/group_homeworks/:category_id" exact
render={
(props) => (<ListPageIndex {...this.props} {...props} {...this.state} />)
}
></Route>
{/* 普通作业 */}
<Route path="/courses/:coursesId/common_homeworks"
<Route path="/courses/:coursesId/common_homeworks/" strict
render={
(props) => (<CommonWork {...this.props} {...props} {...this.state} />)
}
></Route>
{/* 分组作业 */}
<Route path="/courses/:coursesId/group_homeworks"
<Route path="/courses/:coursesId/group_homeworks/" strict
render={
(props) => (<GroupWork {...this.props} {...props} {...this.state} />)
}
@ -700,12 +719,12 @@ class CoursesIndex extends Component{
{/*实训查重列表*/}
<Route path="/courses/:coursesId/shixun_homeworks/:homeworkid/student_work"
render={
(props) => (<ShixunStudentWork {...this.props} {...props} {...this.state} />)
(props) => (<ShixunHomeworkPage {...this.props} {...props} {...this.state} />)
}
></Route>
<Route path="/courses/:coursesId/shixun_homework/:homeworkid/student_work"
render={
(props) => (<ShixunStudentWork {...this.props} {...props} {...this.state} />)
(props) => (<ShixunHomeworkPage {...this.props} {...props} {...this.state} />)
}
></Route>
@ -724,32 +743,32 @@ class CoursesIndex extends Component{
{/*教师列表*/}
<Route path="/courses/:coursesId/shixun_homeworks/:homeworkid/list"
render={
(props) => (<Listofworks {...this.props} {...props} {...this.state} />)
(props) => (<ShixunHomeworkPage {...this.props} {...props} {...this.state} />)
}
></Route>
<Route path="/courses/:coursesId/shixun_homework/:homeworkid/list"
render={
(props) => (<Listofworks {...this.props} {...props} {...this.state} />)
(props) => (<ShixunHomeworkPage {...this.props} {...props} {...this.state} />)
}
></Route>
{/*实训作业page*/}
<Route path="/courses/:coursesId/shixun_homeworks/:homeworkid/Page"
render={
(props) => (<ShixunHomeworkPage {...this.props} {...props} {...this.state} />)
}
></Route>
{/*实训作业设置*/}
<Route path="/courses/:coursesId/shixun_homeworks/:homeworkid/settings"
render={
(props) => (<Trainingjobsetting {...this.props} {...props} {...this.state} />)
(props) => (<ShixunHomeworkPage {...this.props} {...props} {...this.state} />)
}
></Route>
<Route path="/courses/:coursesId/shixun_homework/:homeworkid/settings"
render={
(props) => (<Trainingjobsetting {...this.props} {...props} {...this.state} />)
(props) => (<ShixunHomeworkPage {...this.props} {...props} {...this.state} />)
}
></Route>
{/*/!*实训作品列表教师*!/*/}
{/*<Route path="/courses/:coursesId/:homeworkid/list"*/}
{/* render={*/}
{/* (props) => (<Listofworks {...this.props} {...props} {...this.state} />)*/}
{/* }*/}
{/*></Route>*/}
{/*提交总结*/}
<Route path="/courses/:coursesId/shixun_homeworks/:id/commitsummary/:homeworkid"
render={
@ -770,13 +789,13 @@ class CoursesIndex extends Component{
{/*实训学生作品列表已公布*/}
<Route path="/courses/:coursesId/shixun_homeworks/:homeworkid/openlist"
render={
(props) => (<Studenthascompleted {...this.props} {...props} {...this.state} />)
(props) => (<ShixunHomeworkPage {...this.props} {...props} {...this.state} />)
}
></Route>
{/*实训学生作品列表已公布*/}
<Route path="/courses/:coursesId/shixun_homework/:homeworkid/openlist"
render={
(props) => (<Studenthascompleted {...this.props} {...props} {...this.state} />)
(props) => (<ShixunHomeworkPage {...this.props} {...props} {...this.state} />)
}
></Route>
@ -785,14 +804,14 @@ class CoursesIndex extends Component{
{/*实训作业问答主目录*/}
<Route path="/courses/:coursesId/shixun_homeworks/:homeworkid/questions"
render={
(props) => (<Workquestionandanswer {...this.props} {...props} {...this.state} />)
(props) => (<ShixunHomeworkPage {...this.props} {...props} {...this.state} />)
}
></Route>
{/*实训作业问答子目录*/}
<Route path="/courses/:coursesId/shixun_homework/:homeworkid/questions"
render={
(props) => (<Workquestionandanswer {...this.props} {...props} {...this.state} />)
(props) => (<ShixunHomeworkPage {...this.props} {...props} {...this.state} />)
}
></Route>
@ -844,4 +863,4 @@ class CoursesIndex extends Component{
}
}
export default CNotificationHOC() ( SnackbarHOC() ( TPMIndexHOC(CoursesIndex) ));
export default ImageLayerOfCommentHOC({imgSelector: '.imageLayerParent img, .imageLayerParent .imageTarget', parentSelector: '.newMain'}) (CNotificationHOC() ( SnackbarHOC() ( TPMIndexHOC(CoursesIndex) )));

@ -56,6 +56,14 @@ const ShixunHomework= Loadable({
loading: Loading,
})
const GraduationTopics= Loadable({
loader: () => import('./graduation/topics'),
loading: Loading,
})
const GraduationTasks= Loadable({
loader: () => import('./graduation/tasks'),
loading: Loading,
})
class ListPageIndex extends Component{
constructor(props) {
super(props)
@ -169,12 +177,34 @@ class ListPageIndex extends Component{
}
></Route>
<Route path="/courses/:coursesId/files/:main_id"
render={
(props) => (<Resourcelist {...this.props} {...props} {...this.state} />)
}
></Route>
<Route path="/courses/:coursesId/file/:Id"
render={
(props) => (<Resourcelist {...this.props} {...props} {...this.state} />)
}
></Route>
<Route path="/courses/:coursesId/graduation_topics/:Id"
render={
(props) => (<GraduationTopics {...this.props} {...props} {...this.state} />)
}></Route>
<Route path="/courses/:coursesId/graduation_tasks/:Id"
render={
(props) => (<GraduationTasks {...this.props} {...props} {...this.state} />)
}
></Route>
{/* 默认 */}
<Route path="/courses/:coursesId"
render={
(props) => (<StudentsList {...this.props} {...props} {...this.state} />)
}
></Route>
</Switch>
</div>
</div>

@ -5,9 +5,10 @@ import {Link} from 'react-router-dom';
import {getImageUrl} from 'educoder';
import axios from 'axios'
import {getUrl} from 'educoder';
import moment from 'moment';
import moment from 'moment'
import CoursesListType from '../coursesPublic/CoursesListType';
import Showoldfiles from "../coursesPublic/Showoldfiles";
import Modals from '../../modals/Modals';
class Fileslistitem extends Component{
constructor(props){
@ -25,45 +26,32 @@ class Fileslistitem extends Component{
})
this.props.Settingtypes(discussMessage.id)
}
showfiles=()=>{
showfiles=(value)=>{
let {discussMessage,coursesId}=this.props
let file_id=discussMessage.id
let url="/files/"+file_id+"/histories.json"
axios.get(url,{
params:{
course_id:coursesId
}
},
}).then((result)=>{
if(result.data.attachment_histories.length===0){
let link = document.createElement('a');
// link.href = window.URL.createObjectURL(new Blob([result.data.url]));
link.href = result.data.url;
link.download = result.data.title;
//兼容火狐浏览器
document.body.appendChild(link);
let evt = document.createEvent("MouseEvents");
evt.initEvent("click", false, false);
link.dispatchEvent(evt);
document.body.removeChild(link);
// // window.location.href=result.data.url;
// let url = window.URL.createObjectURL(new Blob([result.data.url]));
// let link = document.createElement('a');
// link.style.display = 'none';
// link.href = url;
// link.setAttribute('download',result.data.title);
// document.body.appendChild(link);
// link.click();
}else{
let link = document.createElement('a');
document.body.appendChild(link);
link.href = result.data.url;
link.download = result.data.title;
//兼容火狐浏览器
let evt = document.createEvent("MouseEvents");
evt.initEvent("click", false, false);
link.dispatchEvent(evt);
document.body.removeChild(link);
}else{
this.setState({
Showoldfiles:true,
allfiles:result.data
})
}
// console.log(result)
}).catch((error)=>{
console.log(error)
})
@ -74,7 +62,68 @@ class Fileslistitem extends Component{
Showoldfiles:false,
})
}
render(){
onDelete = (id) => {
this.setState({
Modalstype:true,
Modalstopval:"是否确认删除?",
ModalCancel:this.cancelmodel,
ModalSave:()=>this.savedelete(id),
})
}
cancelmodel=()=>{
this.setState({
Modalstype:false,
Loadtype:false,
Modalstopval:"",
ModalCancel:"",
ModalSave:"",
checkBoxValues:[],
})
}
savedelete=(id)=>{
this.setState({
Modalstype:false,
})
const cid = this.props.match.params.coursesId
const url = `/files/bulk_delete.json`;
axios.delete(url, { data: {
course_id:cid,
ids: [id],
}})
.then((response) => {
if (response.data.status == 0) {
//Modalstopval:response.data.message,
this.props.updatafiledfun()
this.setState({
// Modalstype:true,
// Modalstopval:"删除成功",
ModalsBottomval:"",
// ModalSave:this.cancelmodel,
// Loadtype:true,
checkBoxValues:[],
checkAllValue:false
})
this.props.showNotification("删除成功");
}
})
.catch(function (error) {
console.log(error);
});
}
render(){
const { checkBox,
discussMessage,
@ -84,6 +133,16 @@ class Fileslistitem extends Component{
return(
<div className="graduateTopicList boardsList">
{/*提示*/}
{this.state.Modalstype&&this.state.Modalstype===true?<Modals
modalsType={this.state.Modalstype}
modalsTopval={this.state.Modalstopval}
modalCancel={this.state.ModalCancel}
modalSave={this.state.ModalSave}
modalsBottomval={this.state.ModalsBottomval}
loadtype={this.state.Loadtype}
/>:""}
<Showoldfiles
visible={this.state.Showoldfiles}
allfiles={this.state.allfiles}
@ -97,20 +156,21 @@ class Fileslistitem extends Component{
margin-top: 0px;
}
`}</style>
{checkBox}
<style>{`
.boardsList .panel-list-img {
width: 50px;
height: 50px;
}
`}</style>
<a href={"/users/"+this.props.user.login} alt="用户"
style={{"width": "50px", "height": "50px", "display": "block", margin: "0 10px"}}>
<img
alt="1?1529221779" className="panel-list-img mr15" height="50"
src={getImageUrl("images/"+discussMessage.author.image_url)} width="50"
></img>
</a>
{/*<a href={"/users/"+this.props.user.login} alt="用户"*/}
{/*style={{"width": "50px", "height": "50px", "display": "block", margin: "0 10px"}}>*/}
{/*<img*/}
{/*alt="1?1529221779" className="panel-list-img mr15" height="50"*/}
{/*src={getImageUrl("images/"+discussMessage.author.image_url)} width="50"*/}
{/*></img>*/}
{/*</a>*/}
<style>{`
.boardsList .contentSection{
@ -125,44 +185,42 @@ class Fileslistitem extends Component{
`}</style>
<div className="clearfix ds pr contentSection">
<h6>
{
this.props.isAdmin ? <a
// href={"/courses/" + coursesId + "/graduation/graduation_tasks/" + categoryid + "/" + taskid + "/list"}
onClick={this.showfiles}
title={discussMessage.title}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</a> : ""
}
<span className="fl mr12 mt3">
{checkBox}
</span>
{
this.props.isAdmin ? <a
// href={"/courses/" + coursesId + "/graduation/graduation_tasks/" + categoryid + "/" + taskid + "/list"}
onClick={()=>this.showfiles(discussMessage.title)}
title={discussMessage.title}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</a> : ""
}
{
this.props.isStudent? <a
onClick={this.showfiles}
onClick={()=>this.showfiles(discussMessage.title)}
title={discussMessage.title}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</a> :""
}
{
this.props.isNotMember ? discussMessage.is_lock === true ?
this.props.isNotMember===true?
discussMessage.is_lock === true ?
<span className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</span>
:
<a
onClick={this.showfiles}
// href={"/courses/" + coursesId + "/graduation/graduation_tasks/" + categoryid + "/" + taskid + "/list"}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</a> :""
}
:<a
onClick={()=>this.showfiles(discussMessage.title)}
title={discussMessage.title}
className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.title}</a>:""
}
{
discussMessage.is_lock === true ?
<Tooltip title={ this.props.isNotMember?"私有属性,非课堂成员不能访问":"私有属性"} placement="bottom">
<Tooltip title={ this.props.isNotMember===true?"私有属性,非课堂成员不能访问":"私有属性"} placement="bottom">
<i className="iconfont icon-guansuo color-grey-c ml10 font-16 fl mt4"></i>
</Tooltip>
:""
}
{discussMessage.is_publish===true?"":<CoursesListType typelist={["未发布"]} typesylename={""}/>}
{discussMessage.is_publish===false?<CoursesListType typelist={["未发布"]} typesylename={""}/>:""}
</h6>
<style>
{
@ -176,39 +234,36 @@ class Fileslistitem extends Component{
}
</style>
{this.props.isAdmin ||this.props.current_user.username===discussMessage.author.name?
<span className={"sttingbox"}>
<WordsBtn style="blue" className="colorblue font-16 mr20 fr">
<a className="btn colorblue"
onClick={()=>this.settingList()}>设置</a>
</WordsBtn>
</span>:""}
<div className="cl"></div>
<style>
{
`
.lightgreybox{
min-width: 260px;
}
.mrf2{
margin-top: -2px;
}
`
}
</style>
{discussMessage.course_groups.length===0?"":
<p className="color-grey panel-lightgrey mt8 fl lightgreybox">
<p className="color-grey panel-lightgrey mt8 fl lightgreybox ml30" style={{width:'100%'}}>
{discussMessage.course_groups.map((item,key)=>{
return(
<div className="mr50">
<span className="mr15 color-dark">{item.course_group_name}</span>
<span className="mr15 color-grey9 fr">发布于 { moment(item.course_group_publish_time).format('YYYY-MM-DD hh:mm')}</span>
<span className="mr15 color-grey9 ">发布于 { moment(item.course_group_publish_time).format('YYYY-MM-DD HH:mm')}</span>
</div>
)
})}
</p>}
<p className="color-grey panel-lightgrey mt8 fl" style={{width:'70%'}}>
<p className="color-grey panel-lightgrey mt8 fl ml30" style={{width:'100%'}}>
<span className="mr50">
<span className="mr15 color-dark">{discussMessage.author.name}</span>
<span className="mr15 color-dark">{discussMessage.author.login}</span>
<span className="mr15 color-grey9">大小 {discussMessage.filesize}</span>
<span className="mr15 color-grey9">下载 {discussMessage.downloads_count}</span>
<span className="mr15 color-grey9">引用 {discussMessage.quotes}</span>
@ -217,19 +272,45 @@ class Fileslistitem extends Component{
{/*{moment(discussMessage.publish_time).fromNow()}*/}
{ discussMessage.publish_time===null?"":
discussMessage.is_publish===true?"":"发布于"}
{ discussMessage.publish_time===null?"":discussMessage.is_publish===true?moment(discussMessage.publish_time).fromNow():moment(discussMessage.publish_time).format('YYYY-MM-DD hh:mm')}
{ discussMessage.publish_time===null?"":discussMessage.is_publish===true?moment(discussMessage.publish_time).fromNow():moment(discussMessage.publish_time).format('YYYY-MM-DD HH:mm')}
</span>
</span>
{this.props.isAdmin?
<span className={"fr mrf2 mr10"}>
<WordsBtn style="blue" className="colorblue font-16 mr20 fr">
<a className="btn colorblue"
onClick={()=>this.settingList()}>设置</a>
</WordsBtn>
</span>:""}
{this.props.isStudent===true&&this.props.current_user.login===discussMessage.author.login?
<span className={"fr mrf2 mr10"}>
<WordsBtn style="blue" className="colorblue font-16 mr20 fr">
<a className="btn colorblue"
onClick={()=>this.settingList()}>设置</a>
</WordsBtn>
<WordsBtn style="blue" className="colorblue font-16 mr20 fr">
<a className="btn colorblue"
onClick={()=>this.onDelete(discussMessage.id)}>删除</a>
</WordsBtn>
</span>:""}
</p>
<p className="color-grey panel-lightgrey mt8 fl" style={{width:'100%'}}>
<span className="mr50">
<span className="mr15 color-dark">资源描述 :</span>
<span className="mr15 color-dark">{discussMessage.description}</span>
{this.props.isAdmin ?<span><i className="iconfont icon-bianjidaibeijing font-22 color-green" onClick={()=>this.settingList()}></i></span>:""}
</span>
<p className="color-grey panel-lightgrey mt8 fl ml30" style={{width:'100%'}}>
<pre className="color-dark">资源描述 :{discussMessage.description===null?"暂无描述":discussMessage.description}</pre>
{/*<span className="mr50">*/}
{/*/!*<span className="mr15 color-dark"></span>*!/*/}
{/*<span className="mr15 color-dark">*/}
{/*</span>*/}
{/*/!*{this.props.isAdmin ?<span><i className="iconfont icon-bianjidaibeijing font-22 color-green" onClick={()=>this.settingList()}></i></span>:""}*!/*/}
{/*</span>*/}
</p>

@ -7,11 +7,12 @@ import Sendtofilesmodal from "../coursesPublic/SendToFilesModal";
import Selectresource from "../coursesPublic/SelectResource";
import Sendresource from "../coursesPublic/sendResource";
import Selectsetting from "../coursesPublic/SelectSetting";
import CourseLayoutcomponent from '../common/CourseLayoutComponent';
import HomeworkModal from "../coursesPublic/HomeworkModal";
import Fileslistitem from './Fileslistitem';
import Titlesearchsection from '../common/titleSearch/TitleSearchSection';
import './style.css';
import '../css/members.css';
import moment from 'moment';
class Fileslists extends Component{
constructor(props){
@ -36,12 +37,15 @@ class Fileslists extends Component{
course_modules:undefined,
has_course_groups:false,
course_is_public:undefined,
isSpin:false
isSpin:false,
course_second_categories:[]
}
}
componentDidMount=()=>{
this.setState({
isSpin:true
isSpin:true,
checkBoxValues:[],
checkAllValue:false
})
if(this.props.match.params.main_id){
this.seactall();
@ -49,21 +53,37 @@ class Fileslists extends Component{
this.seactall(parseInt(this.props.match.params.Id),1)
}
this.updadatalist();
on('updateNavSuccess', this.updateNavSuccess)
on('updateNavSuccess',this.updadatalist)
}
updateNavSuccess=()=>{
this.setState({
isSpin:true
})
if(this.props.match.params.main_id){
this.seactall();
}else if(this.props.match.params.Id){
this.seactall(parseInt(this.props.match.params.Id),1)
}
}
componentDidUpdate = (prevProps) => {
if(prevProps.match.params.main_id != this.props.match.params.main_id){
this.setState({
isSpin:true
})
this.setState({
isSpin:true,
checkBoxValues:[],
checkAllValue:false
})
if(this.props.match.params.main_id!=undefined){
this.seactall();
}
}
if(prevProps.match.params.Id != this.props.match.params.Id){
this.setState({
isSpin:true
})
this.setState({
isSpin:true,
checkBoxValues:[],
checkAllValue:false
})
if(this.props.match.params.Id!=undefined){
this.seactall(parseInt(this.props.match.params.Id),1)
}
@ -96,16 +116,33 @@ class Fileslists extends Component{
axios.get(url, {
}).then((response) => {
if(response!=undefined){
if(response.data&&response.data){
let list=response.data.course_modules;
let course_second_categoriess;
list.map((item,key)=>{
course_second_categoriess=item.course_second_categories
})
this.setState({
course_modules:response.data,
has_course_groups:response.data.has_course_groups
has_course_groups:response.data.has_course_groups,
course_second_categories:course_second_categoriess
})
}
}
})
}
updatafiled=()=>{
if(this.props.match.params.main_id){
this.seactall();
}else if(this.props.match.params.Id){
this.seactall(parseInt(this.props.match.params.Id),1)
}
}
seactall=(coursesecondcategoryid,type)=>{
this.setState({
@ -150,8 +187,8 @@ class Fileslists extends Component{
let list=result.data.data;
this.setState({
total_count:list.total_count,
public_count:list.public_count,
private_count:list.private_count,
publish_count:list.publish_count,
unpublish_count:list.unpublish_count,
files:list.files,
filesId:list.id,
name:list.name,
@ -207,7 +244,9 @@ class Fileslists extends Component{
this.props.showNotification("请先在列表中选择要发送的资源");
}else if(value===3){
this.props.showNotification("请先在列表中选择要公开的资源");
}
}else if(value===4){
this.props.showNotification("请先在列表中选择要发布的资源");
}
}
onDelete = () => {
@ -243,8 +282,7 @@ class Fileslists extends Component{
.then((response) => {
if (response.data.status == 0) {
//Modalstopval:response.data.message,
this.seactall();
this.updatafiled()
this.setState({
// Modalstype:true,
// Modalstopval:"删除成功",
@ -255,6 +293,7 @@ class Fileslists extends Component{
checkAllValue:false
})
this.props.showNotification("删除成功");
this.props.updataleftNavfun()
}
})
.catch(function (error) {
@ -297,14 +336,14 @@ class Fileslists extends Component{
this.setState({
Modalstype:true,
Modalstopval:"公开后非课堂成员也可以访问查看",
ModalsBottomval:"是否确认公开?",
Modalstopval:"设为公开后非课堂成员也可以访问查看",
ModalsBottomval:"是否确认设为公开?",
ModalCancel:this.cancelmodel,
ModalSave:this.saveonOpen,
})
}
saveonOpen=()=>{
saveonOpen=()=>{
this.setState({
Modalstype:false,
})
@ -507,8 +546,6 @@ class Fileslists extends Component{
})
.then((response) => {
if (response.data.status == 0) {
this.seactall();
this.setState({
// Modalstype:true,
// Modalstopval:response.data.message,
@ -516,22 +553,95 @@ class Fileslists extends Component{
// ModalSave:this.cancelmodel,
// Loadtype:true,
checkBoxValues:[],
// checkAllValue:false
checkAllValue:false
})
this.props.showNotification('资源移动成功')
this.props.updataleftNavfun()
this.updatafiled()
}
})
}
homeworkstart=()=>{
let selectnum= this.testonSelect();
if(selectnum===true){
this.noSelect(4);
return
}
let starttime= this.props.getNowFormatDates(1);
let endtime=this.props.getNowFormatDates(2);
this.setState({
modalname:"立即发布",
visible:true,
typs:"start",
Topval:"学生将能立即查看和下载发布资源",
// Botvalleft:"暂不发布",
// Botval:`本操作只对"未发布"的分班有效`,
// starttime:"发布时间:"+moment(moment(new Date())).format("YYYY-MM-DD HH:mm"),
// starttimes:starttime,
// endtime:"截止时间:"+endtime,
Cancelname:"暂不发布",
Savesname:"立即发布",
Cancel:this.homeworkhide,
Saves:this.homeworkstartend,
})
}
// 立即发布
homeworkstartend=(ds,endtime)=>{
let {checkBoxValues}=this.state;
let coursesId=this.props.match.params.coursesId;
let url ="/files/bulk_publish.json";
axios.put(url, {
course_id:coursesId,
ids :checkBoxValues,
}).then((result)=>{
if(result.status===200){
this.props.showNotification("发布成功")
this.setState({
checkBoxValues:[],
checkAllValue:false
})
this.homeworkhide()
this.props.updataleftNavfun()
this.updatafiled()
}
}).catch((error)=>{
console.log(error);
})
}
render(){
homeworkhide=()=>{
this.setState({
modalname:undefined,
modaltype:undefined,
visible:false,
Topval:undefined,
Topvalright:undefined,
Botvalleft:undefined,
Botval:undefined,
starttime:undefined,
endtime:undefined,
Cancelname:undefined,
Savesname:undefined,
Cancel:undefined,
Saves:undefined,
StudentList_value:undefined,
addname:undefined,
addnametype:false,
addnametab:undefined,
typs:undefined,
starttimes:undefined,
})
}
render(){
let { searchValue,
checkBoxValues,
checkAllValue,
total_count,
public_count,
private_count,
publish_count,
unpublish_count,
files,
sorttype,
Modalstype,
@ -548,14 +658,35 @@ class Fileslists extends Component{
discussMessageid,
course_modules,
shixunmodal,
course_is_public
course_is_public,
filesId
} = this.state;
let category_id= this.props.match.params.category_id;
return(
<div>
<React.Fragment >
{/*立即发布*/}
{this.state.visible===true?<HomeworkModal
category_id={this.props.match.params.category_id}
modaltype={this.state.modaltype}
modalname={this.state.modalname}
visible={this.state.visible}
Topval={this.state.Topval}
Topvalright={this.state.Topvalright}
Botvalleft={this.state.Botvalleft}
Botval={this.state.Botval}
starttime={this.state.starttime}
starttimes={this.state.starttimes}
typs={this.state.typs}
endtime={this.state.endtime}
Cancelname={this.state.Cancelname}
Savesname={this.state.Savesname}
Cancel={this.state.Cancel}
Saves={this.state.Saves}
course_groups={this.state.course_groups}
/>:""}
{/*发送*/}
<Sendtofilesmodal
@ -628,7 +759,6 @@ class Fileslists extends Component{
has_course_groups={this.state.has_course_groups}
/>:""}
<CourseLayoutcomponent {...this.props}>
<Titlesearchsection
title={name}
searchValue={ searchValue }
@ -647,8 +777,8 @@ class Fileslists extends Component{
secondRowLeft={
<div style={{"display":"inline-block", "marginTop": "22px"}}>
<span> {total_count} 个资源</span>
<span style={{"marginLeft":"16px"}}>公共资源{public_count}</span>
{this.props.isAdmin()||this.props.isStudent()?<span style={{"marginLeft":"16px"}}>私有资源{private_count}</span>:""}
<span style={{"marginLeft":"16px"}}>已发布{publish_count}</span>
<span style={{"marginLeft":"16px"}}>未发布{unpublish_count}</span>
</div>
}
onPressEnter={this.onPressEnter}
@ -656,12 +786,15 @@ class Fileslists extends Component{
showSearchInput={true}
></Titlesearchsection>
<div className="mt20 edu-back-white padding20-30" style={{display:this.props.isAdmin()||this.props.isStudent()?"":"none"}}>
{this.props.isAdmin()? <div className="mt20 edu-back-white padding20-30" style={{display:this.props.isAdmin()||this.props.isStudent()?"":"none"}}>
<div className="clearfix">
{this.props.isAdmin()? <Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue}>已选 {checkBoxValues.length} </Checkbox>:""}
<div className="studentList_operation_ul">
{this.props.isAdmin()?<li className="li_line"><a href="javascript:void(0)" className="color-grey-9" onClick={this.onDelete}>删除</a></li>:""}
{this.props.isAdmin()?<li className="li_line"><a href="javascript:void(0)" className="color-grey-9" onClick={this.onSend}>发送</a></li>:""}
{this.props.isAdmin()?
<li className="li_line"><a href="javascript:void(0)" className="color-grey-9" onClick={this.homeworkstart}>立即发布</a></li>
:""}
{this.props.isAdmin()?course_is_public===true?
<li className="li_line"><a href="javascript:void(0)" className="color-grey-9" onClick={this.onOpen}>设为公开</a></li>
:"":""}
@ -676,31 +809,37 @@ class Fileslists extends Component{
overflow-y: auto;
}
.drop_down_menu li {
overflow: visible;
}
overflow: visible;
}
.courseSecond{
margin-left: 10px;
padding: 10px;
}
`}
</style>
<ul className="drop_down_menu" style={{"right":"0px","left":"unset"}}>
<p className="drop_down_search">
<ul className="drop_down_menu" style={{"right":"0px","left":"unset","min-width":'150px'}}>
{this.state.course_second_categories.length>10? <p className="drop_down_search">
<Input placeholder="搜索" value={this.state.dirSearchValue} onChange={(e) => {this.setState({dirSearchValue: e.target.value})}}/>
</p>
</p>:""}
{/*{course_modules&&course_modules.course_modules.map((item,key)=>{*/}
{/*return(*/}
{/*<li key={key} id={item.id} onClick={() => this.moveTos(0)}>{item.module_name}</li>*/}
{/*)*/}
{/*})}*/}
{course_modules&&course_modules.course_modules.map((item,key)=>{
return(
filesId&&filesId===item.id?"":<li key={key} id={item.id} onClick={() => this.moveTos(0)}>{item.module_name}</li>
)
})}
{ course_modules&&course_modules.course_modules.map( (item,key) => {
return item.course_second_categories.filter((item)=> {
return (!this.state.dirSearchValue || item.name.indexOf(this.state.dirSearchValue) != -1)
}).map((itm,k)=>{
return(
<li key={k} id={itm.id} onClick={() => this.moveTos(itm.id )}>{itm.name}</li>
filesId&&filesId===itm.id?"":<li key={k} id={itm.id} onClick={() => this.moveTos(itm.id )}>{itm.name}</li>
)
})
})}
{this.state.course_second_categories.length===0?
<div className={"courseSecond"}>暂无数据</div>:""}
{/*{course_modules&&course_modules.course_modules.map((item,key)=>{*/}
{/*return(*/}
@ -711,9 +850,9 @@ class Fileslists extends Component{
{/*})*/}
{/*)*/}
{/*})}*/}
{this.props.isAdmin()?parseInt(this.props.match.params.main_id)===parseInt(this.props.coursesids)?
{this.props.isAdmin()?parseInt(this.props.match.params.main_id)===filesId&&filesId?
<p className="drop_down_btn">
<a className="color-grey-6" onClick={()=>this.addDir()}>添加目录...</a>
<a className="color-grey-6" onClick={()=>this.addDir()}>添加目录</a>
</p>
:"":""}
</ul>
@ -734,7 +873,7 @@ class Fileslists extends Component{
</li>:""}
</div>
</div>
</div>
</div> :""}
<style>{`
.padding02010{
@ -766,9 +905,10 @@ class Fileslists extends Component{
isAdmin={this.props.isAdmin()}
isStudent={this.props.isStudent()}
isNotMember={this.props.isNotMember()}
checkBox={<Checkbox value={item.id}></Checkbox>}
checkBox={this.props.isAdmin()?<Checkbox value={item.id} key={item.id}></Checkbox>:""}
Settingtypes={(id)=>this.Settingtypes(id)}
coursesId={this.props.match.params.coursesId}
updatafiledfun={()=>this.updatafiled()}
></Fileslistitem>
</div>
</div>
@ -810,18 +950,17 @@ class Fileslists extends Component{
<div className="alltask edu-back-white"
style={
{
display: total_count===undefined?'block' :total_count===0? 'block' : 'none'
display: files===undefined?'block' :files.length===0? 'block' : 'none'
}
}
>
<div className="edu-tab-con-box clearfix edu-txt-center"><img className="edu-nodata-img mb20"
src="https://www.educoder.net/images/educoder/nodata.png" />
<div className="edu-tab-con-box clearfix edu-txt-center">
<img className="edu-nodata-img mb20" src="/images/educoder/nodata.png" />
<p className="edu-nodata-p mb20">暂无数据哦~</p></div>
</div>
</CourseLayoutcomponent>
</div>
</React.Fragment>
)
}
}

@ -0,0 +1,89 @@
import React,{ Component } from "react";
import {Tooltip, Modal, Input } from 'antd'
import moment from 'moment'
import { getUrl, WordsBtn } from 'educoder'
import axios from 'axios'
class AddDirModal extends Component{
constructor(props){
super(props);
this.state = {
}
}
onInput = (e) => {
this.setState({
inputValue: e.target.value
})
}
open = () => {
this.setState({ visible: true, inputValue: '' })
}
onSave = () => {
let coursesId = this.props.match.params.coursesId;
const url = `/courses/${coursesId}/boards.json`
let { inputValue } = this.state;
if (!inputValue) {
this.setState({ errorMsg: '名称不能为空'})
return;
}
if (inputValue.length > 20) {
this.setState({ errorMsg: '名称不能超过20个字'})
return;
}
this.setState({ errorMsg: ''})
axios.post(url,{
name: inputValue
}).then((response)=>{
if (response.data.status == 0) {
this.onCancel()
this.props.showNotification('添加成功')
this.props.addSuccess && this.props.addSuccess()
}
}).catch((error)=>{
console.log(error)
})
}
onCancel = () => {
this.setState({ visible: false, inputValue: '', errorMsg: '' })
}
render(){
let { inputValue, visible, errorMsg } = this.state;
const { title } = this.props;
return(
<Modal
keyboard={false}
title={title}
visible={visible}
className={"Navmodal"}
closable={false}
footer={null}
destroyOnClose={true}
centered={true}
>
<div className="df">
<div className={"fl mt5"}>{this.props.label}</div>
<Input placeholder={this.props.inputPlaceholder || '示例讨论小组A'}
className={"input-flex-35 greyInput fl"}
maxLength="60"
value={inputValue}
onInput={this.onInput}
/>
</div>
{errorMsg && <span style={{color: 'red', marginTop: '2px', display: 'inline-block' }}>{errorMsg}</span>}
{/* {this.state.NavmodalValuetype===true?<span className={"color-red"}>
{this.state.NavmodalValues}
</span>:""} */}
{/* this.state.NavmodalValuetype===true?"clearfix mt20 edu-txt-center": */}
<div className={"clearfix mt50 edu-txt-center"}>
<a className="task-btn mr30" onClick={this.onCancel}>取消</a>
<a className="task-btn task-btn-orange" onClick={this.onSave}>确定</a>
</div>
</Modal>
)
}
}
export default AddDirModal;

@ -1,6 +1,7 @@
import React,{ Component } from "react";
import {Tooltip} from 'antd'
import moment from 'moment'
import { getUrl, WordsBtn } from 'educoder'
class BoardsListItem extends Component{
constructor(props){
super(props);
@ -26,6 +27,8 @@ class BoardsListItem extends Component{
if (!discussMessage || !discussMessage.author) {
return '';
}
let canNotLink = !isAdminOrStudent && discussMessage.is_public == false
return(
<div className="panel-inner-fourm boardsList">
<style>{`
@ -35,17 +38,19 @@ class BoardsListItem extends Component{
}
`}</style>
{ checkBox }
<a href="/users/innov" alt="用户" style={{"width":"50px","height":"50px","display":"block", margin: "0 10px"}}>
<a href={`/users/${discussMessage.author.login}`} alt="用户" style={{"width":"50px","height":"50px","display":"block", margin: "0 10px"}}>
{/* /images/avatars/User/1?1529221779 */}
<img
alt="1?1529221779" className="panel-list-img mr15" height="50"
src={`/images/${discussMessage.author.image_url}`} width="50"
src={`${getUrl()}/images/${discussMessage.author.image_url}`} width="50"
></img>
</a>
<div className="clearfix ds pr pt5 contentSection" onClick={() => onItemClick(discussMessage)}>
<h6>
<a href="javascript:void(0)" className="panel-list-title hide fl mt5 color-dark font-bd" style={{ fontWeight: 'bold' }}
onClick={() => this.onTitleClick(discussMessage)}
<a href="javascript:void(0)" className="panel-list-title hide fl mt5 color-dark font-bd"
style={{ fontWeight: 'bold', cursor: (canNotLink ? 'default' : 'poninter'), maxWidth: '700px' }}
onClick={canNotLink ? () => {} : () => this.onTitleClick(discussMessage)}
title={`${discussMessage.subject.length > 40 ? discussMessage.subject : ''}`}
>{discussMessage.subject}</a>
{ !!discussMessage.sticky && <span className="btn-cir btn-cir-red fl mt5 ml5">置顶</span> }
{
@ -57,34 +62,37 @@ class BoardsListItem extends Component{
</h6>
<div className="cl"></div>
<p className="color-grey panel-lightgrey mt10 fl">
<p className="color-grey panel-lightgrey mt18 fl">
<span className="mr50">
<a href="/users/innov" className="panel-name-small hide fl mr15 mr30 color-grey3">{discussMessage.author.name}</a>
<a href={`/users/${discussMessage.author.login}`} className="panel-name-small hide fl mr15 mr30 color-grey3 font-14">{discussMessage.author.name}</a>
{ discussMessage.total_replies_count != 0 && <span className="mr15 color-grey9">{discussMessage.total_replies_count} 回复</span> }
{ discussMessage.total_praises_count != 0 && <span className="mr15 color-grey9">{discussMessage.total_praises_count} 点赞</span> }
{ discussMessage.visits != 0 && <span className="mr15 color-grey9">{discussMessage.visits} 浏览</span> }
{ discussMessage.total_replies_count != 0 && <span className="mr15 color-grey9 font-14">{discussMessage.total_replies_count} 回复</span> }
{ discussMessage.total_praises_count != 0 && <span className="mr15 color-grey9 font-14">{discussMessage.total_praises_count} 点赞</span> }
{ discussMessage.visits != 0 && <span className="mr15 color-grey9 font-14">{discussMessage.visits} 浏览</span> }
<span className="mr15 color-light-grey-C">{moment(discussMessage.created_on).fromNow()} </span>
<span className="mr15 color-light-grey-C font-14">{moment(discussMessage.created_on).fromNow()} </span>
</span>
{/* <span className="mr10">最后回复<span className="ml10 mr10">社区导师</span>10个月前</span> */}
</p>
<div className="fr mt15">
{(isAdmin || discussMessage.author.login == current_user.login) &&
<WordsBtn style="blue" className="fl font-16 ml28"
onClick={(e) => { this.props.toEditPage(this.props.match.params.coursesId, this.props.match.params.boardId, discussMessage.id )} }>编辑</WordsBtn> }
{ isAdmin && <WordsBtn style="blue" className="fl font-16 ml28"
onClick={(e) => { debugger; onSticky(discussMessage); e.cancelBubble = true; e.stopPropagation();}}>
{ discussMessage.sticky ? '取消置顶' : '置顶' }</WordsBtn> }
</div>
{/* <span className="mr10"><i className="fa fa-eye color-grey mr5 "></i>473</span> */}
{/* <p className="fr panel-lightgrey mt10">
<span className="mr10"><i className="fa fa-eye color-grey mr5" data-tip-down="浏览数"></i>82</span>
<span className="mr10"><i className="fa fa-thumbs-up color-grey mr5" data-tip-down="点赞数"></i>1</span>
<span className="mr10"><i className="fa fa-comments-o color-grey mr5" data-tip-down="回复数"></i>4</span>
</p> */}
{ (isAdmin || discussMessage.author.login == current_user.login) &&
{/* { (isAdmin || discussMessage.author.login == current_user.login) &&
<div className="homepagePostSetting" style={{"right":"4px","top":"5px","display":"block"}}>
<ul>
<li className="edu-position edu-position-hidebox">
<i className="fa fa-bars color-grey-b"></i>
<ul className="edu-position-hide undis">
{/* <li><a href="javascript:void(0)" onclick="show_send(34255, 1, 'message');">发送</a></li> */}
{(isAdmin || discussMessage.author.login == current_user.login) && <li><a href="javascript:void(0)" onClick={(e) => {
this.props.toEditPage(this.props.match.params.coursesId, this.props.match.params.boardId, discussMessage.id )} } >编辑</a></li>
}
@ -92,14 +100,13 @@ class BoardsListItem extends Component{
{ discussMessage.sticky ? '取消置顶' : '置顶' }
</a></li>
}
{/* <li>
<a href="javascript:void(0);" onclick="delete_confirm_box_3('/boards/5464/topics/34255/destroy', '确定要删除该帖子吗?')">删除</a>
</li> */}
</ul>
</li>
</ul>
</div>
}
} */}
</div>
</div>
)

@ -3,13 +3,13 @@ import React,{ Component } from "react";
import {
Form, Input, InputNumber, Switch, Radio,
Slider, Button, Upload, Icon, Rate, Checkbox, message,
Row, Col, Select, Modal
Row, Col, Select, Modal, Divider
} from 'antd';
import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor';
import axios from 'axios'
import './board.css'
import "../common/formCommon.css"
import AddDirModal from './AddDirModal'
import { RouteHOC } from './common.js'
import CBreadcrumb from '../common/CBreadcrumb'
import {getUploadActionUrl, bytesToSize, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll} from 'educoder';
@ -26,17 +26,18 @@ class BoardsNew extends Component{
this.state = {
fileList: [],
boards: []
boards: [],
title_num: 60
}
}
componentDidMount = () => {
const topicId = this.props.match.params.topicId
addSuccess = () => {
this.fetchBoards()
}
fetchBoards = () => {
const isEdit = this.isEdit
const boardId = this.props.match.params.boardId
const boardsUrl = `/courses/board_list.json?board_id=${boardId}`
const isEdit = !!topicId
const boardsUrl = `/courses/board_list.json?board_id=${boardId}`
axios.get(boardsUrl, { })
.then((response) => {
if (response.data.status == 0) {
@ -57,8 +58,17 @@ class BoardsNew extends Component{
.catch(function (error) {
console.log(error);
});
}
componentDidMount = () => {
const topicId = this.props.match.params.topicId
const isEdit = !!topicId
this.isEdit = isEdit
const boardId = this.props.match.params.boardId
this.fetchBoards()
if (isEdit) {
const url = `/messages/${topicId}.json`
axios.get(url, {
@ -69,6 +79,7 @@ class BoardsNew extends Component{
if (data) {
this.editTopic = data;
this.props.form.setFieldsValue({
sticky: !!data.sticky,
content: data.content,
subject: data.subject,
select_board_id: data.board_id // TODO 没返回给前端
@ -83,7 +94,8 @@ class BoardsNew extends Component{
status: 'done'
}
})
this.setState({ fileList: _fileList, board_name: data.board_name })
this.setState({ fileList: _fileList, board_name: data.board_name, title_num: 60 - parseInt(data.subject.length) })
}
}
})
@ -218,8 +230,14 @@ class BoardsNew extends Component{
});
}
// 附件相关 ------------ END
changeTitle=(e)=>{
console.log(e.target.value.length);
this.setState({
title_num: 60 - parseInt(e.target.value.length)
})
}
render() {
let { addGroup, fileList, course_id } = this.state;
let { addGroup, fileList, course_id, title_num } = this.state;
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
@ -260,6 +278,12 @@ class BoardsNew extends Component{
return(
<div className="newMain ">
<AddDirModal {...this.props}
title="添加目录"
label="目录名称"
ref="addDirModal"
addSuccess={this.addSuccess}
></AddDirModal>
<style>{`
.courseForm .ant-form {
}
@ -280,20 +304,35 @@ class BoardsNew extends Component{
{ name: this.isEdit ? '帖子编辑' : '帖子新建'}
]}></CBreadcrumb>
<p className="clearfix mt30 mb30">
<p className="clearfix mt20 mb20">
<span className="fl font-24 color-grey-3">{this.isEdit ? "编辑" : "新建"}帖子</span>
<a href="javascript:void(0)" className="color-grey-6 fr font-16 mr2"
onClick={() => this.props.history.goBack()}>
返回
</a>
</p>
{/* notRequired */}
<Form {...formItemLayout} onSubmit={this.handleSubmit}>
<div className="formBlock" style={{paddingBottom: '0px'}}>
<div className="formBlock" style={{paddingBottom: '0px', position: 'relative'}}>
{ isAdmin &&
<React.Fragment>
{getFieldDecorator('sticky', {
valuePropName: 'checked',
})(
isAdmin && <Checkbox style={{ right: '22px',
top: '28px',
position: 'absolute'
}}>置顶</Checkbox>
)}
{/* checkbox 有个边距样式 .ant-checkbox-wrapper + span, */}
<span style={{ "padding-left": 0, "padding-right": 0 }}></span>
</React.Fragment>
}
<Form.Item
label="标题"
className="topicTitle "
>
{getFieldDecorator('subject', {
rules: [{
required: true, message: '请输入标题',
@ -301,7 +340,8 @@ class BoardsNew extends Component{
max: 60, message: '最大限制为60个字符',
}],
})(
<Input placeholder="请输入帖子标题最大限制60个字符" />
<Input placeholder="请输入帖子标题最大限制60个字符" className="searchViewAfter" maxLength="60"
onInput={this.changeTitle} addonAfter={String(title_num)} />
)}
</Form.Item>
@ -312,7 +352,17 @@ class BoardsNew extends Component{
{getFieldDecorator('select_board_id', {
// initialValue: '3779',
})(
<Select style={{ width: 230 }}>
<Select style={{ width: 230 }}
dropdownRender={menu => (
<div>
{menu}
<Divider style={{ margin: '4px 0' }} />
<div style={{ padding: '8px', cursor: 'pointer' }} onMouseDown={() => this.refs['addDirModal'].open()}>
<Icon type="plus" /> 添加目录
</div>
</div>
)}
>
{this.state.boards.map(item => {
return (
<Option value={item.id}>{item.name}</Option>
@ -322,7 +372,7 @@ class BoardsNew extends Component{
)}
</Form.Item>
{ isAdmin && <Form.Item
{/* { isAdmin && <Form.Item
label=""
style={{ display: 'inline-block', marginLeft: "14px" }}
>
@ -330,7 +380,7 @@ class BoardsNew extends Component{
})(
<Checkbox>置顶</Checkbox>
)}
</Form.Item> }
</Form.Item> } */}
</div>
<style>{`
@ -355,6 +405,7 @@ class BoardsNew extends Component{
<Form.Item
label="内容"
className="mdInForm"
>
{getFieldDecorator('content', {
rules: [{

@ -24,7 +24,7 @@ import '../../forums/RightSection.css'
import './TopicDetail.css'
import '../common/courseMessage.css'
import { Pagination, Tooltip } from 'antd'
import { bytesToSize, ConditionToolTip } from 'educoder'
import { bytesToSize, ConditionToolTip, markdownToHTML, MarkdownToHtml } from 'educoder'
import SendToCourseModal from '../coursesPublic/modal/SendToCourseModal'
import CBreadcrumb from '../common/CBreadcrumb'
import { generateComments, generateChildComments, _findById, handleContentBeforeCreateNew, addNewComment
@ -87,15 +87,6 @@ class TopicDetail extends Component {
replies_count: response.data.data.total_replies_count
}, {...this.state.memo})
}, () => {
setTimeout(()=>{
var shixunDescr = window.editormd.markdownToHTML("memo_content_editorMd", {
htmlDecode: "style,script,iframe", // you can filter tags decode
taskList: true,
tex: true, // 默认不解析
flowChart: true, // 默认不解析
sequenceDiagram: true // 默认不解析
});
}, 200)
})
// const { memo_replies, memo } = response.data;
@ -181,13 +172,13 @@ class TopicDetail extends Component {
// md渲染content等xhr执行完即memoLoading变化memo.content更新后初始化md
setTimeout(()=>{
var shixunDescr = window.editormd.markdownToHTML("memo_content_editorMd", {
htmlDecode: "style,script,iframe", // you can filter tags decode
taskList: true,
tex: true, // 默认不解析
flowChart: true, // 默认不解析
sequenceDiagram: true // 默认不解析
});
// var shixunDescr = window.editormd.markdownToHTML("memo_content_editorMd", {
// htmlDecode: "style,script,iframe", // you can filter tags decode
// taskList: true,
// tex: true, // 默认不解析
// flowChart: true, // 默认不解析
// sequenceDiagram: true // 默认不解析
// });
}, 200)
}
@ -236,15 +227,30 @@ class TopicDetail extends Component {
// filesize = bytesToSize(item.filesize)
}
attachments.push(
<p className="clearfix" key={index} >
<a href={item.url} className="color-green clearfix notefileDownload">
<i className="iconfont icon-xiazai color-green ml5 fl"></i>
{fileName && <ConditionToolTip title={fileName} condition={fileName.length > 30 }>
<span className="fl task-hide upload_item" style={{ color: '#333'}}>{fileName}</span>
</ConditionToolTip>}
<span className="fl" style={{ color: '#999', marginLeft: '6px'}}>{filesize? ` ${filesize.replace(' ', '')}` : ''}</span>
// <p className="clearfix" key={index} >
// <a href={item.url} className="color-green clearfix notefileDownload">
// <i className="iconfont icon-fujian color-green ml5 fl"></i>
// {fileName && <ConditionToolTip title={fileName} condition={fileName.length > 30 }>
// <span className="fl task-hide upload_item" style={{ color: '#333'}}>{fileName}</span>
// </ConditionToolTip>}
// <span className="fl" style={{ color: '#999', marginLeft: '6px'}}>{filesize? ` ${filesize.replace(' ', '')}` : ''}</span>
// </a>
// </p>
<div className="color-grey df" key={index}>
<a className="color-grey ">
<i className="font-14 color-green iconfont icon-fujian mr8" aria-hidden="true"></i>
</a>
</p>
{/* {fileName && <ConditionToolTip title={fileName} condition={fileName.length > 30 }> </ConditionToolTip>} */}
<a href={item.url} title={fileName.length > 30 ? fileName : ''}
className="mr12 color9B9B overflowHidden1" length="58" style={{maxWidth: '480px'}}>
{fileName}
</a>
<span className="color656565 mt2 color-grey-6 font-12 mr8">{item.filesize}</span>
</div>
)
})
return attachments;
@ -407,9 +413,10 @@ class TopicDetail extends Component {
// md
editor.setValue && editor.setValue('')
const user = this._getUser();
this.setState({
comments: addNewComment(comments, _id, content, user)
comments: addNewComment(comments, _id, content, user, this.props.isSuperAdmin(), this)
})
const newMemo2 = Object.assign({}, this.state.memo);
newMemo2.total_replies_count = newMemo2.total_replies_count + 1;
@ -417,6 +424,7 @@ class TopicDetail extends Component {
memo: newMemo2
})
this.refs.editor.showEditor();
this.refs.editor.close();
}
@ -518,13 +526,24 @@ class TopicDetail extends Component {
const courseId=this.props.match.params.coursesId;
const boardId = this.props.match.params.boardId
return (
<div className="edu-back-white edu-class-container edu-position course-message" id="forum_index_list"> {/* fl with100 */}
<div className="edu-back-white edu-class-container edu-position course-message topicDetail" id="forum_index_list"> {/* fl with100 */}
<style>{`
.topicDetail #forum_list .return_btn.no_mr {
margin-right: 1px;
}
/* 有内容时,编辑器下方的边框*/
.topicDetail .borderBottom.commentInputs {
border-bottom: 1px solid rgb(238, 238, 238);
}
.independent {
background: rgb(250, 250, 250);
padding-bottom: 20px;
margin-bottom: 0px !important;
}
.course-message.topicDetail .panel-comment_item .comment_orig_content {
width: 1072px;
}
`}</style>
<CBreadcrumb className={'independent'} items={[
{ to: `/courses/${courseId}`, name: this.props.coursedata.name},
@ -551,7 +570,7 @@ class TopicDetail extends Component {
</span> }
{/* || current_user.user_id === author_info.user_id */}
{ current_user && (isAdmin || isCurrentUserTheAuthor) &&
<div className="edu-position-hidebox" style={{position: 'absolute', right: '18px',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>
<ul className="edu-position-hide undis">
@ -628,15 +647,12 @@ class TopicDetail extends Component {
</div>
<div className="padding40 memoContent new_li">
<div id="memo_content_editorMd" className="new_li">
<textarea style={{'display': 'none'}}>
{memo.content}
</textarea>
</div>
<div className="padding30 memoContent new_li" style={{ paddingBottom: '10px'}}>
{memo.is_md == true ? <MarkdownToHtml content={memo.content}></MarkdownToHtml> :
<div dangerouslySetInnerHTML={{ __html: memo.content }}></div>
}
</div>
{/* style={{ paddingTop: '0px'}} */}
<div className="padding40 bor-bottom-greyE" >
<div className="padding30 bor-bottom-greyE" style={{paddingTop: '2px'}}>
<div className="mt10 mb20">
{/* ${memo.user_praise ? '' : ''} */}
<Tooltip title={`${memo.liked ? '取消点赞' : '点赞'}`}>
@ -655,16 +671,16 @@ class TopicDetail extends Component {
</div>
<MemoDetailMDEditor ref="editor" memo={memo} usingMockInput={true} placeholder="说点什么"
height={160} showError={true} buttonText={'发表'}></MemoDetailMDEditor>
height={160} showError={true} buttonText={'发表'} className={comments && comments.length && 'borderBottom'}></MemoDetailMDEditor>
{/* onClick={ this.createNewComment }
enableReplyTo={true}
*/}
<div className="padding40 bor-bottom-greyE memoReplies commentsDelegateParent comments_hideSecondReplyUserHeader"
style={{ display: (comments && !!comments.length) ? 'block' : 'none' }}>
<div className="padding20 memoReplies commentsDelegateParent comments_hideSecondReplyUserHeader"
style={{ display: (comments && !!comments.length) ? 'block' : 'none', paddingBottom: '0px' }}>
<div className="replies_count">
<span className="labal">全部回复</span>
<span className="count">{memo.total_replies_count}</span>
<span className="labal font-16">全部回复</span>
<span className="count font-16">({memo.total_replies_count})</span>
</div>
<Comments comments={comments} user={current_user}
@ -691,11 +707,13 @@ class TopicDetail extends Component {
</div>} */}
</div>
{ total_count > REPLY_PAGE_COUNT &&
<div className="memoMore">
<Pagination showQuickJumper onChange={this.onPaginationChange} current={pageCount} total={total_count} pageSize={10}/>
<div className="memoMore" style={{'margin-top': '20px'}}>
{ total_count > REPLY_PAGE_COUNT &&
<Pagination showQuickJumper onChange={this.onPaginationChange} current={pageCount} total={total_count} pageSize={10}/>
}
<div className="writeCommentBtn" onClick={this.showCommentInput}>写评论</div>
</div> }
</div>
</div>
</div>

@ -218,6 +218,9 @@ class Boards extends Component{
}
onPressEnter = (e) => {
clearTimeout(this.timeoutHandler)
this.timeoutHandler = null;
this.fetchAll(this.state.searchValue, 1)
}
onInputSearchChange = (e) => {
@ -227,6 +230,7 @@ class Boards extends Component{
if (this.timeoutHandler) {
clearTimeout(this.timeoutHandler)
this.timeoutHandler = null;
}
this.timeoutHandler = setTimeout(() => {
this.fetchAll(this.state.searchValue, 1)
@ -345,7 +349,7 @@ class Boards extends Component{
<React.Fragment>
{ isAdmin && !parent_id && <WordsBtn style="blue" className="mr30" onClick={()=>this.addDir()}>添加目录</WordsBtn> }
{ isAdmin && !!parent_id && <WordsBtn style="blue" className="mr30" onClick={()=>this.renameDir()}>目录重命名</WordsBtn> }
{ isAdminOrStudent && <WordsBtn style="blue" className="" onClick={()=>this.onToBoardsNew()}>我要发</WordsBtn> }
{ isAdminOrStudent && <WordsBtn style="blue" className="" onClick={()=>this.onToBoardsNew()}>我要发</WordsBtn> }
</React.Fragment>
}
secondRowLeft={
@ -359,7 +363,7 @@ class Boards extends Component{
<FilesListItem></FilesListItem> */}
<div className="mt20 edu-back-white padding20-30">
{isAdmin && <div className="mt20 edu-back-white padding20-30">
<div className="clearfix">
{isAdmin && <Checkbox className="fl" onChange={this.onCheckAll} checked={checkAllValue}>已选 {checkBoxValues.length} </Checkbox>}
<div className="studentList_operation_ul">
@ -406,6 +410,7 @@ class Boards extends Component{
</div>
</div>
</div>
}
<style>{`
.panel-inner-fourm {
border-bottom: none;
@ -423,7 +428,7 @@ class Boards extends Component{
<BoardsListItem
{...this.props}
discussMessage={item}
checkBox={ isAdmin ? <Checkbox value={item.id}></Checkbox> : ''}
checkBox={ isAdmin ? <Checkbox value={item.id} key={item.id}></Checkbox> : ''}
onItemClick={this.onItemClick}
onSticky={this.onSticky}
></BoardsListItem>
@ -446,7 +451,9 @@ class Boards extends Component{
</Tooltip>
</a>
</p> } */}
{pagination.total_count > 15 && <Pagination className="coursePagination" showQuickJumper pageSize={15} total={pagination.total_count} onChange={this.onPageChange} />}
{pagination.total_count > 15 && <Pagination className="coursePagination"
current={pagination.page}
showQuickJumper pageSize={15} total={pagination.total_count} onChange={this.onPageChange} />}
</React.Fragment>
)

@ -86,7 +86,7 @@ class CommonWorkAnswer extends Component{
{/* 内容区 */}
<div className="padding40 memoContent new_li">
{reference_answer ? <MarkdownToHtml content={reference_answer || "还未设置答案。"}></MarkdownToHtml> :
reference_answer === undefined ? '' : <NoneData></NoneData>}
reference_answer === undefined ? '' : ((!attachments || attachments.length == 0) && <NoneData></NoneData>)}
{ attachments && attachments.map((item) => {
return ( <div className="color-grey">

@ -13,6 +13,9 @@ import CheckCodeModal from '../coursesPublic/modal/CheckCodeModal'
import '../css/Courses.css'
import WorkDetailPageHeader from './common/WorkDetailPageHeader'
import CommonWorkAppraiseReply from './reply/CommonWorkAppraiseReply'
import Example from './TestHooks'
import CommonWorkAppraiseReviseAttachments from './CommonWorkAppraiseReviseAttachments'
const { Option} = Select;
const CheckboxGroup = Checkbox.Group;
const confirm = Modal.confirm;
@ -174,17 +177,23 @@ class CommonWorkAppraise extends Component{
modalSave={ModalSave}
loadtype={loadtype}
/>
{/* 内容区 */}
{/* <div className="padding40 memoContent new_li">
</div> */}
<div className={" "} style={{}}>
{(description || (attachments && attachments.length != 0)) && <div className={"stud-class-set bor-bottom-greyE edu-back-white"} style={{ padding: '20px 20px 20px 20px'}}>
<div className={"color-grey-6 h20 mb20 font-16"}>
<div className={"appraise imageLayerParent "} style={{}}>
<style>{`
.workAppraise>div:last-child {
border-bottom: none !important;
}
`}</style>
<div className={"workAppraise"}>
{(description || (attachments && attachments.length != 0)) && <div className={"stud-class-set edu-back-white padding20-30"}>
<div className={"color-grey-6 mb15 font-16"}>
内容
</div>
<div className={"ml20"} className="markdown-body" dangerouslySetInnerHTML={{__html: markdownToHTML(description)}}>
<div className="markdown-body ml20" dangerouslySetInnerHTML={{__html: markdownToHTML(description)}}>
</div>
{attachments.map((item,key)=>{
@ -193,8 +202,9 @@ class CommonWorkAppraise extends Component{
<a className="color-grey ml20">
<i className="font-14 color-green iconfont icon-fujian mr8" aria-hidden="true"></i>
</a>
<a href={item.url}
className="mr12 color9B9B" length="58">
className="mr12 color9B9B imageTarget" length="58" title={`${item.title && item.title.length > 40 ? item.title : ''}`}>
{item.title}
</a>
<span className="color656565 mt2 color-grey-6 font-12 mr8">{item.filesize}</span>
@ -209,7 +219,7 @@ class CommonWorkAppraise extends Component{
{ update_time &&
<React.Fragment>
<span className={"color9B9B fr"}>更新</span>
<span className={"fr font-13 mr10 ml10"}>{update_user_name}</span>
<span className={"fr font-14 mr10 ml10"}>{update_user_name}</span>
<span className={"color9B9B fr"}>
{moment(update_time).format('YYYY-MM-DD HH:mm')==="Invalid date"?"":moment(update_time).format('YYYY-MM-DD HH:mm')}
</span>
@ -218,7 +228,7 @@ class CommonWorkAppraise extends Component{
{ commit_time &&
<React.Fragment>
<span className={"color9B9B fr mr30"}>提交</span>
<span className={"fr font-13 mr10 ml10"}>{author_name}</span>
<span className={"fr font-14 mr10 ml10"}>{author_name}</span>
<span className={" color9B9B fr"}>
{moment(commit_time).format('YYYY-MM-DD HH:mm')==="Invalid date"?"":moment(commit_time).format('YYYY-MM-DD HH:mm')}
</span>
@ -227,46 +237,10 @@ class CommonWorkAppraise extends Component{
</div> }
{revise_attachments.length===0?"":<div className={"stud-class-set bor-bottom-greyE pd20 edu-back-white"}>
<style>{`
.color-grey:hover i {
display: inline !important;
}
`}</style>
<div className={"color-grey-6 mb10 font-16"}>
补交附件
</div>
<div className={"ml20"}>
{revise_reason}
</div>
{revise_attachments.map((item,key)=>{
return(
<div className="color-grey" key={key}>
<a className="color-grey ml20">
<i className="font-14 color-green iconfont icon-fujian mr8" aria-hidden="true"></i>
</a>
<a href={item.url}
className="mr12 color9B9B" length="58">
{item.title}
</a>
<span className="color656565 mt2 color-grey-6 font-12 mr8">{item.filesize}</span>
{item.delete===true?<i className="font-14 iconfont icon-guanbi " style={{display: 'none'}} id={item.id} aria-hidden="true" onClick={()=>this.onAttachmentRemove(item.id)}></i>:""}
</div>
)
})}
<div className={"color-grey-6 h20 ml20"}>
<span className={"color9B9B fr mr10"}>更新</span>
<span className={"fr font-13 mr10 ml10"}>{atta_update_user}</span>
<span className={"color9B9B fr"}>
{moment(atta_update_time).format('YYYY-MM-DD HH:mm')==="Invalid date"?"":moment(atta_update_time).format('YYYY-MM-DD HH:mm')}
</span>
</div>
</div>}
<CommonWorkAppraiseReviseAttachments {...this.state}></CommonWorkAppraiseReviseAttachments>
{is_evaluation != true && project_info && project_info.name && <div className={"stud-class-set bor-bottom-greyE edu-back-white"} style={{ padding: '18px 20px 20px 20px'}}>
<div className={"color-grey-6 h20 mb20"}>
{is_evaluation != true && project_info && project_info.name && <div className={"stud-class-set bor-top-greyE edu-back-white padding20-30"}>
<div className={"color-grey-6 mb10"}>
关联项目
</div>
<div className={"ml20"}>
@ -275,8 +249,8 @@ class CommonWorkAppraise extends Component{
</div>
}
{is_evaluation != true && work_members && !!work_members.length && <div className={"stud-class-set bor-bottom-greyE edu-back-white"} style={{ padding: '18px 20px 20px 20px'}}>
<div className={"color-grey-6 h20 mb20"}>
{is_evaluation != true && work_members && !!work_members.length && <div className={"stud-class-set bor-top-greyE edu-back-white padding20-30"}>
<div className={"color-grey-6 mb10"}>
其他组员
</div>
<div className={"ml20"}>
@ -286,6 +260,7 @@ class CommonWorkAppraise extends Component{
</div>
</div>
}
</div>
{/* task_type={datalist&&datalist.task_type} */}

@ -0,0 +1,52 @@
import React, { useState } from 'react'
import moment from 'moment'
// import Example from './TestHooks'
function CommonWorkAppraiseReviseAttachments(props) {
const { revise_attachments, revise_reason, atta_update_time, atta_update_user} = props
if (!revise_attachments) return ''
return (
<React.Fragment>
{/* {Example()} */}
{revise_attachments.length===0?"":<div className={"stud-class-set bor-top-greyE padding20-30 edu-back-white"}>
<style>{`
.color-grey:hover i {
display: inline !important;
}
`}</style>
<div className={"color-grey-6 mb10 font-16"}>
补交附件
</div>
{/* {age} */}
<div className={"ml20"}>
{revise_reason}
</div>
{revise_attachments.map((item,key)=>{
return(
<div className="color-grey" key={key}>
<a className="color-grey ml20">
<i className="font-14 color-green iconfont icon-fujian mr8" aria-hidden="true"></i>
</a>
<a href={item.url}
className="mr12 color9B9B imageTarget" length="58">
{item.title}
</a>
<span className="color656565 mt2 color-grey-6 font-12 mr8">{item.filesize}</span>
{item.delete===true?<i className="font-14 iconfont icon-guanbi " style={{display: 'none'}} id={item.id} aria-hidden="true" onClick={()=>this.onAttachmentRemove(item.id)}></i>:""}
</div>
)
})}
<div className={"color-grey-6 clearfix lineh-25 ml20"}>
<span className={"color9B9B fr"}>更新</span>
<span className={"fr font-13 mr10 ml10"}>{atta_update_user}</span>
<span className={"color9B9B fr"}>
{moment(atta_update_time).format('YYYY-MM-DD HH:mm')==="Invalid date"?"":moment(atta_update_time).format('YYYY-MM-DD HH:mm')}
</span>
</div>
</div>}
</React.Fragment>
)
}
export default CommonWorkAppraiseReviseAttachments;

@ -8,15 +8,15 @@ import { CNotificationHOC } from '../common/CNotificationHOC'
import { RouteHOC } from './common'
import locale from 'antd/lib/date-picker/locale/zh_CN';
import { WordsBtn, MarkdownToHtml, trigger } from 'educoder';
import { WordsBtn, MarkdownToHtml, trigger, queryString } from 'educoder';
import axios from 'axios';
import Modals from '../../modals/Modals';
import CoursesListType from '../coursesPublic/CoursesListType';
import AccessoryModal from "../coursesPublic/AccessoryModal";
import PublishRightnow from './PublishRightnow'
import '../css/Courses.css'
import CBreadcrumb from '../common/CBreadcrumb'
import DownloadMessageysl from "../../modals/DownloadMessageysl";
//引入对应跳转的组件
@ -62,7 +62,8 @@ class CommonWorkDetailIndex extends Component{
this.publishModal = React.createRef();
this.endModal = React.createRef();
this.state = {
DownloadType:false,
DownloadMessageval:undefined,
}
}
initWorkDetailCommonState = (data) => {
@ -99,6 +100,45 @@ class CommonWorkDetailIndex extends Component{
doWhenSuccess = () => {
trigger('commonwork_fetch_all')
}
/// 确认是否下载
confirmysl(url){
axios.get(url).then((response) => {
if(response.data.status&&response.data.status===-1){
}else if(response.data.status&&response.data.status===-2){
if(response.data.message === "100"){
// 已超出文件导出的上限数量100 ),建议:
this.setState({
DownloadType:true,
DownloadMessageval:100
})
}else {
//因附件资料超过500M
this.setState({
DownloadType:true,
DownloadMessageval:500
})
}
}else {
this.props.showNotification(`正在下载中`);
window.open("/api"+url, '_blank');
}
}).catch((error) => {
console.log(error)
});
}
Downloadcal=()=>{
this.setState({
DownloadType:false,
DownloadMessageval:undefined
})
}
render() {
let {course_name, homework_name, homework_status, noTab
, view_answer, author_name, category, work_id
@ -108,6 +148,8 @@ class CommonWorkDetailIndex extends Component{
let courseId=this.props.match.params.coursesId;
let category_id= category && category.category_id;
let category_name= category && category.category_name;
let workId=this.props.match.params.workId;
const studentWorkId = this.props.match.params.studentWorkId
@ -121,17 +163,33 @@ class CommonWorkDetailIndex extends Component{
}
const isAdmin = this.props.isAdmin()
let exportUrl = `/api/homework_commons/${workId}/works_list.zip`
const exportResultUrl = `/api/homework_commons/${workId}/works_list.xlsx`
let exportParams = {}
const isListModule = childModuleName == '作品列表';
// 是列表页
let params = {}
if (isListModule) {
// TODO
// params = this.refs.commonWorkList._getRequestParams()
}
let exportUrl = `/homework_commons/${workId}/works_list.zip?${queryString.stringify(params)}`
let exportResultUrl = `/homework_commons/${workId}/works_list.xlsx?${queryString.stringify(params)}`
return (
<div>
<PublishRightnow ref={this.publishModal} showActionButton={false} {...this.props} checkBoxValues={[workId]}
isPublish={true} doWhenSuccess={this.doWhenSuccess} checkBeforePost={this.saveWorkSetting}
onToPublishClick={this.onToPublishClick}
></PublishRightnow>
<DownloadMessageysl
{...this.props}
value={this.state.DownloadMessageval}
modalCancel={this.Downloadcal}
modalsType={this.state.DownloadType}
/>
<PublishRightnow ref={this.endModal} showActionButton={false} {...this.props} checkBoxValues={[workId]}
isPublish={false} doWhenSuccess={this.doWhenSuccess}></PublishRightnow>
<div className="newMain clearfix worklist1">
<div className={"educontent mt20"}>
<style>{`
@ -141,7 +199,7 @@ class CommonWorkDetailIndex extends Component{
`}</style>
<CBreadcrumb items={[
{ to: `/courses/${courseId}`, name: course_name},
{ to: `/courses/${courseId}/${moduleEngName}/${category_id}`, name: moduleName },
{ to: `/courses/${courseId}/${moduleEngName}/${category_id}`, name: category_name },
window.location.pathname.indexOf('appraise') == -1 ? { } : { to: `/courses/${courseId}/${moduleEngName}/${workId}/list`, name: '作业详情' },
// 1. 与上一条联动当匿评他人作品时TA人作品的作者真实姓名切换为“匿名”
window.location.pathname.indexOf('appraise') == -1 ? { name: '作业详情' } : { name: author_name },
@ -150,7 +208,9 @@ class CommonWorkDetailIndex extends Component{
]}></CBreadcrumb>
<div style={{ width:'100%',height:'52px'}} >
<span className=" fl color-black summaryname">
<span className=" fl color-black summaryname" title={`${homework_name && homework_name.length > 36 ? homework_name : ''}`}
style={{height: 'auto'}}
>
{homework_name}
{/* <Link to={"/courses/"+courseId+"/graduation"+"/graduation_tasks/"}>{homework_name}</Link> */}
</span>
@ -187,7 +247,7 @@ class CommonWorkDetailIndex extends Component{
<div className="mt10 clearfix edu-back-white poll_list pl5">
<Link
onClick={() => this.setState({moduleName: '作品列表'})}
className={`${childModuleName == '作品列表' ? 'active' : '' } `}
className={`${isListModule ? 'active' : '' } `}
to={`/courses/${courseId}/${moduleEngName}/${workId}/list`}>作品列表</Link>
<Link
onClick={() => this.setState({moduleName: '作业问答'})}
@ -226,8 +286,12 @@ class CommonWorkDetailIndex extends Component{
{this.props.isAdmin()? <li className="li_line drop_down fr color-blue font-16 mr8 mt20" style={{"padding":"0 20px"}}>
导出<i className="iconfont icon-xiajiantou font-12 ml2"></i>
<ul className="drop_down_menu" style={{"right":"-34px","left":"unset","height":"auto"}}>
<li><a href={exportResultUrl} calssName="color-dark">导出成绩</a></li>
<li><a href={exportUrl} calssName="color-dark">导出作品附件</a></li>
<li><a href={"javascript:void(0)"} className="color-dark"
onClick={() => this.confirmysl(exportResultUrl, exportParams)}
>导出成绩</a></li>
<li><a href={"javascript:void(0)"} className="color-dark"
onClick={() => this.confirmysl(exportUrl, exportParams)}
>导出作品附件</a></li>
</ul>
</li>:""}
@ -243,6 +307,12 @@ class CommonWorkDetailIndex extends Component{
{work_statuses && work_statuses.indexOf('提交作品') != -1 && <a className={"fr color-blue font-16"} href={"javascript:void(0)"}
onClick={() => { this.props.toWorkPostPage(this.props.match.params)}}
>提交作品</a>}
{ work_statuses && work_statuses.indexOf('补交作品') != -1 &&
<a className={"fr color-blue font-16"} href={"javascript:void(0)"}
onClick={() => { this.props.toWorkPostPage(this.props.match.params, null, true, work_id)}}>
补交作品</a> }
{work_statuses && work_statuses.indexOf('修改作品') != -1 && <a className={"fr color-blue font-16"} href={"javascript:void(0)"}
onClick={() => { this.props.toWorkPostPage(this.props.match.params, null, true, work_id)}}
>修改作品</a>}
@ -285,7 +355,7 @@ class CommonWorkDetailIndex extends Component{
{/* 作品列表 */}
<Route exact path="/courses/:coursesId/common_homeworks/:workId/list"
render={
(props) => (<CommonWorkList {...this.props} {...props} {...this.state} {...commonHandler}/>)
(props) => (<CommonWorkList ref="commonWorkList" {...this.props} {...props} {...this.state} {...commonHandler}/>)
}
></Route>

@ -8,7 +8,6 @@ import { WordsBtn } from 'educoder'
import AccessoryModal2 from '../coursesPublic/AccessoryModal2'
import AccessoryModal from '../coursesPublic/AccessoryModal'
import axios from 'axios'
import ConnectProject from './ConnectProject'
class CommonWorkItem extends Component{
constructor(props){
super(props);
@ -17,7 +16,12 @@ class CommonWorkItem extends Component{
}
}
onItemClick = (item) => {
this.props.toWorkListPage(this.props.match.params, item.homework_id)
const isStudent = this.props.isStudent()
if (isStudent) {
this.props.toWorkQuestionPage(this.props.match.params, item.homework_id)
} else {
this.props.toWorkListPage(this.props.match.params, item.homework_id)
}
}
sendMoreAttachment = (item) => {
this.handleItem = item;
@ -104,6 +108,7 @@ class CommonWorkItem extends Component{
let coursesId = this.props.match.params.coursesId;
const isStudent = this.props.isStudent()
const isAdmin = this.props.isAdmin()
const isAdminOrStudent = this.props.isAdminOrStudent()
return(
<div className="workList">
@ -127,20 +132,21 @@ class CommonWorkItem extends Component{
}
</style>
{
mainList && mainList.homeworks.length>0 && mainList.homeworks.map((item,index)=>{
mainList && mainList.homeworks && mainList.homeworks.length>0 && mainList.homeworks.map((item,index)=>{
let canNotLink = !isAdminOrStudent && item.private_icon == true
return(
<div className="mt20 edu-back-white padding02010" key={index} >
<div className="clearfix">
<div className="workList_Item">
{
mainList && mainList.course_identity < 5 &&
<span className="fl mr12"><Checkbox value={item.homework_id}></Checkbox></span>
mainList && isAdmin &&
<span className="fl mr12"><Checkbox value={item.homework_id} key={item.homework_id}></Checkbox></span>
}
<div className="flex1" onClick={() => this.props.onItemClick(Object.assign({}, item, {id: item.homework_id})) }>
<p className="clearfix mb20">
<a title={item.name}
className="fl font-16 font-bd mt2 comnonwidth580"
onClick={() => this.onItemClick(item)}
className="fl font-16 font-bd mt2 comnonwidth580" style={{cursor: canNotLink ? 'default' : 'poninter'}}
onClick={ canNotLink ? () => {} : () => this.onItemClick(item)}
>{item.name}</a>
{/* 只有非课堂成员且作业是私有的情况下才会为true */}
@ -154,8 +160,8 @@ class CommonWorkItem extends Component{
<span className="fl">
<CoursesListType typelist={item.status} />
</span>
{
mainList && mainList.course_identity < 5 &&
{/* {
mainList && isAdmin &&
<li className="fr drop_down">
<i className="iconfont icon-caidan font-16 color-grey-c"></i>
<ul className="drop_down_normal" style={{ textAlign: 'center'}}>
@ -168,7 +174,7 @@ class CommonWorkItem extends Component{
</li>
</ul>
</li>
}
} */}
</p>
<p className="color-grey-9 clearfix">
{item.commit_count===undefined?"":<span className="mr20 fl">{item.commit_count} 已交</span>}
@ -177,23 +183,40 @@ class CommonWorkItem extends Component{
item.status_time!="" &&
<Tooltip title={ item.status.indexOf('提交中') != -1 ? '提交剩余时间' :
item.status.indexOf('补交中') != -1 ? '补交剩余时间' :
item.status.indexOf('申诉中') != -1 ? '申诉剩余时间' :
item.status.indexOf('匿评中') != -1 ? '匿评剩余时间' :
item.status.indexOf('匿评申诉中') != -1 ? '匿评申诉剩余时间' : ''}>
<span className="mr20 fl">{item.status_time}</span>
</Tooltip>
}
{isAdmin && <div className="fr">
<WordsBtn style="blue" className="fl font-16 ml28" onClick={ () => { this.props.toEditPage(this.props.match.params, item.homework_id) }}>编辑</WordsBtn>
<WordsBtn style="blue" className="fl font-16 ml28" onClick={ () => { this.props.toWorkSettingPage(this.props.match.params, item.homework_id) }}>设置</WordsBtn>
</div>}
{
//
isStudent &&
<li className="fr">
{ //
item.work_status && item.work_status.indexOf('关联项目') != -1 &&
<ConnectProject className="fl" {...this.props} work={item}></ConnectProject>
<React.Fragment>
<WordsBtn style="blue" className={` font-16 fl`} onClick={() => this.props.toCreateProject(item)}>创建项目</WordsBtn>
<WordsBtn style="blue" className={` font-16 fl ml28`} onClick={() => this.props.openConnectionProject(item)}>关联项目</WordsBtn>
</React.Fragment>
}
{ //
item.work_status && item.work_status.indexOf('取消关联') != -1 &&
<WordsBtn style="blue" className={` font-16 fl`} onClick={() => this.props.cancelConnectionProject(item)}>取消关联</WordsBtn>
}
{ //
item.work_status && item.work_status.indexOf('提交作品') != -1 &&
<WordsBtn style="blue" className="fl font-16 ml28" onClick={() => this.props.toWorkPostPage(this.props.match.params, item.homework_id)}>提交作品</WordsBtn>
}
{
//
item.work_status && item.work_status.indexOf('补交作品') != -1 &&

@ -1,5 +1,5 @@
import React,{Component} from "React";
import { Form, Select, Input, Button,Checkbox,Upload,Icon,message,Modal, Table, Divider, Tag,DatePicker,Radio,Tooltip,Spin} from "antd";
import { Form, Select, Input, Button,Checkbox,Upload,Icon,message,Modal, Table, Divider, Tag,DatePicker,Radio,Tooltip,Spin, Pagination} from "antd";
import {Link} from 'react-router-dom';
import locale from 'antd/lib/date-picker/locale/zh_CN';
import { WordsBtn, ConditionToolTip, queryString,getImageUrl, on, off} from 'educoder';
@ -31,25 +31,37 @@ function renderScore(score, content) {
} else if (score >= 60) {
color = '#FF6800'
}
return <a href="javascript:;" style={{ color, minWidth: '30px', display: 'inline-block', textAlign: 'center' }}>{score == '--' ? '--': (content || score)}</a>
return <a href="javascript:;" style={{ color, cursor: 'default', minWidth: '30px', display: 'inline-block', textAlign: 'center' }}>
{score == null || score == undefined || score == '--' ? '--': (content || score)}
</a>
}
function getScoreTip(score, dom) {
return score == '--' ? '未评分' : score == '**' ? '未公开' : dom
}
function buildColumns(that, student_works) {
let gotWorkGroup = false;
let gotProjectInfo = false;
if (student_works) {
student_works.forEach(item => {
if (item.work_group) {
gotWorkGroup = true
}
if (item.project_info && item.project_info.name) {
gotProjectInfo = true;
}
})
}
let courseId= that.props.match.params.coursesId;
let workId= that.props.match.params.workId;
const { course_group_count } = that.state;
const { course_group_count, homework_status } = that.state;
const isAdmin = that.props.isAdmin()
const isAdminOrStudent = that.props.isAdminOrStudent()
const isStudent = that.props.isStudent()
const isNiPing = homework_status && homework_status.indexOf('匿评中') != -1
const isAppeal = homework_status && homework_status.indexOf('申诉中') != -1
// https://www.trustie.net/issues/21450 分组作业作品列表 学时视角,匿评阶段的列表显示信息不正确
const niPingAndIsStudent = isStudent && (isNiPing || isAppeal)
let columns = [{
width: 60,
title: '序号',
@ -57,40 +69,52 @@ function buildColumns(that, student_works) {
key: 'id',
render: (text, record, index) => {
return (
<span style={{ minWidth: '50px', display: 'inline-block', textAlign: 'center' }} >{(that.state.page - 1) * PAGE_SIZE + index + 1}</span>
<span style={{ minWidth: '50px', display: 'inline-block', textAlign: 'center' }} >
{record.isMine == true && (student_works && student_works.length) ? '我' : (that.state.page - 1) * PAGE_SIZE + index + 1}
</span>
)},
}, {
title: '姓名',
width: 90,
dataIndex: 'user_name',
key: 'user_name',
// width: '110px',
render: (text, record) => (
<div style={{
width: '110px',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}}>
<Tooltip placement="bottom" title={text}>
whiteSpace: 'nowrap',
width: '98px',
margin: '0 auto'
}} title={text}>
{/* <Tooltip placement="bottom" title={text}>
</Tooltip> */}
{text}
</Tooltip>
</div>
),
}, {
width: 180,
title: '学号',
dataIndex: 'student_id',
key: 'student_id',
render: (text, record) => (
<span>
<a href="javascript:;" style={{color:'#9A9A9A'}}>{record.student_id}</a>
</span>
),
}]
if (!niPingAndIsStudent && isAdminOrStudent) {
columns.push({
width: 88,
title: '学号',
dataIndex: 'student_id',
key: 'student_id',
render: (text, record) => (
<span>
<a href="javascript:;"
title={record.student_id}
style={{color:'#9A9A9A', 'text-overflow': 'ellipsis', 'white-space': 'nowrap', 'width': '100px', display: 'block', overflow: 'hidden'
, margin: '0 auto', cursor: 'default'}}
>{record.student_id}</a>
</span>
),
})
}
// TODO 只有有分班时才显示分班列
if (course_group_count != 0) {
if (course_group_count != 0 && !niPingAndIsStudent) {
columns.push( {
title: '分班',
key: 'group_name',
@ -98,12 +122,12 @@ function buildColumns(that, student_works) {
render: (text, record) => (
<span>
<a href="javascript:;" style={{color:'#9A9A9A'}}>{record.group_name}</a>
<a href="javascript:;" style={{color:'#9A9A9A', cursor: 'default'}}>{record.group_name}</a>
</span>
),
} )
}
if (gotWorkGroup) {
if (gotWorkGroup && !niPingAndIsStudent) {
columns.push({
width: 72,
title: '分组',
@ -117,6 +141,22 @@ function buildColumns(that, student_works) {
),
})
}
if (gotProjectInfo) {
columns.push({
width: 72,
title: '关联项目',
dataIndex: 'project_info',
key: 'project_info',
render: (project_info, record) => (
<span>
{project_info && project_info.name && <a href={`/projects/${project_info.id}`} target="_blank"
className="overflowHidden1" style={{color:'#4CACFF', width: '80px', margin: '0 auto', display: 'block'}} title={project_info.name}
>{project_info.name}</a>}
</span>
),
})
}
columns = columns.concat([{
width: 88,
title: '提交状态',
@ -138,61 +178,68 @@ function buildColumns(that, student_works) {
}
return (
<span>
<a href="javascript:;" style={{color: color}}>
<a href="javascript:;" style={{color: color, cursor: 'default'}}>
{status === 0 ? "未提交" : status === 1 ? "按时提交" : status === 2 ? "延时提交" : ""}
</a>
</span>
)},
}, {
width: 133,
width: 150,
title: '更新时间',
dataIndex: 'update_time',
key: 'update_time',
render: (update_time, record) => (
<span>
<a href="javascript:;" style={{color:'#989898'}}>{update_time ? moment(update_time).format('YYYY-MM-DD hh:mm') : '--'}</a>
<a href="javascript:;" style={{color:'#989898', cursor: 'default'}}>{update_time ? moment(update_time).format('YYYY-MM-DD HH:mm') : '--'}</a>
</span>
),
}, {
width: 72,
title: '教师评分',
key: 'teacher_score',
dataIndex: 'teacher_score',
render: (teacher_score, record) => (
<Tooltip title={ getScoreTip(teacher_score, teacher_score) }>
}])
if (!niPingAndIsStudent) {
columns.push({
width: 70,
title: '教师评分',
key: 'teacher_score',
dataIndex: 'teacher_score',
render: (teacher_score, record) => (
<Tooltip title={ getScoreTip(teacher_score, teacher_score) }>
<span>
{ renderScore(teacher_score) }
</span>
</Tooltip>
),
})
columns.push({
width: 70,
title: '助教评分',
key: 'teaching_asistant_score',
dataIndex: 'teaching_asistant_score',
/**
* 2名助教进行了评分
平均分85.0
*
*/
render: (teaching_asistant_score, record) => (
<span>
{ renderScore(teacher_score) }
</span>
</Tooltip>
),
}, {
width: 72,
title: '助教评分',
key: 'teaching_asistant_score',
dataIndex: 'teaching_asistant_score',
/**
* 2名助教进行了评分
平均分85.0
*
*/
render: (teaching_asistant_score, record) => (
<span>
{ <Tooltip placement="bottom" title={
getScoreTip(teaching_asistant_score,
<div>
<div>{record.ta_comment_count}名助教进行了评分</div>
<div>{that.state.ta_mode == 1 ? '平均分': '复审分'}{teaching_asistant_score}</div>
</div>) }
>
{renderScore(teaching_asistant_score) }
</Tooltip> }
</span>
),
}])
{ <Tooltip placement="bottom" title={
getScoreTip(teaching_asistant_score,
<div>
<div>{record.ta_comment_count}名助教进行了评分</div>
<div>{that.state.ta_mode == 1 ? '平均分': '复审分'}{teaching_asistant_score}</div>
</div>) }
>
{renderScore(teaching_asistant_score) }
</Tooltip> }
</span>
),
})
}
if (that.state.anonymous_comment) {
/**
@ -202,7 +249,7 @@ function buildColumns(that, student_works) {
*/
columns.push({
width: 84,
title: <div style={{fontWeight:'bold'}}><div style={{fontWeight:'bold'}}>匿评</div></div>,
title: <div style={{color: 'rgba(0,0,0,.85)'}}><div style={{color: 'rgba(0,0,0,.85)'}}>匿评</div></div>,
key: 'student_score',
dataIndex: 'student_score',
@ -210,8 +257,8 @@ function buildColumns(that, student_works) {
<span>
<Tooltip title={
getScoreTip(student_score,
<div>
<div>{`${record.student_comment_count}名学生进行了匿评`}</div>
that.state.is_evaluation ? `你的评阅分数:${record.student_score}` : <div>
{record.student_comment_count && <div>{`${record.student_comment_count}名学生进行了匿评`}</div>}
<div>有效平均分{record.student_score}</div>
</div>
)
@ -225,7 +272,7 @@ function buildColumns(that, student_works) {
if (that.state.anonymous_appeal) {
columns.push({
width: 72,
width: 70,
title: '匿评申诉',
key: 'appeal_all_count',
dataIndex: 'appeal_all_count',
@ -235,43 +282,45 @@ function buildColumns(that, student_works) {
{ !!appeal_all_count &&
<Tooltip placement="bottom" title={`共有${appeal_all_count}条匿评申诉,${record.appeal_deal_count}条待处理`}>
<span style={{ minWidth: '30px', display: 'inline-block', textAlign: 'center' }}>
{`${appeal_all_count}/${record.appeal_deal_count}`}
{`${record.appeal_deal_count}/${appeal_all_count}`}
</span>
</Tooltip> }
{ !appeal_all_count && <span style={{ color: '#747A7F' }}>-/-</span>}
</span>
),
})
}
columns.push({
width: 72,
title: '最终成绩',
key: 'work_score',
dataIndex: 'work_score',
render: (work_score, record) => {
return (
<span>
<Tooltip title={
getScoreTip(work_score,
<div>
<div>{`${record.user_name}${record.user_login}`}</div>
{ record.ultimate_score ?
<div>最终调整成绩{record.work_score}</div> :
if (!niPingAndIsStudent) {
columns.push({
width: 70,
title: '最终成绩',
key: 'work_score',
dataIndex: 'work_score',
render: (work_score, record) => {
return (
<span>
<Tooltip title={
getScoreTip(work_score,
<div>
{ record.final_score && <div>作业评分{record.final_score}</div> }
{ !!that.state.late_penalty && <div>迟交扣分{that.state.late_penalty}</div>}
{ !!that.state.absence_penalty && <div>缺评扣分{that.state.absence_penalty}</div>}
{ !!that.state.appeal_penalty && <div>违规匿评扣分{that.state.appeal_penalty}</div>}
<div>最终成绩{record.work_score}</div>
</div> }
</div>)
}>
{ renderScore(work_score) }
</Tooltip>
</span>
)
},
})
<div>{`${record.user_name}${record.user_login}`}</div>
{ record.ultimate_score ?
<div>最终调整成绩{record.work_score}</div> :
<div>
{ record.final_score && <div>作业评分{record.final_score}</div> }
{ record.late_penalty >= 0 && <div>迟交扣分{record.late_penalty}</div>}
{ record.absence_penalty >= 0 && <div>缺评扣分{record.absence_penalty}</div>}
{ record.appeal_penalty >= 0 && <div>违规匿评扣分{record.appeal_penalty}</div>}
<div>最终成绩{record.work_score}</div>
</div> }
</div>)
}>
{ renderScore(work_score) }
</Tooltip>
</span>
)
},
})
}
if (isAdminOrStudent || that.props.work_public == true) {
columns.push({
width: 92,
@ -279,7 +328,7 @@ function buildColumns(that, student_works) {
key: 'operation',
dataIndex: 'operation',
render: (operation, record) => (
record.work_status === 0 ? '--':
record.work_status === 0 && !isAdmin ? <span style={{ color: '#747A7F' }}>--</span>:
<div>
{/* 0 未提交 */}
{/*<React.Fragment>*/}
@ -308,9 +357,9 @@ const orderMap = {
work_score: 'asc',
student_id: 'asc',
}
const PAGE_SIZE = 50
const PAGE_SIZE = 20
// 类似页面 http://localhost:3007/courses/1309/graduation/graduation_tasks/48/76/setting
class CommonWorkSetting extends Component{
class CommonWorkList extends Component{
constructor(props){
super(props)
@ -335,8 +384,8 @@ class CommonWorkSetting extends Component{
category: {},
}
}
onTablePagination = (pageInfo) => {
this.setState({ page: pageInfo.current }, () => {
onTablePagination = (page) => {
this.setState({ page: page }, () => {
this.fetchList()
})
@ -351,6 +400,8 @@ class CommonWorkSetting extends Component{
componentDidMount() {
this.fetchList()
on('commonwork_fetch_all', this.fetchAllListener)
$("html").animate({ scrollTop: $('html').scrollTop() - 100 })
}
componentWillUnmount() {
off('commonwork_fetch_all', this.fetchAllListener)
@ -400,17 +451,17 @@ class CommonWorkSetting extends Component{
}
teacherCommentOptionChange = (values, isAllChecked) => {
this.setState({arg_teacher_comment: isAllChecked ? [] : values}, () => {
this.setState({arg_teacher_comment: isAllChecked ? [] : values, page: 1}, () => {
this.fetchList()
})
}
statusOptionChange = (values, isAllChecked) => {
this.setState({arg_work_status: isAllChecked ? [] : values}, () => {
this.setState({arg_work_status: isAllChecked ? [] : values, page: 1}, () => {
this.fetchList()
})
}
courseGroupOptionChange = (values, isAllChecked) => {
this.setState({arg_course_group: isAllChecked ? [] : values}, () => {
this.setState({arg_course_group: isAllChecked ? [] : values, page: 1}, () => {
this.fetchList()
})
}
@ -521,7 +572,7 @@ class CommonWorkSetting extends Component{
StudentData=isStudent ? [{ id, user_name, user_login, student_id, group_name, work_status, update_time, teacher_score, teaching_asistant_score, student_score,
ultimate_score, work_score, student_comment_count, appeal_all_count, appeal_deal_count,
late_penalty, absence_penalty, appeal_penalty,
work_group: '' }] : []
work_group: '', isMine: true }] : []
}
let params = this._getRequestParams()
let exportUrl = `/api/homework_commons/${workId}/works_list.zip?${queryString.stringify(params)}`;
@ -536,6 +587,19 @@ class CommonWorkSetting extends Component{
}
})
// time_status int 时间对应的状态: 0未发布1:提交中2:补交中3:匿评中4:申诉中5:评阅中6:已结束
let timeMsg = '提交剩余时间'
if (time_status === 1) {
} else if (time_status === 2) {
timeMsg = '补交剩余时间'
} else if (time_status === 3) {
timeMsg = '匿评剩余时间'
} else if (time_status === 4) {
timeMsg = '申诉剩余时间'
}
// console.log(StudentData)
// console.log(student_works)
return(
@ -585,7 +649,7 @@ class CommonWorkSetting extends Component{
<CheckAllGroup options={options_teacher_comment} label={'你的评阅:'} onChange={this.teacherCommentOptionChange}></CheckAllGroup>
<CheckAllGroup options={options_status} label={'作品状态:'} onChange={this.statusOptionChange}></CheckAllGroup>
{options_course_group.length > 1 && <CheckAllGroup options={options_course_group} label={'分班情况:'} onChange={this.courseGroupOptionChange} checkboxGroupStyle={{width: '86%'}}></CheckAllGroup>}
{options_course_group.length > 1 && <CheckAllGroup options={options_course_group} label={'分班情况:'} onChange={this.courseGroupOptionChange} checkboxGroupStyle={{width: '980px'}}></CheckAllGroup>}
{/* value={search} */}
@ -610,7 +674,7 @@ class CommonWorkSetting extends Component{
(!!commit_count || !!uncommit_count) &&
<React.Fragment>
<span className="color-orange-tip">{commit_count}</span> {uncommit_count} 
{time_status===5?"":"剩余提交时间"}
{timeMsg || ''}
<span className="color-orange-tip">{left_time.time}</span>
</React.Fragment>
}
@ -684,7 +748,7 @@ class CommonWorkSetting extends Component{
}
<div className={"justify break_full_word new_li edu-back-white course_table_wrap"} style={{minHeight:"480px"}}>
<div className={"justify break_full_word new_li edu-back-white course_table_wrap"} style={{minHeight:"480px", marginBottom: '30px'}}>
<style>{`
.ant-spin-nested-loading > div > .ant-spin .ant-spin-dot {
top: 72%;}
@ -708,31 +772,35 @@ class CommonWorkSetting extends Component{
</div>
</div>
</Spin>
:<Table
dataSource={student_works}
columns={columns}
showQuickJumper
pagination={work_count > PAGE_SIZE ? { //分页
:
<React.Fragment>
{/* pagination={work_count > PAGE_SIZE ? { //分页
total: work_count, //数据总数量
pageSize: PAGE_SIZE, //显示几条一页
current: page,
} : false}
loading={loadingstate}
} : false}
onChange={this.onTablePagination}
/>}
</div>
{/* <div className={"justify break_full_word new_li edu-back-white singleLine"} style={{minHeight:"480px"}}>
{data2===undefined?"":<Table
showHeader={false}
dataSource={data2}
*/}
<Table
className="stageTable"
dataSource={student_works}
columns={columns}
showQuickJumper
pagination={false}
loading={loadingstate}
/>}
</div> */}
/>
</React.Fragment>
}
</div>
</div>
{work_count > PAGE_SIZE && <Pagination
style={{ textAlign: 'center', marginBottom: '20px' }}
showQuickJumper pageSize={PAGE_SIZE} onChange={this.onTablePagination} current={page} total={work_count} />}
</React.Fragment>
@ -740,5 +808,5 @@ class CommonWorkSetting extends Component{
}
}
const CommonWorkSettingForm = Form.create({ name: 'commonworkSettingForm' })(CommonWorkSetting);
export default CommonWorkSettingForm;
const CommonWorkListForm = Form.create({ name: 'commonworkListForm' })(CommonWorkList);
export default CommonWorkListForm;

@ -92,8 +92,16 @@ class CommonWorkPost extends Component{
} else {
axios.get(url).then((response)=>{
if(response.data.course_id){
const mine = {
user_id: response.data.user_id,
user_name: response.data.user_name,
student_id: response.data.user_student_id,
group_name: response.data.group_name,
}
this.setState({
...response.data,
selectmemberslist: [mine],
memberNumMin: response.data.min_num,
memberNumMax: response.data.max_num,
})
@ -102,30 +110,6 @@ class CommonWorkPost extends Component{
console.log(error)
})
}
return
const responseData = {
"course_id": 1309,
"course_name": "计算机开发实战课-示例",
"category": {
"category_id": 11551,
"category_name": "分组作业"
},
"homework_status": [
"申诉中"
],
"homework_name": "小米便签的功能改进",
"homework_id": 7013,
"homework_type": "group",
"user_id": 15582,
"user_name": "胡莎莎",
"user_student_id": null,
"group_name": "示例A班"
}
this.setState({
...responseData
})
}
@ -173,7 +157,7 @@ class CommonWorkPost extends Component{
}
if(isGroup){
if(userids!=undefined){
if(userids.length<memberNumMin){
if(userids.length + 1<memberNumMin){
this.setState({
minvalue: memberNumMin,
setvalue:"小于",
@ -181,7 +165,7 @@ class CommonWorkPost extends Component{
})
return
}else if(userids.length>memberNumMax){
}else if(userids.length + 1>memberNumMax){
this.setState({
minvalue: memberNumMax,
setvalue:"大于",
@ -293,9 +277,11 @@ class CommonWorkPost extends Component{
}
// 附件相关 START
handleChange = (info) => {
let fileList = info.fileList;
if (info.file.status === 'uploading') {
let fileList = info.fileList;
this.setState({ fileList: appendFileSizeToUploadFileAll(fileList) });
this.setState({ fileList: appendFileSizeToUploadFileAll(fileList) });
}
}
onAttachmentRemove = (file) => {
@ -418,84 +404,6 @@ class CommonWorkPost extends Component{
}).catch((error)=>{
console.log(error)
})
return
const member = {
"members": [
{
"user_id": 8686,
"user_name": "陈晓婷",
"group_name": "未分班",
"student_id": "2018201801106004",
"commit_status": false
},
{
"user_id": 46220,
"user_name": "刘恩",
"group_name": "未分班",
"student_id": "173139241573",
"commit_status": false
},
{
"user_id": 57106,
"user_name": "曾啸笛",
"group_name": "未分班",
"student_id": "184962010005",
"commit_status": false
},
{
"user_id": 57110,
"user_name": "王玉龙",
"group_name": "未分班",
"student_id": "184962710013",
"commit_status": false
},
{
"user_id": 57280,
"user_name": "陈涛",
"group_name": "未分班",
"student_id": "184962020046",
"commit_status": false
},
{
"user_id": 57341,
"user_name": "何仁杰",
"group_name": "未分班",
"student_id": "18496232002036",
"commit_status": false
},
{
"user_id": 57386,
"user_name": "王震东",
"group_name": "未分班",
"student_id": "1849620100012",
"commit_status": false
},
{
"user_id": 58337,
"user_name": "李游",
"group_name": "未分班",
"student_id": null,
"commit_status": false
},
{
"user_id": 58787,
"user_name": "彭然",
"group_name": "未分班",
"student_id": null,
"commit_status": false
},
{
"user_id": 59553,
"user_name": "李明霞",
"group_name": "未分班",
"student_id": null,
"commit_status": false
}
]
}
this.setState({
members: member.members
})
}
@ -587,6 +495,18 @@ render(){
onChange: this.handleChange,
onRemove: this.onAttachmentRemove,
beforeUpload: (file) => {
// TODO 文件存在则提示并退出
let gotSameFile = false;
this.state.fileList && this.state.fileList.some((item) => {
if (item.name && item.name.startsWith(file.name)) {
gotSameFile = true;
return true
}
})
if (gotSameFile) {
this.props.showNotification("该附件已被上传!")
return false
}
console.log('beforeUpload', file.name);
const isLt150M = file.size / 1024 / 1024 < 150;
if (!isLt150M) {
@ -633,11 +553,12 @@ render(){
</p>
<div style={{ width:'100%',height:'75px'}} >
<p className=" fl color-black mt25 summaryname">{homework_name}</p>
<p className=" fl color-black mt25 summaryname" title={homework_name}>{homework_name}</p>
<a className="color-grey-6 fr font-16 ml30 mt10 mr20" onClick={this.goback}>返回</a>
</div>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 12 }} >
{/* */}
<Form >
<div className="stud-class-set pd20 coursenavbox edu-back-white">
<style>{`
.uploadBtn.ant-btn {
@ -659,10 +580,12 @@ render(){
<Form.Item
label="内容"
style={{marginBottom: '4px'}}
className="mdInForm"
>
{getFieldDecorator('description', {
rules: [{
required: true, message: '请输入帖子内容',
required: true, message: '请输入作品内容',
}, {
max: 5000, message: '最大限制为5000个字符',
}],
@ -727,7 +650,7 @@ render(){
width: '375px',
height: '30px'
}}>
<Checkbox value={item.user_id} checked={parseInt(task_status[key])===item.user_id?true:false}
<Checkbox value={item.user_id} key={item.user_id} checked={parseInt(task_status[key])===item.user_id?true:false}
disabled={item.commit_status || item.user_id == this.props.current_user.user_id ===true?true:false} className="fl "
></Checkbox>
<Tooltip placement="bottom" title={item.user_nam}><div className={"fl ml5 fonthidden"} style={{width: '70px'}}>{item.user_name}</div></Tooltip>

@ -101,14 +101,13 @@ class CommonWorkQuestion extends Component{
{isGroup && <div className="df mt10">
<div style={{flex: '0 0 160px'}}>
<div>分组要求</div>
<div>分组人数 {group_info.min_num} - {group_info.max_num} </div>
<div>{group_info.base_on_project ? '基于项目实施' : '不基于项目实施'}</div>
<div>分组要求 {group_info.min_num} ~ {group_info.max_num}</div>
<div>{group_info.base_on_project ? '基于项目实施' : '不基于项目'}</div>
</div>
<div style={{color: '#9B9B9B'}}>
<div>提交作品时需要关联同组成员组内成员作品共享</div>
<div>{group_info.base_on_project ? '基于项目,则项目管理员角色的成员可以提交作品' : '非基于项目,则任意小组成员可以提交作品'}</div>
<div>各小组必须在educoder平台创建项目</div>
<div>学生提交作品时需要关联同组成员组内成员作品共享</div>
<div>{group_info.base_on_project ? '学生必须在本平台创建项目,项目管理员可以提交作品' : '无需再平台创建项目,任意小组成员均可以提交作品'}</div>
{/* <div>各小组必须在educoder平台创建项目</div> */}
</div>
</div>}

@ -49,6 +49,8 @@ class CommonWorkSetting extends Component{
super(props)
this.publishModal = React.createRef();
this.endModal = React.createRef();
this.fetchMoment = moment()
this.state={
unified_setting: true,
rules: [],
@ -123,6 +125,7 @@ class CommonWorkSetting extends Component{
} else if (result.data.publish_time && moment(result.data.publish_time) < moment()) {
disable_unified_setting = true
}
this.fetchMoment = moment()
this.setState({
// starttimetype:starttype,
// endtimetype:endtype,
@ -231,7 +234,7 @@ class CommonWorkSetting extends Component{
end_time: endTime.format(dateFormat)
})
}
if (!this.state.late_time && endTime) {
if (this.state.allow_late && !this.state.late_time && endTime) {
this.setState({
late_time: endTime.add(1, 'months').format(dateFormat)
})
@ -259,20 +262,28 @@ class CommonWorkSetting extends Component{
unified_setting: checked
})
}
// 启用匿评
anonymous_comment_change = (e) => {
const checked = e.target.checked;
const { end_time } = this.state;
const currentEndTime = this._getCurrentEndTime()
let evaluation_start, evaluation_end, evaluation_num = 0, absence_penalty = 0;
if (checked) {
if (end_time) {
evaluation_start = moment(end_time).add(7, 'days').format(dateFormat)
evaluation_end = moment(end_time).add(21, 'days').format(dateFormat)
if (this.state.allow_late && this.state.late_time) {
evaluation_start = moment(this.state.late_time).add(14, 'days').format(dateFormat)
evaluation_end = moment(this.state.late_time).add(28, 'days').format(dateFormat)
} else if (currentEndTime) {
evaluation_start = moment(currentEndTime).add(14, 'days').format(dateFormat)
evaluation_end = moment(currentEndTime).add(28, 'days').format(dateFormat)
}
if (!this.state.evaluation_num) {
evaluation_num = 3
}
if (!this.state.absence_penalty) {
absence_penalty = 2
}
} else {
evaluation_start = ''
evaluation_end = ''
evaluation_start = null
evaluation_end = null
evaluation_num = 0
absence_penalty = 0
}
@ -310,15 +321,20 @@ class CommonWorkSetting extends Component{
absence_penalty:value
})
}
// 启用匿评申诉
anonymous_appeal_change = (e) => {
const { evaluation_end } = this.state;
const anonymous_appeal = e.target.checked
let appeal_time, appeal_penalty = this.state.appeal_penalty
const currentEndTime = this._getCurrentEndTime()
if (anonymous_appeal) {
appeal_penalty = 2
if (evaluation_end) {
appeal_time = moment(evaluation_end).add(7, 'days').format(dateFormat)
}
if (this.state.allow_late && this.state.late_time) {
appeal_time = moment(this.state.late_time).add(5 * 7, 'days').format(dateFormat)
} else if (currentEndTime) {
appeal_time = moment(currentEndTime).add(5 * 7, 'days').format(dateFormat)
}
} else {
appeal_time = null;
}
@ -380,7 +396,7 @@ class CommonWorkSetting extends Component{
answer_public: e.target.checked
})
}
// 补交设置 允许补交
allow_late_change=(e)=>{
this.setState({
allow_late: e.target.value
@ -389,11 +405,16 @@ class CommonWorkSetting extends Component{
this.setState({
late_penalty: 5
})
if (this.state.end_time && !this.state.late_time) {
const currentEndTime = this._getCurrentEndTime();
if (currentEndTime && !this.state.late_time) {
this.setState({
late_time: moment(handleDateString(this.state.end_time)).add(1, 'months').format(dateFormat)
late_time: moment(handleDateString(currentEndTime)).add(1, 'months').format(dateFormat)
})
}
} else {
this.setState({
late_time: null
})
}
}
@ -421,7 +442,7 @@ class CommonWorkSetting extends Component{
Topval:"本操作只对“未发布”的对象生效",
Botvalleft:"暂不发布",
Botval:"则通过后续手动设置,定时发布",
starttime:starttime,
starttime:moment(moment(new Date())).format("YYYY-MM-DD HH:mm"),
endtime:endtime,
Cancelname:"暂不发布",
Savesname:"立即发布",
@ -469,6 +490,20 @@ class CommonWorkSetting extends Component{
// }
}
_getCurrentEndTime = () => {
const { unified_setting, end_time, rules } = this.state;
if (unified_setting) {
return end_time
} else {
let max_un_unified_setting_end_time = null;
rules.map(item => {
if (!max_un_unified_setting_end_time || moment(item.end_time) > moment(max_un_unified_setting_end_time)) {
max_un_unified_setting_end_time = item.end_time;
}
})
return max_un_unified_setting_end_time
}
}
saveWorkSetting=()=>{
let workId=this.props.match.params.workId;
@ -484,6 +519,7 @@ class CommonWorkSetting extends Component{
publish_time_type, end_time_type
} = this.state;
let group_settings_param = []
let max_un_unified_setting_end_time = null
if (!unified_setting) {
const result = this.refs.pollDetailTabForthRules.notUnifiedSettingCheck(this.state.rules);
this.setState({
@ -494,6 +530,9 @@ class CommonWorkSetting extends Component{
return false;
}
group_settings_param = result.rules.map(item => {
if (!max_un_unified_setting_end_time || moment(item.end_time) > moment(max_un_unified_setting_end_time)) {
max_un_unified_setting_end_time = item.end_time;
}
return {
group_id: item.course_group_id,
publish_time: item.publish_time,
@ -517,16 +556,22 @@ class CommonWorkSetting extends Component{
return false
}
let temp_publish_time = publish_time
let temp_end_time = end_time
if (!temp_publish_time) {
const publish_time_moment = getNextHalfHourOfMoment(moment());
temp_publish_time = publish_time_moment.format(dateFormat);
}
if (!temp_end_time) {
temp_end_time = moment(handleDateString(temp_publish_time)).add(1, 'months').format(dateFormat)
let temp_publish_time
let temp_end_time
if (unified_setting) {
temp_publish_time = publish_time
temp_end_time = end_time
if (!temp_publish_time) {
const publish_time_moment = getNextHalfHourOfMoment(moment());
temp_publish_time = publish_time_moment.format(dateFormat);
}
if (!temp_end_time) {
temp_end_time = moment(handleDateString(temp_publish_time)).add(1, 'months').format(dateFormat)
}
} else {
temp_end_time = max_un_unified_setting_end_time
}
// 已发布的不检查
const isUnPublish= homework_status.indexOf(STATUS_UN_PUBLISH) != -1
const isAdmin = this.props.isAdmin()
@ -534,20 +579,22 @@ class CommonWorkSetting extends Component{
const publish_time_editable = isUnPublish;
const end_time_editable = isAdmin || !end_time || moment(end_time) > current;
if (publish_time_editable && temp_publish_time && moment(temp_publish_time) < moment()) {
this.setState({
publicTimeTip: '发布时间不能小于当前时间'
})
scrollTo('.publicTimeTip')
return false
}
// 已截止的不检查
if (end_time_editable && temp_end_time && moment(temp_end_time) <= moment(temp_publish_time)) {
this.setState({
publicTimeTip: '截止时间必须晚于发布时间'
})
scrollTo('.publicTimeTip')
return false
if (unified_setting) {
if (publish_time_editable && temp_publish_time && moment(temp_publish_time) < moment()) {
this.setState({
publicTimeTip: '发布时间不能小于当前时间'
})
scrollTo('.publicTimeTip')
return false
}
// 已截止的不检查
if (end_time_editable && temp_end_time && moment(temp_end_time) <= moment(temp_publish_time)) {
this.setState({
publicTimeTip: '截止时间必须晚于发布时间'
})
scrollTo('.publicTimeTip')
return false
}
}
this.setState({
publicTimeTip: ''
@ -949,6 +996,9 @@ class CommonWorkSetting extends Component{
.settingForm .ant-radio-group, .settingForm.ant-form {
color: #666;
}
.settingForm.ant-form {
margin-bottom: 30px;
}
.settingForm input.ant-input {
height: 40px
@ -959,7 +1009,7 @@ class CommonWorkSetting extends Component{
}
`}</style>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 12 }} className={'settingForm'}>
<Form className={'settingForm'}>
<div className="stud-class-set bor-bottom-greyE pd20 edu-back-white pl36">
{/* TODO
取消统一发布设置
@ -992,9 +1042,11 @@ class CommonWorkSetting extends Component{
<React.Fragment>
<div className={"h20 mb30 ml30"}>
<span>发布时间</span>
<Tooltip placement="bottom" title={this.props.isSuperAdmin()?"":publish_time_type===true?"发布时间已过,则不能修改":""}>
{/* <Tooltip placement="bottom" title={this.props.isSuperAdmin()?"":publish_time_type===true?"":""}>
</Tooltip> */}
<ConditionToolTip condition={moment(this.state.init_publish_time) < this.fetchMoment} title={"时间已过,不能再修改"}>
<span>
<ConditionToolTip condition={moment(this.state.init_publish_time) < moment()} title={"时间已过,不能再修改"}>
<DatePicker
dropdownClassName="hideDisable"
@ -1006,7 +1058,7 @@ class CommonWorkSetting extends Component{
placeholder="请选择发布时间"
id={"startime"}
width={"210px"}
value={publish_time===null||publish_time===""?"":moment(publish_time, dateFormat)}
value={!publish_time?"":moment(publish_time, dateFormat)}
onChange={this.onChangeTimepublish}
// disabled={this.props.isSuperAdmin()?false:publish_time_type===true?true:false}
disabled={moment(this.state.init_publish_time) < moment() || noAuth}
@ -1015,17 +1067,18 @@ class CommonWorkSetting extends Component{
// return publish_time && publish_time < moment().add(-1, 'days'); }
// }
/>
</ConditionToolTip>
</span>
</Tooltip>
</ConditionToolTip>
<span className={"font-14 color-grey-9 ml10"}>学生收到作业的时间</span>
</div>
<div className={"h20 mb30 ml30"}>
<span>截止时间</span>
<Tooltip placement="bottom" title={this.props.isSuperAdmin()?"":end_time_type===true?"截止时间已过,则不能修改":""}>
{/* <Tooltip placement="bottom" title={this.props.isSuperAdmin()?"":end_time_type===true?"":""}>
</Tooltip> */}
<ConditionToolTip condition={moment(this.state.init_end_time) < this.fetchMoment} title={"时间已过,不能再修改"}>
<span>
<ConditionToolTip condition={moment(this.state.init_end_time) < moment()} title={"时间已过,不能再修改"}>
<DatePicker
dropdownClassName="hideDisable"
showTime={{ format: 'HH:mm' }}
@ -1036,7 +1089,7 @@ class CommonWorkSetting extends Component{
placeholder="请选择截止时间"
id={"endTime"}
width={"210px"}
value={end_time===null||end_time===""?"":moment(end_time, dateFormat)}
value={!end_time?"":moment(end_time, dateFormat)}
onChange={this.onChangeTimeend}
disabled={this.props.isSuperAdmin()?false:end_time_type===true?true:false}
disabled={moment(this.state.init_end_time) < moment() || noAuth}
@ -1051,9 +1104,9 @@ class CommonWorkSetting extends Component{
// return end_time.valueOf() < moment(publish_time, dateFormat).valueOf(); }
// }
/>
</ConditionToolTip>
</span>
</Tooltip>
</ConditionToolTip>
<span className={"font-14 color-grey-9 ml10"}>学生按时提交作品的时间截点</span>
</div>
@ -1065,6 +1118,7 @@ class CommonWorkSetting extends Component{
course_group={adaptered_group_settings}
rulesCheckInfo={(info)=>this.rulesCheckInfo(info)}
flagPageEdit={true}
moduleName="作业"
></PollDetailTabForthRules>
}
@ -1082,7 +1136,7 @@ class CommonWorkSetting extends Component{
<RadioGroup onChange={this.allow_late_change} value={allow_late}>
<Radio style={radioStyle} value={true} disabled={noAuth}>允许补交</Radio>
<Radio style={radioStyle} value={true} disabled={noAuth || moment(init_late_time) < this.fetchMoment}>允许补交</Radio>
<div className={"h21 mb10 ml30 mt20"}>
<span>迟交扣分</span>
@ -1095,7 +1149,9 @@ class CommonWorkSetting extends Component{
<div className={" mb10 ml30"}>
<span>结束时间</span>
<ConditionToolTip condition={moment(init_late_time) < moment()} title={"时间已过,不能再修改"}>
{/* <ConditionToolTip condition={moment(init_late_time) < this.fetchMoment} title={""}>
</ConditionToolTip> */}
<span>
<DatePicker
showToday={false}
dropdownClassName="hideDisable"
@ -1105,10 +1161,11 @@ class CommonWorkSetting extends Component{
placeholder="请选择结束时间"
id={"enTime"}
width={"210px"}
value={late_time===null||late_time===""? undefined :moment(late_time, dateFormat)}
value={!late_time ? undefined :moment(late_time, dateFormat)}
onChange={this.onChangeTimelatetime}
disabledTime={disabledDateTime}
disabled={!allow_late || noAuth || moment(init_late_time) < moment()}
// || moment(init_late_time) < moment()
disabled={!allow_late || noAuth }
// disabledDate={ (late_time) =>
// {
// const end_time = this.state.end_time
@ -1116,13 +1173,14 @@ class CommonWorkSetting extends Component{
// return late_time < moment(end_time, dateFormat).add(-1, 'days'); }
// }
/>
</ConditionToolTip>
</span>
<span className={"font-14 color-grey-9 ml10"}>学生延时提交作品的时间截点</span>
{<div className={"latetimetype color-red "}>{latetimetype}</div>}
</div>
<Radio style={radioStyle} value={false} disabled={noAuth}>禁止补交</Radio>
<Radio style={radioStyle} value={false} disabled={noAuth || moment(init_late_time) < this.fetchMoment}>禁止补交</Radio>
</RadioGroup>
@ -1141,8 +1199,8 @@ class CommonWorkSetting extends Component{
<div className={"h20 mb30 ml60"}>
<span>开启时间</span>
<Tooltip placement="bottom" title={this.props.isSuperAdmin()?"":starttimetype===true?"发布时间已过,则不能修改":""}>
<ConditionToolTip condition={moment(init_evaluation_start) < this.fetchMoment} title={"时间已过,不能再修改"}>
<span>
<ConditionToolTip condition={moment(init_evaluation_start) < moment()} title={"时间已过,不能再修改"}>
<DatePicker
dropdownClassName="hideDisable"
showTime={{ format: 'HH:mm' }}
@ -1153,7 +1211,7 @@ class CommonWorkSetting extends Component{
placeholder="请选择匿名开启时间"
id={"startime"}
width={"210px"}
value={evaluation_start===null||evaluation_start===""?"":moment(evaluation_start, dateFormat)}
value={!evaluation_start ?"":moment(evaluation_start, dateFormat)}
onChange={this.onChangeEvaluationStart}
disabled={ (anonymous_comment && !noAuth ? false : true) || moment(init_evaluation_start) < moment() }
// disabledDate={ (evaluation_start) =>
@ -1163,16 +1221,19 @@ class CommonWorkSetting extends Component{
// return evaluation_start.valueOf() < moment(end_time, dateFormat).valueOf(); }
// }
/>
</ConditionToolTip>
</span>
</ConditionToolTip>
</Tooltip>
<span className={"font-14 color-grey-9 ml10"}>匿评开始时间之前提交作品的学生参与匿评</span>
</div>
<div className={"h20 mb30 ml60"}>
<span>结束时间</span>
<Tooltip placement="bottom" title={this.props.isSuperAdmin()?"":starttimetype===true?"发布时间已过,则不能修改":""}>
{/* <Tooltip placement="bottom" title={this.props.isSuperAdmin()?"":starttimetype===true?"":""}>
</Tooltip> */}
<ConditionToolTip condition={moment(init_evaluation_end) < this.fetchMoment} title={"时间已过,不能再修改"}>
<span>
<ConditionToolTip condition={moment(init_evaluation_end) < moment()} title={"时间已过,不能再修改"}>
<DatePicker
dropdownClassName="hideDisable"
showTime={{ format: 'HH:mm' }}
@ -1182,7 +1243,7 @@ class CommonWorkSetting extends Component{
placeholder="请选择匿名结束时间"
id={"endtime"}
width={"210px"}
value={evaluation_end===null||evaluation_end===""?"":moment(evaluation_end, dateFormat)}
value={!evaluation_end ?"":moment(evaluation_end, dateFormat)}
onChange={this.onChangeEvaluationEnd}
disabledTime={disabledDateTime}
disabled={(anonymous_comment && !noAuth ? false : true) || moment(init_evaluation_end) < moment()}
@ -1193,15 +1254,17 @@ class CommonWorkSetting extends Component{
// return evaluation_end.valueOf() < moment(evaluation_start, dateFormat).valueOf(); }
// }
/>
</ConditionToolTip>
<span className={"font-14 color-grey-9 ml10"}>学生匿评TA人作品的时间截点</span>
</span>
</Tooltip>
</ConditionToolTip>
<span className={"font-14 color-grey-9 ml10"}>学生匿评TA人作品的时间截点</span>
<span className={"font-14 color-grey-9 ml10"}></span>
</div>
{anonymous_comment_time_tip && <div className={" anonymous_comment_time_tip color-red ml60"} style={{marginTop: '-6px'}}>{anonymous_comment_time_tip}</div>}
{/* marginTop: '-6px' */}
{<div className={" anonymous_comment_time_tip color-red ml60"} style={{}}>{anonymous_comment_time_tip}</div>}
{/* 匿评数量 */}
<div className={"h20 mb30 ml60"}>
@ -1242,7 +1305,7 @@ class CommonWorkSetting extends Component{
margin-left: 18px;
}
`}</style>
<PopInstruction width={448} id={1}>
<PopInstruction width={458} id={1}>
<p className="font-14 edu-txt-left pop-instruction">
允许学生对自己作品的匿评评分进行申诉由教师和助教处理申诉<br/>
@ -1264,9 +1327,10 @@ class CommonWorkSetting extends Component{
{/* 启用匿评申述 结束时间: */}
<div className={"h20 mb30 ml60"}>
<span>结束时间</span>
<Tooltip placement="bottom" title={this.props.isSuperAdmin()?"":starttimetype===true?"发布时间已过,则不能修改":""}>
{/* <Tooltip placement="bottom" title={this.props.isSuperAdmin()?"":starttimetype===true?"":""}>
</Tooltip> */}
<ConditionToolTip condition={moment(init_appeal_time) < this.fetchMoment} title={"时间已过,不能再修改"}>
<span>
<ConditionToolTip condition={moment(init_appeal_time) < moment()} title={"时间已过,不能再修改"}>
<DatePicker
dropdownClassName="hideDisable"
showTime={{ format: 'HH:mm' }}
@ -1277,15 +1341,15 @@ class CommonWorkSetting extends Component{
placeholder="请选择申诉结束时间"
id={"endtime"}
width={"210px"}
value={appeal_time===null||appeal_time===""?"":moment(appeal_time, dateFormat)}
value={!appeal_time?"":moment(appeal_time, dateFormat)}
onChange={this.appeal_time_change}
disabled={ (anonymous_appeal && !noAuth ? false : true) || moment(init_appeal_time) < moment()}
/>
</ConditionToolTip>
</span>
</Tooltip>
</ConditionToolTip>
<span className={"font-14 color-grey-9 ml10"}></span>
<span className={"font-14 color-grey-9 ml10"}>学生提交匿评申诉的时间截点</span>
</div>
{<div className={" appeal_time_tip color-red ml60 mb6"}>{appeal_time_tip}</div>}
@ -1299,7 +1363,7 @@ class CommonWorkSetting extends Component{
/>
</span>
</Tooltip>
<span className={"font-14 color-grey-9 ml10"}></span>
<span className={"font-14 color-grey-9 ml10"}>学生违规匿评TA人作品时其成绩将被扣减的分值</span>
</div>
{this.state.appeal_penalty_tip && <div className={" appeal_penalty_tip color-red ml60"} style={{marginTop: '-6px'}}>{this.state.appeal_penalty_tip}</div>}
@ -1334,21 +1398,17 @@ class CommonWorkSetting extends Component{
<RadioGroup onChange={this.final_mode_change} value={final_mode}>
<Radio style={radioStyle} value={false} disabled={noAuth}>
多项评分配比<span className={"font-14 color-grey-9 ml10"}>选中则按照比例计算最终成绩</span>
<PopInstruction width={500} id={2}>
<PopInstruction width={512} id={2}>
<p className="font-14 edu-txt-left pop-instruction">
计算说明<br/>
优先顺序排前的非零评分 * 100% - <br/>
( 迟交扣分 + 缺评扣分 * 缺评数 + 违规匿评扣分 * 违规匿评数 )<br/>
有教师评分则教师评分100%否则教辅评分100%依次类推
{/* 教师评分 * 其百分比 + 助教评分 * 其百分比 + 学生匿评平均分 * 其百分比 - <br/>
( 迟交扣分 + 缺评扣分 * 缺评数 + 违规匿评扣分 * 违规匿评数 )<br/>
<br/>
教师评分 * 其百分比 + 助教评分 * 其百分比 + 学生匿评平均分 * 其百分比 - ( <br/>
迟交扣分 + 缺评扣分 * 缺评数 + 违规匿评扣分 * 违规匿评数 )<br/><br/>
注意<br/>
非零百分比的评分选项在没有评分记录的情况下其百分比平摊到另外的评<br/>
分选项上例如教师评分40% + 助教评分35% + 学生匿评25%学生A没<br/>
有得到教师评分则最终成绩将按照助教评分55% + 学生匿评45%进行计算 */}
非零百分比的评分选项若评分记录为空则其百分比将自动平摊到其它非零<br/>
评分选项上<br/>
教师评分40% + 助教评分35% + 学生匿评25%学生A没有教师评分记<br/>
则其最终成绩按照助教评分55% + 学生匿评45%进行计算
</p>
</PopInstruction>
@ -1380,12 +1440,30 @@ class CommonWorkSetting extends Component{
{<div className={"color-red ml30 final_mode_false_tip"}>{final_mode_false_tip}</div>}
<Radio style={radioStyle} value={true} disabled={noAuth}>
单项评分优先<span className={"font-14 color-grey-9 ml10"}>选中则按照优先顺序计算最终成绩</span>
<PopInstruction width={500} id={3}>
<p className="font-14 edu-txt-left pop-instruction">
计算说明<br/>
优先顺序排前的非零评分 * 100% - <br/>
( 迟交扣分 + 缺评扣分 * 缺评数 + 违规匿评扣分 * 违规匿评数 )<br/>
有教师评分则教师评分100%否则教辅评分100%依次类推
{/* 教师评分 * 其百分比 + 助教评分 * 其百分比 + 学生匿评平均分 * 其百分比 - <br/>
( 迟交扣分 + 缺评扣分 * 缺评数 + 违规匿评扣分 * 违规匿评数 )<br/>
<br/>
注意<br/>
非零百分比的评分选项在没有评分记录的情况下其百分比平摊到另外的评<br/>
分选项上例如教师评分40% + 助教评分35% + 学生匿评25%学生A没<br/>
有得到教师评分则最终成绩将按照助教评分55% + 学生匿评45%进行计算 */}
</p>
</PopInstruction>
</Radio>
</RadioGroup>
<div className={"font-16"} style={{ marginLeft: '25px' }}>
<span>教师评分 教辅评分 学生匿评评分</span>
<span className={"font-14 color-grey-9 ml10"}>有教师评分则教师评分100%否则教辅评分100%依次类推 </span>
{/* <span className={"font-14 color-grey-9 ml10"}>有教师评分则教师评分100%否则教辅评分100%,依次类推 </span> */}
</div>
</div>

@ -5,6 +5,7 @@ import '../css/members.css'
import { WordsBtn } from 'educoder'
import axios from 'axios'
import InfiniteScroll from 'react-infinite-scroller';
import NoneData from "../coursesPublic/NoneData"
const Search =Input.Search;
const LIMIT = 15
@ -23,7 +24,12 @@ class ConnectProject extends Component{
}
onSubmit = () => {
const { radioValue } = this.state;
const { radioValue, projects } = this.state;
if (projects.length === 0) {
this.closeConnectionProject()
return;
}
if (!radioValue) {
this.props.showNotification('请先在下面的列表中选择项目')
return;
@ -31,13 +37,14 @@ class ConnectProject extends Component{
this.connectProject(radioValue)
}
connectProject = (project_id) => {
let workId=this.props.work.homework_id;
let workId=this.work.homework_id;
const url = `/homework_commons/${workId}/student_works/relate_project.json`
axios.post(url, {
project_id: project_id
}).then((result)=>{
if(result.data.status==0){
this.closeConnectionProject()
this.props.connectSuccess()
this.props.showNotification('关联成功')
}
}).catch((error)=>{
@ -70,20 +77,17 @@ class ConnectProject extends Component{
loading: false,
hasMore: result.data.projects.length != 0
})
if (page == 1) {
this.setState({ haveProjects: result.data.projects.length > 0 })
}
}
}).catch((error)=>{
console.log(error);
})
}
toCreateProject = () => {
if (window.location.port == 3007) {
window.location.href = '/testbdweb.educoder.net/projects/new'
} else {
window.location.href = '/educoder.net/projects/new'
}
}
//关联项目
openConnectionProject=()=>{
openConnectionProject=(work)=>{
this.work = work;
this.fetchData()
this.setState({
project_flag:true
@ -99,10 +103,9 @@ class ConnectProject extends Component{
}
render(){
let {project_flag, projects, loading, hasMore }=this.state;
let {project_flag, projects, loading, hasMore, haveProjects }=this.state;
return(
<React.Fragment>
<WordsBtn style="blue" className={` font-16 ${this.props.className || ''}`} onClick={this.openConnectionProject}>关联项目</WordsBtn>
<Modal
visible={project_flag}
title="关联项目"
@ -113,16 +116,33 @@ class ConnectProject extends Component{
footer={null}
destroyOnClose={true}
>
<div className="newupload_conbox clearfix">
<style>{`
.connectProject .ant-radio {
float: left;
line-height: 18px;
}
.connectProject .ant-radio-wrapper .name {
max-width: 480px;
display: inline-block;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
}
.connectProject .ant-radio-wrapper>span:last-child {
line-height: 18px;
}
`}</style>
<div className="newupload_conbox clearfix connectProject">
{
projects && projects.length &&
(projects && !!projects.length || this.state.keyword) &&
<div>
<Search placeholder="请输入项目名称进行搜索" className="with100"
value={this.state.keyword} onInput={(e) => {this.setState({keyword: e.target.value})}}
onSearch={this.onSearchValue}
></Search>
<Radio.Group onChange={this.onChange} value={this.state.radioValue} className={"with100"}>
<div className="mt15" style={{"maxHeight":"161px","overflow-y":"auto"}}>
<div className="mt15" style={{"maxHeight":"228px","overflow-y":"auto", "overflow-x": 'hidden'}}>
<InfiniteScroll
threshold={20}
initialLoad={false}
@ -132,7 +152,9 @@ class ConnectProject extends Component{
useWindow={false}
>
{ projects.map(item => {
return <p className="mb7" key={item.id}><Radio value={item.id}>{item.name}</Radio></p>
return <p className="mb7" key={item.id}><Radio value={item.id}>
<span title={item.name.length > 12 ? item.name : ''} className="name">{item.name}</span>
</Radio></p>
})}
</InfiniteScroll>
</div>
@ -140,9 +162,13 @@ class ConnectProject extends Component{
</div>
}
{
(!projects || projects.length == 0) &&
haveProjects && projects.length == 0 &&
<NoneData></NoneData>
}
{
(!haveProjects) &&
<div className="edu-txt-center">
您当前尚未管理任何项目请先<WordsBtn style="blue" className="" onClick={this.toCreateProject}>创建项目</WordsBtn>
您当前尚未管理任何项目请先<WordsBtn style="blue" className="" onClick={this.props.toCreateProject}>创建项目</WordsBtn>
</div>
}

@ -75,12 +75,6 @@ class CoursesWorkIndex extends Component{
(props) => (<CommonWorkDetailIndex {...this.props} {...props} {...this.state} />)
}
></Route>
<Route exact path="/courses/:coursesId/common_homeworks/new"
render={
(props) => (<NewWork {...this.props} {...props} {...this.state} />)
}
></Route>
{/* 作业问答 */}
<Route exact path="/courses/:coursesId/common_homeworks/:workId/question"
render={
@ -120,7 +114,7 @@ class CoursesWorkIndex extends Component{
(props) => (<NewWork {...this.props} {...props} {...this.state} />)
}
></Route>
<Route exact path="/courses/:coursesId/common_homeworks/new"
<Route exact path="/courses/:coursesId/common_homeworks/:categroy_id/new"
render={
(props) => (<NewWork {...this.props} {...props} {...this.state} />)
}

@ -36,6 +36,10 @@ const CommonWorkAnswer = Loadable({
loader: () => import('./CommonWorkAnswer'),
loading:Loading,
})
const CommonWorkAppraise = Loadable({
loader: () => import('./CommonWorkAppraise'),
loading:Loading,
})
const CommonWork = Loadable({
@ -87,6 +91,12 @@ class CoursesWorkIndex extends Component{
(props) => (<CommonWorkDetailIndex {...this.props} {...props} {...this.state} />)
}
></Route>
{/* 评阅 */}
<Route exact path="/courses/:coursesId/group_homeworks/:workId/:studentWorkId/appraise"
render={
(props) => (<CommonWorkAppraise {...this.props} {...props} {...this.state} />)
}
></Route>
<Route exact path="/courses/:coursesId/group_homeworks/:workId/post"
@ -107,7 +117,7 @@ class CoursesWorkIndex extends Component{
(props) => (<NewWork {...this.props} {...props} {...this.state} />)
}
></Route>
<Route exact path="/courses/:coursesId/group_homeworks/new"
<Route exact path="/courses/:coursesId/group_homeworks/:categroy_id/new"
render={
(props) => (<NewWork {...this.props} {...props} {...this.state} />)
}

@ -38,7 +38,8 @@ class NewWork extends Component{
}
}
fetchCourseData = (courseId) => {
const url = `/courses/${courseId}/homework_commons/new.json?type=1`
const isGroup = this.props.isGroup()
const url = `/courses/${courseId}/homework_commons/new.json?type=${isGroup ? 3 : 1}`
axios.get(url, {
})
.then((response) => {
@ -369,11 +370,12 @@ class NewWork extends Component{
</p> */}
<CBreadcrumb items={[
{ to: `/courses/${courseId}`, name: this.state.course_name},
{ to: `/courses/${courseId}/${moduleEngName}/${category && category.category_id ? category.category_id : ''}`, name: category.category_name },
{ to: `/courses/${courseId}/${moduleEngName}/${category && category.category_id ? category.category_id : ''}`
, name: category && category.category_name },
{ name: `${ this.isEdit ? '编辑' : '新建'}` }
]}></CBreadcrumb>
<p className="clearfix mt30 mb30">
<p className="clearfix mt20 mb20">
<span className="fl font-24 color-grey-3">{this.isEdit ?"编辑":"新建"}{ moduleName }</span>
{/* history.goBack()
this.props.toListPage(this.props.match.params, category.category_id)}
@ -417,12 +419,25 @@ class NewWork extends Component{
height: 40px;
line-height: 40px;
}
.workContent.AboutInputForm.ant-form-item {
border-bottom: none;
padding-bottom: 0px !important;
}
.newWorkUpload {
padding: 0px 30px 30px 30px!important;
background: #fff;
width: 100%;
display: inline-block;
border-bottom: 1px solid #EDEDED;
}
`}</style>
{ <Form.Item
label="内容"
className="AboutInputForm"
className="AboutInputForm workContent mdInForm"
>
{getFieldDecorator('description', {
rules: [{
@ -432,14 +447,13 @@ class NewWork extends Component{
<TPMMDEditor ref={this.contentMdRef} placeholder="请在此输入作业内容和要求,最大限制5000个字符" mdID={'courseContentMD'} refreshTimeout={1500}
watch={false} className="courseMessageMD" initValue={this.state.description}></TPMMDEditor>
)}
<Upload {...uploadProps} className="upload_1">
<Button className="uploadBtn">
<Icon type="upload" /> 上传附件
</Button>
(单个文件150M以内)
</Upload>
</Form.Item> }
<Upload {...uploadProps} className="upload_1 newWorkUpload">
<Button className="uploadBtn">
<Icon type="upload" /> 上传附件
</Button>
(单个文件150M以内)
</Upload>
{ isGroup &&
@ -465,7 +479,7 @@ class NewWork extends Component{
<span className="ml15 mr15">~</span>
{/* min={has_commit ? init_max_num : (min_num == undefined ? 2 : min_num + 1) } */}
<ConditionToolTip condition={has_commit} title={'已有提交作品,人数范围只能扩大'}>
<InputNumber className="winput-240-40" placeholder="请填写每组最大人数" value={max_num}
<InputNumber className="winput-240-40" placeholder="请填写每组最大人数" value={max_num} max={10}
onChange={this.max_num_change} style={{width:'180px'}} />
</ConditionToolTip>
<label className="color-grey-9 ml20 font-14">项目管理员角色的成员都可以提交作品提交作品时需要关联同组成员组内成员作品共享</label>

@ -52,9 +52,9 @@ class PublishRightnow extends Component{
modalname: isPublish ? "立即发布" : "立即截止",
modaltype:1,
visible:true,
Topval: isPublish ? "本操作只对“未发布”的对象生效" : "本操作只对“提交中”的对象生效",
Botvalleft: isPublish ? "暂不发布" : "暂不截止",
Botval: isPublish ? "则通过后续手动设置,定时发布" : "则将根据已设置的截止时间,定时截止",
Topval: isPublish ? "学生将立即收到作业" : "学生将不能再提交作品",
// Botvalleft: isPublish ? "暂不发布" : "暂不截止",
Botval: this.props.fromListPage ? (isPublish ? "本操作只对“未发布”的分班有效" : "本操作只对“提交中”的分班有效") : '',
starttime: isPublish ? `发布时间:${startMoment.format(dateFormat)}` : '',
starttimes:isPublish ? `${startMoment.format(dateFormat)}` : '',
endtime: isPublish ? `截止时间:${startMoment.add(1, 'months').add(1, 'hours').minutes(0).format(dateFormat)}` : '',

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

Loading…
Cancel
Save