After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 9.6 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 27 KiB |
@ -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',
|
||||
},
|
||||
};
|
||||
|
After Width: | Height: | Size: 154 KiB |
@ -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}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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,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];
|
||||
}
|
@ -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,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)
|
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 29 KiB |
@ -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,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,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;
|
||||
|
@ -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;
|