Commit 8d29826f by guomingpang

feat:外部课程相关模块提交

parent 83cbc02d
#ignore obj and lib file
dist
rev
node_modules
coverage
*/vendor.js
*/vendor.*.*
*/vendor-manifest.json
coverage
npm-shrinkwrap.json
### OSX template
.DS_Store .DS_Store
node_modules/ .AppleDouble
dist/ .LSOverride
yarn.lock
yarn-error.lock
# IntelliJ project files
.idea
*.iml
out
gen
### Sass template
.sass-cache/
*.css.map
### Vim template
# swap
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
# session
Session.vim
# temporary
.netrwhist
*~
# auto-generated tag files
tags
### SublimeText template
# cache files for sublime text
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
# workspace files are user-specific
*.sublime-workspace
# project files should be checked into the repository, unless a significant
# proportion of contributors will probably not be using SublimeText
# *.sublime-project
# sftp configuration file
sftp-config.json
npm-debug.log npm-debug.log
*.zip
build/vendor.js.map
package-lock.json
.vscode/*
demo.js
debug.log
'use strict'; 'use strict'
const fs = require('fs'); const fs = require('fs')
const path = require('path'); const path = require('path')
const webpack = require('webpack'); const webpack = require('webpack')
const resolve = require('resolve'); const resolve = require('resolve')
const PnpWebpackPlugin = require('pnp-webpack-plugin'); const PnpWebpackPlugin = require('pnp-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin')
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin'); const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin')
const TerserPlugin = require('terser-webpack-plugin'); const TerserPlugin = require('terser-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const safePostCssParser = require('postcss-safe-parser'); const safePostCssParser = require('postcss-safe-parser')
const ManifestPlugin = require('webpack-manifest-plugin'); const ManifestPlugin = require('webpack-manifest-plugin')
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin')
const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin')
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin')
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent')
const paths = require('./paths'); const paths = require('./paths')
const modules = require('./modules'); const modules = require('./modules')
const vConsolePlugin = require('vconsole-webpack-plugin'); const vConsolePlugin = require('vconsole-webpack-plugin')
const getClientEnvironment = require('./env'); const getClientEnvironment = require('./env')
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin')
const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin'); const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin')
const typescriptFormatter = require('react-dev-utils/typescriptFormatter'); const typescriptFormatter = require('react-dev-utils/typescriptFormatter')
const postcssNormalize = require('postcss-normalize'); const postcssNormalize = require('postcss-normalize')
const appPackageJson = require(paths.appPackageJson); const appPackageJson = require(paths.appPackageJson)
// Source maps are resource heavy and can cause out of memory issue for large source files. // Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false'; const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false'
// Some apps do not need the benefits of saving a web request, so not inlining the chunk // Some apps do not need the benefits of saving a web request, so not inlining the chunk
// makes for a smoother build process. // makes for a smoother build process.
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false'; const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false'
const isExtendingEslintConfig = process.env.EXTEND_ESLINT === 'true'; const isExtendingEslintConfig = process.env.EXTEND_ESLINT === 'true'
const imageInlineSizeLimit = parseInt( const imageInlineSizeLimit = parseInt(process.env.IMAGE_INLINE_SIZE_LIMIT || '10000')
process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'
);
// Check if TypeScript is setup // Check if TypeScript is setup
const useTypeScript = fs.existsSync(paths.appTsConfig); const useTypeScript = fs.existsSync(paths.appTsConfig)
// style files regexes // style files regexes
const cssRegex = /\.css$/; const cssRegex = /\.css$/
const cssModuleRegex = /\.module\.css$/; const cssModuleRegex = /\.module\.css$/
const lessRegex = /\.less$/; const lessRegex = /\.less$/
const lessModuleRegex = /\.module\.less$/; const lessModuleRegex = /\.module\.less$/
// This is the production and development configuration. // This is the production and development configuration.
// It is focused on developer experience, fast rebuilds, and a minimal bundle. // It is focused on developer experience, fast rebuilds, and a minimal bundle.
module.exports = function (webpackEnv) { module.exports = function (webpackEnv) {
const isEnvDevelopment = webpackEnv === 'development'; const isEnvDevelopment = webpackEnv === 'development'
const isEnvProduction = webpackEnv === 'production'; const isEnvProduction = webpackEnv === 'production'
// Variable used for enabling profiling in Production // Variable used for enabling profiling in Production
// passed into alias object. Uses a flag if passed into the build command // passed into alias object. Uses a flag if passed into the build command
const isEnvProductionProfile = const isEnvProductionProfile = isEnvProduction && process.argv.includes('--profile')
isEnvProduction && process.argv.includes('--profile');
// We will provide `paths.publicUrlOrPath` to our app // We will provide `paths.publicUrlOrPath` to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. // 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. // Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
// Get environment variables to inject into our app. // Get environment variables to inject into our app.
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1)); const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1))
// common function to get style loaders // common function to get style loaders
const getStyleLoaders = (cssOptions, preProcessor) => { const getStyleLoaders = (cssOptions, preProcessor) => {
...@@ -76,13 +73,11 @@ module.exports = function (webpackEnv) { ...@@ -76,13 +73,11 @@ module.exports = function (webpackEnv) {
loader: MiniCssExtractPlugin.loader, loader: MiniCssExtractPlugin.loader,
// css is located in `static/css`, use '../../' to locate index.html folder // css is located in `static/css`, use '../../' to locate index.html folder
// in production `paths.publicUrlOrPath` can be a relative path // in production `paths.publicUrlOrPath` can be a relative path
options: paths.publicUrlOrPath.startsWith('.') options: paths.publicUrlOrPath.startsWith('.') ? { publicPath: '../../' } : {}
? { publicPath: '../../' }
: {},
}, },
{ {
loader: require.resolve('css-loader'), loader: require.resolve('css-loader'),
options: cssOptions, options: cssOptions
}, },
{ {
// Options for PostCSS as we reference these options twice // Options for PostCSS as we reference these options twice
...@@ -97,32 +92,32 @@ module.exports = function (webpackEnv) { ...@@ -97,32 +92,32 @@ module.exports = function (webpackEnv) {
require('postcss-flexbugs-fixes'), require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({ require('postcss-preset-env')({
autoprefixer: { autoprefixer: {
flexbox: 'no-2009', flexbox: 'no-2009'
}, },
stage: 3, stage: 3
}), }),
// Adds PostCSS Normalize as the reset css with default options, // Adds PostCSS Normalize as the reset css with default options,
// so that it honors browserslist config in package.json // so that it honors browserslist config in package.json
// which in turn let's users customize the target behavior as per their needs. // which in turn let's users customize the target behavior as per their needs.
postcssNormalize(), postcssNormalize()
], ],
sourceMap: isEnvProduction && shouldUseSourceMap, sourceMap: isEnvProduction && shouldUseSourceMap
}, }
}, }
].filter(Boolean); ].filter(Boolean)
if (preProcessor) { if (preProcessor) {
loaders.push( loaders.push(
{ {
loader: require.resolve('resolve-url-loader'), loader: require.resolve('resolve-url-loader'),
options: { options: {
sourceMap: isEnvProduction && shouldUseSourceMap, sourceMap: isEnvProduction && shouldUseSourceMap
}, }
}, },
{ {
loader: require.resolve(preProcessor), loader: require.resolve(preProcessor),
options: { options: {
sourceMap: true, sourceMap: true
}, }
}, },
{ {
loader: require.resolve('less-loader'), loader: require.resolve('less-loader'),
...@@ -130,26 +125,22 @@ module.exports = function (webpackEnv) { ...@@ -130,26 +125,22 @@ module.exports = function (webpackEnv) {
lessOptions: { lessOptions: {
modifyVars: { modifyVars: {
'primary-color': 'rgba(255, 183, 20, 1)', 'primary-color': 'rgba(255, 183, 20, 1)',
'border-radius-base': '4px', 'border-radius-base': '4px'
},
javascriptEnabled: true,
}, },
javascriptEnabled: true
}
} }
} }
); )
}
return loaders
} }
return loaders;
};
return { return {
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development', mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
// Stop compilation early in production // Stop compilation early in production
bail: isEnvProduction, bail: isEnvProduction,
devtool: isEnvProduction devtool: isEnvProduction ? (shouldUseSourceMap ? 'source-map' : false) : isEnvDevelopment && 'cheap-module-source-map',
? shouldUseSourceMap
? 'source-map'
: false
: isEnvDevelopment && 'cheap-module-source-map',
// These are the "entry points" to our application. // These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle. // This means they will be the "root" imports that are included in JS bundle.
entry: [ entry: [
...@@ -163,10 +154,9 @@ module.exports = function (webpackEnv) { ...@@ -163,10 +154,9 @@ module.exports = function (webpackEnv) {
// the line below with these two lines if you prefer the stock client: // the line below with these two lines if you prefer the stock client:
// require.resolve('webpack-dev-server/client') + '?/', // require.resolve('webpack-dev-server/client') + '?/',
isEnvDevelopment && require.resolve('webpack/hot/dev-server'), isEnvDevelopment && require.resolve('webpack/hot/dev-server'),
isEnvDevelopment && isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient'),
require.resolve('react-dev-utils/webpackHotDevClient'),
// Finally, this is your app's code: // Finally, this is your app's code:
paths.appIndexJs, paths.appIndexJs
// We include the app code last so that if there is a runtime error during // We include the app code last so that if there is a runtime error during
// initialization, it doesn't blow up the WebpackDevServer client, and // initialization, it doesn't blow up the WebpackDevServer client, and
// changing JS code would still trigger a refresh. // changing JS code would still trigger a refresh.
...@@ -178,27 +168,19 @@ module.exports = function (webpackEnv) { ...@@ -178,27 +168,19 @@ module.exports = function (webpackEnv) {
pathinfo: isEnvDevelopment, pathinfo: isEnvDevelopment,
// There will be one main bundle, and one file per asynchronous chunk. // There will be one main bundle, and one file per asynchronous chunk.
// In development, it does not produce real files. // In development, it does not produce real files.
filename: isEnvProduction filename: isEnvProduction ? 'static/js/[name].[contenthash:8].js' : isEnvDevelopment && 'static/js/bundle.js',
? 'static/js/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/bundle.js',
// TODO: remove this when upgrading to webpack 5 // TODO: remove this when upgrading to webpack 5
futureEmitAssets: true, futureEmitAssets: true,
// There are also additional JS chunk files if you use code splitting. // There are also additional JS chunk files if you use code splitting.
chunkFilename: isEnvProduction chunkFilename: isEnvProduction ? 'static/js/[name].[contenthash:8].chunk.js' : isEnvDevelopment && 'static/js/[name].chunk.js',
? 'static/js/[name].[contenthash:8].chunk.js'
: isEnvDevelopment && 'static/js/[name].chunk.js',
// webpack uses `publicPath` to determine where the app is being served from. // 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. // It requires a trailing slash, or the file assets will get an incorrect path.
// We inferred the "public path" (such as / or /my-project) from homepage. // We inferred the "public path" (such as / or /my-project) from homepage.
publicPath: isEnvDevelopment ? '/' : './', publicPath: isEnvDevelopment ? '/' : './',
// Point sourcemap entries to original disk location (format as URL on Windows) // Point sourcemap entries to original disk location (format as URL on Windows)
devtoolModuleFilenameTemplate: isEnvProduction devtoolModuleFilenameTemplate: isEnvProduction
? info => ? (info) => path.relative(paths.appSrc, info.absoluteResourcePath).replace(/\\/g, '/')
path : isEnvDevelopment && ((info) => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
.relative(paths.appSrc, info.absoluteResourcePath)
.replace(/\\/g, '/')
: isEnvDevelopment &&
(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
// Prevents conflicts when multiple webpack runtimes (from different apps) // Prevents conflicts when multiple webpack runtimes (from different apps)
// are used on the same page. // are used on the same page.
jsonpFunction: `webpackJsonp${appPackageJson.name}`, jsonpFunction: `webpackJsonp${appPackageJson.name}`,
...@@ -206,9 +188,8 @@ module.exports = function (webpackEnv) { ...@@ -206,9 +188,8 @@ module.exports = function (webpackEnv) {
// module chunks which are built will work in web workers as well. // module chunks which are built will work in web workers as well.
globalObject: 'this', globalObject: 'this',
library: appPackageJson.name, library: appPackageJson.name,
libraryTarget: "umd", libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${appPackageJson.name}`, jsonpFunction: `webpackJsonp_${appPackageJson.name}`
}, },
optimization: { optimization: {
minimize: isEnvProduction, minimize: isEnvProduction,
...@@ -222,7 +203,7 @@ module.exports = function (webpackEnv) { ...@@ -222,7 +203,7 @@ module.exports = function (webpackEnv) {
// into invalid ecma 5 code. This is why the 'compress' and 'output' // into invalid ecma 5 code. This is why the 'compress' and 'output'
// sections only apply transformations that are ecma 5 safe // sections only apply transformations that are ecma 5 safe
// https://github.com/facebook/create-react-app/pull/4234 // https://github.com/facebook/create-react-app/pull/4234
ecma: 8, ecma: 8
}, },
compress: { compress: {
ecma: 5, ecma: 5,
...@@ -236,10 +217,10 @@ module.exports = function (webpackEnv) { ...@@ -236,10 +217,10 @@ module.exports = function (webpackEnv) {
// https://github.com/facebook/create-react-app/issues/5250 // https://github.com/facebook/create-react-app/issues/5250
// Pending further investigation: // Pending further investigation:
// https://github.com/terser-js/terser/issues/120 // https://github.com/terser-js/terser/issues/120
inline: 2, inline: 2
}, },
mangle: { mangle: {
safari10: true, safari10: true
}, },
// Added for profiling in devtools // Added for profiling in devtools
keep_classnames: isEnvProductionProfile, keep_classnames: isEnvProductionProfile,
...@@ -249,10 +230,10 @@ module.exports = function (webpackEnv) { ...@@ -249,10 +230,10 @@ module.exports = function (webpackEnv) {
comments: false, comments: false,
// Turned on because emoji and regex is not minified properly using default // Turned on because emoji and regex is not minified properly using default
// https://github.com/facebook/create-react-app/issues/2488 // https://github.com/facebook/create-react-app/issues/2488
ascii_only: true, ascii_only: true
}, }
}, },
sourceMap: shouldUseSourceMap, sourceMap: shouldUseSourceMap
}), }),
// This is only used in production mode // This is only used in production mode
new OptimizeCSSAssetsPlugin({ new OptimizeCSSAssetsPlugin({
...@@ -265,57 +246,53 @@ module.exports = function (webpackEnv) { ...@@ -265,57 +246,53 @@ module.exports = function (webpackEnv) {
inline: false, inline: false,
// `annotation: true` appends the sourceMappingURL to the end of // `annotation: true` appends the sourceMappingURL to the end of
// the css file, helping the browser find the sourcemap // the css file, helping the browser find the sourcemap
annotation: true, annotation: true
} }
: false, : false
}, },
cssProcessorPluginOptions: { cssProcessorPluginOptions: {
preset: ['default', { minifyFontValues: { removeQuotes: false } }], preset: ['default', { minifyFontValues: { removeQuotes: false } }]
}, }
}), })
], ],
// Automatically split vendor and commons // Automatically split vendor and commons
// https://twitter.com/wSokra/status/969633336732905474 // https://twitter.com/wSokra/status/969633336732905474
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366 // https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
splitChunks: { splitChunks: {
chunks: 'all', chunks: 'all',
name: false, name: false
}, },
// Keep the runtime chunk separated to enable long term caching // Keep the runtime chunk separated to enable long term caching
// https://twitter.com/wSokra/status/969679223278505985 // https://twitter.com/wSokra/status/969679223278505985
// https://github.com/facebook/create-react-app/issues/5358 // https://github.com/facebook/create-react-app/issues/5358
runtimeChunk: { runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`, name: (entrypoint) => `runtime-${entrypoint.name}`
}, }
}, },
resolve: { resolve: {
// This allows you to set a fallback for where webpack should look for modules. // 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" // We placed these paths second because we want `node_modules` to "win"
// if there are any conflicts. This matches Node resolution mechanism. // if there are any conflicts. This matches Node resolution mechanism.
// https://github.com/facebook/create-react-app/issues/253 // https://github.com/facebook/create-react-app/issues/253
modules: ['node_modules', paths.appNodeModules].concat( modules: ['node_modules', paths.appNodeModules].concat(modules.additionalModulePaths || []),
modules.additionalModulePaths || []
),
// These are the reasonable defaults supported by the Node ecosystem. // These are the reasonable defaults supported by the Node ecosystem.
// We also include JSX as a common component filename extension to support // We also include JSX as a common component filename extension to support
// some tools, although we do not recommend using it, see: // some tools, although we do not recommend using it, see:
// https://github.com/facebook/create-react-app/issues/290 // https://github.com/facebook/create-react-app/issues/290
// `web` extension prefixes have been added for better support // `web` extension prefixes have been added for better support
// for React Native Web. // for React Native Web.
extensions: paths.moduleFileExtensions extensions: paths.moduleFileExtensions.map((ext) => `.${ext}`).filter((ext) => useTypeScript || !ext.includes('ts')),
.map(ext => `.${ext}`)
.filter(ext => useTypeScript || !ext.includes('ts')),
alias: { alias: {
"@": path.resolve(__dirname, '../src'), '@': path.resolve(__dirname, '../src'),
// Support React Native Web // Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web', 'react-native': 'react-native-web',
// Allows for better profiling with ReactDevTools // Allows for better profiling with ReactDevTools
...(isEnvProductionProfile && { ...(isEnvProductionProfile && {
'react-dom$': 'react-dom/profiling', 'react-dom$': 'react-dom/profiling',
'scheduler/tracing': 'scheduler/tracing-profiling', 'scheduler/tracing': 'scheduler/tracing-profiling'
}), }),
...(modules.webpackAliases || {}), ...(modules.webpackAliases || {})
}, },
plugins: [ plugins: [
// Adds support for installing with Plug'n'Play, leading to faster installs and adding // Adds support for installing with Plug'n'Play, leading to faster installs and adding
...@@ -326,15 +303,15 @@ module.exports = function (webpackEnv) { ...@@ -326,15 +303,15 @@ module.exports = function (webpackEnv) {
// To fix this, we prevent you from importing files out of src/ -- if you'd like to, // 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. // 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. // Make sure your source files are compiled, as they will not be processed in any way.
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]), new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson])
], ]
}, },
resolveLoader: { resolveLoader: {
plugins: [ plugins: [
// Also related to Plug'n'Play, but this time it tells webpack to load its loaders // Also related to Plug'n'Play, but this time it tells webpack to load its loaders
// from the current package. // from the current package.
PnpWebpackPlugin.moduleLoader(module), PnpWebpackPlugin.moduleLoader(module)
], ]
}, },
module: { module: {
strictExportPresence: true, strictExportPresence: true,
...@@ -353,13 +330,12 @@ module.exports = function (webpackEnv) { ...@@ -353,13 +330,12 @@ module.exports = function (webpackEnv) {
cache: true, cache: true,
formatter: require.resolve('react-dev-utils/eslintFormatter'), formatter: require.resolve('react-dev-utils/eslintFormatter'),
eslintPath: require.resolve('eslint'), eslintPath: require.resolve('eslint'),
resolvePluginsRelativeTo: __dirname, resolvePluginsRelativeTo: __dirname
},
loader: require.resolve('eslint-loader'),
}, },
loader: require.resolve('eslint-loader')
}
], ],
include: paths.appSrc, include: paths.appSrc
}, },
{ {
// "oneOf" will traverse all following loaders until one will // "oneOf" will traverse all following loaders until one will
...@@ -374,8 +350,8 @@ module.exports = function (webpackEnv) { ...@@ -374,8 +350,8 @@ module.exports = function (webpackEnv) {
loader: require.resolve('url-loader'), loader: require.resolve('url-loader'),
options: { options: {
limit: imageInlineSizeLimit, limit: imageInlineSizeLimit,
name: 'static/media/[name].[hash:8].[ext]', name: 'static/media/[name].[hash:8].[ext]'
}, }
}, },
// Process application JS with Babel. // Process application JS with Babel.
// The preset includes JSX, Flow, TypeScript, and some ESnext features. // The preset includes JSX, Flow, TypeScript, and some ESnext features.
...@@ -384,9 +360,7 @@ module.exports = function (webpackEnv) { ...@@ -384,9 +360,7 @@ module.exports = function (webpackEnv) {
include: paths.appSrc, include: paths.appSrc,
loader: require.resolve('babel-loader'), loader: require.resolve('babel-loader'),
options: { options: {
customize: require.resolve( customize: require.resolve('babel-preset-react-app/webpack-overrides'),
'babel-preset-react-app/webpack-overrides'
),
plugins: [ plugins: [
[ [
...@@ -394,12 +368,11 @@ module.exports = function (webpackEnv) { ...@@ -394,12 +368,11 @@ module.exports = function (webpackEnv) {
{ {
loaderMap: { loaderMap: {
svg: { svg: {
ReactComponent: ReactComponent: '@svgr/webpack?-svgo,+titleProp,+ref![path]'
'@svgr/webpack?-svgo,+titleProp,+ref![path]', }
}, }
}, }
}, ]
],
], ],
// This is a feature of `babel-loader` for webpack (not Babel itself). // This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/ // It enables caching results in ./node_modules/.cache/babel-loader/
...@@ -407,8 +380,8 @@ module.exports = function (webpackEnv) { ...@@ -407,8 +380,8 @@ module.exports = function (webpackEnv) {
cacheDirectory: true, cacheDirectory: true,
// See #6846 for context on why cacheCompression is disabled // See #6846 for context on why cacheCompression is disabled
cacheCompression: false, cacheCompression: false,
compact: isEnvProduction, compact: isEnvProduction
}, }
}, },
// Process any JS outside of the app with Babel. // Process any JS outside of the app with Babel.
// Unlike the application JS, we only compile the standard ES features. // Unlike the application JS, we only compile the standard ES features.
...@@ -420,12 +393,7 @@ module.exports = function (webpackEnv) { ...@@ -420,12 +393,7 @@ module.exports = function (webpackEnv) {
babelrc: false, babelrc: false,
configFile: false, configFile: false,
compact: false, compact: false,
presets: [ presets: [[require.resolve('babel-preset-react-app/dependencies'), { helpers: true }]],
[
require.resolve('babel-preset-react-app/dependencies'),
{ helpers: true },
],
],
cacheDirectory: true, cacheDirectory: true,
// See #6846 for context on why cacheCompression is disabled // See #6846 for context on why cacheCompression is disabled
cacheCompression: false, cacheCompression: false,
...@@ -434,8 +402,8 @@ module.exports = function (webpackEnv) { ...@@ -434,8 +402,8 @@ module.exports = function (webpackEnv) {
// code. Without the options below, debuggers like VSCode // code. Without the options below, debuggers like VSCode
// show incorrect code and set breakpoints on the wrong lines. // show incorrect code and set breakpoints on the wrong lines.
sourceMaps: shouldUseSourceMap, sourceMaps: shouldUseSourceMap,
inputSourceMap: shouldUseSourceMap, inputSourceMap: shouldUseSourceMap
}, }
}, },
// "postcss" loader applies autoprefixer to our CSS. // "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies. // "css" loader resolves paths in CSS and adds assets as dependencies.
...@@ -449,13 +417,13 @@ module.exports = function (webpackEnv) { ...@@ -449,13 +417,13 @@ module.exports = function (webpackEnv) {
exclude: cssModuleRegex, exclude: cssModuleRegex,
use: getStyleLoaders({ use: getStyleLoaders({
importLoaders: 1, importLoaders: 1,
sourceMap: isEnvProduction && shouldUseSourceMap, sourceMap: isEnvProduction && shouldUseSourceMap
}), }),
// Don't consider CSS imports dead code even if the // Don't consider CSS imports dead code even if the
// containing package claims to have no side effects. // containing package claims to have no side effects.
// Remove this when webpack adds a warning or an error for this. // Remove this when webpack adds a warning or an error for this.
// See https://github.com/webpack/webpack/issues/6571 // See https://github.com/webpack/webpack/issues/6571
sideEffects: true, sideEffects: true
}, },
// Adds support for CSS Modules (https://github.com/css-modules/css-modules) // Adds support for CSS Modules (https://github.com/css-modules/css-modules)
// using the extension .module.css // using the extension .module.css
...@@ -465,9 +433,9 @@ module.exports = function (webpackEnv) { ...@@ -465,9 +433,9 @@ module.exports = function (webpackEnv) {
importLoaders: 1, importLoaders: 1,
sourceMap: isEnvProduction && shouldUseSourceMap, sourceMap: isEnvProduction && shouldUseSourceMap,
modules: { modules: {
getLocalIdent: getCSSModuleLocalIdent, getLocalIdent: getCSSModuleLocalIdent
}, }
}), })
}, },
// Opt-in support for SASS (using .scss or .sass extensions). // Opt-in support for SASS (using .scss or .sass extensions).
// By default we support SASS Modules with the // By default we support SASS Modules with the
...@@ -478,11 +446,11 @@ module.exports = function (webpackEnv) { ...@@ -478,11 +446,11 @@ module.exports = function (webpackEnv) {
use: getStyleLoaders( use: getStyleLoaders(
{ {
importLoaders: 2, importLoaders: 2,
sourceMap: isEnvProduction && shouldUseSourceMap, sourceMap: isEnvProduction && shouldUseSourceMap
}, },
'less-loader' 'less-loader'
), ),
sideEffects: true, sideEffects: true
}, },
{ {
test: lessModuleRegex, test: lessModuleRegex,
...@@ -491,7 +459,7 @@ module.exports = function (webpackEnv) { ...@@ -491,7 +459,7 @@ module.exports = function (webpackEnv) {
importLoaders: 2, importLoaders: 2,
sourceMap: isEnvProduction && shouldUseSourceMap, sourceMap: isEnvProduction && shouldUseSourceMap,
modules: true, modules: true,
getLocalIdent: getCSSModuleLocalIdent, getLocalIdent: getCSSModuleLocalIdent
}, },
'less-loader' 'less-loader'
) )
...@@ -509,14 +477,14 @@ module.exports = function (webpackEnv) { ...@@ -509,14 +477,14 @@ module.exports = function (webpackEnv) {
// by webpacks internal loaders. // by webpacks internal loaders.
exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/], exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
options: { options: {
name: 'static/media/[name].[hash:8].[ext]', name: 'static/media/[name].[hash:8].[ext]'
}, }
}, }
// ** STOP ** Are you adding a new loader? // ** STOP ** Are you adding a new loader?
// Make sure to add the new loader(s) before the "file" loader. // Make sure to add the new loader(s) before the "file" loader.
], ]
}, }
], ]
}, },
plugins: [ plugins: [
// Generates an `index.html` file with the <script> injected. // Generates an `index.html` file with the <script> injected.
...@@ -525,7 +493,7 @@ module.exports = function (webpackEnv) { ...@@ -525,7 +493,7 @@ module.exports = function (webpackEnv) {
{}, {},
{ {
inject: true, inject: true,
template: paths.appHtml, template: paths.appHtml
}, },
isEnvProduction isEnvProduction
? { ? {
...@@ -539,8 +507,8 @@ module.exports = function (webpackEnv) { ...@@ -539,8 +507,8 @@ module.exports = function (webpackEnv) {
keepClosingSlash: true, keepClosingSlash: true,
minifyJS: true, minifyJS: true,
minifyCSS: true, minifyCSS: true,
minifyURLs: true, minifyURLs: true
}, }
} }
: undefined : undefined
) )
...@@ -548,9 +516,7 @@ module.exports = function (webpackEnv) { ...@@ -548,9 +516,7 @@ module.exports = function (webpackEnv) {
// Inlines the webpack runtime script. This script is too small to warrant // Inlines the webpack runtime script. This script is too small to warrant
// a network request. // a network request.
// https://github.com/facebook/create-react-app/issues/5358 // https://github.com/facebook/create-react-app/issues/5358
isEnvProduction && isEnvProduction && shouldInlineRuntimeChunk && new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),
shouldInlineRuntimeChunk &&
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),
// Makes some environment variables available in index.html. // Makes some environment variables available in index.html.
// The public URL is available as %PUBLIC_URL% in index.html, e.g.: // The public URL is available as %PUBLIC_URL% in index.html, e.g.:
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico"> // <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
...@@ -576,14 +542,13 @@ module.exports = function (webpackEnv) { ...@@ -576,14 +542,13 @@ module.exports = function (webpackEnv) {
// to restart the development server for webpack to discover it. This plugin // to restart the development server for webpack to discover it. This plugin
// makes the discovery automatic so you don't have to restart. // makes the discovery automatic so you don't have to restart.
// See https://github.com/facebook/create-react-app/issues/186 // See https://github.com/facebook/create-react-app/issues/186
isEnvDevelopment && isEnvDevelopment && new WatchMissingNodeModulesPlugin(paths.appNodeModules),
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
isEnvProduction && isEnvProduction &&
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output // Options similar to the same options in webpackOptions.output
// both options are optional // both options are optional
filename: 'static/css/[name].[contenthash:8].css', filename: 'static/css/[name].[contenthash:8].css',
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css', chunkFilename: 'static/css/[name].[contenthash:8].chunk.css'
}), }),
// Generate an asset manifest file with the following content: // Generate an asset manifest file with the following content:
// - "files" key: Mapping of all asset filenames to their corresponding // - "files" key: Mapping of all asset filenames to their corresponding
...@@ -596,22 +561,18 @@ module.exports = function (webpackEnv) { ...@@ -596,22 +561,18 @@ module.exports = function (webpackEnv) {
publicPath: paths.publicUrlOrPath, publicPath: paths.publicUrlOrPath,
generate: (seed, files, entrypoints) => { generate: (seed, files, entrypoints) => {
const manifestFiles = files.reduce((manifest, file) => { const manifestFiles = files.reduce((manifest, file) => {
manifest[file.name] = file.path; manifest[file.name] = file.path
return manifest; return manifest
}, seed); }, seed)
const entrypointFiles = entrypoints.main.filter( const entrypointFiles = entrypoints.main.filter((fileName) => !fileName.endsWith('.map'))
fileName => !fileName.endsWith('.map')
);
return { return {
files: manifestFiles, files: manifestFiles,
entrypoints: entrypointFiles, entrypoints: entrypointFiles
}; }
}, }
}), }),
// Moment.js is an extremely popular library that bundles large locale files // 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 // by default due to how webpack interprets its code. This is a practical
// solution that requires the user to opt into importing specific locales. // solution that requires the user to opt into importing specific locales.
...@@ -633,36 +594,26 @@ module.exports = function (webpackEnv) { ...@@ -633,36 +594,26 @@ module.exports = function (webpackEnv) {
// as they're likely a resource and not a SPA route. // as they're likely a resource and not a SPA route.
// URLs containing a "?" character won't be blacklisted as they're likely // URLs containing a "?" character won't be blacklisted as they're likely
// a route with query params (e.g. auth callbacks). // a route with query params (e.g. auth callbacks).
new RegExp('/[^/?]+\\.[^/]+$'), new RegExp('/[^/?]+\\.[^/]+$')
], ]
}), }),
// TypeScript type checking // TypeScript type checking
useTypeScript && useTypeScript &&
new ForkTsCheckerWebpackPlugin({ new ForkTsCheckerWebpackPlugin({
typescript: resolve.sync('typescript', { typescript: resolve.sync('typescript', {
basedir: paths.appNodeModules, basedir: paths.appNodeModules
}), }),
async: isEnvDevelopment, async: isEnvDevelopment,
useTypescriptIncrementalApi: true, useTypescriptIncrementalApi: true,
checkSyntacticErrors: true, checkSyntacticErrors: true,
resolveModuleNameModule: process.versions.pnp resolveModuleNameModule: process.versions.pnp ? `${__dirname}/pnpTs.js` : undefined,
? `${__dirname}/pnpTs.js` resolveTypeReferenceDirectiveModule: process.versions.pnp ? `${__dirname}/pnpTs.js` : undefined,
: undefined,
resolveTypeReferenceDirectiveModule: process.versions.pnp
? `${__dirname}/pnpTs.js`
: undefined,
tsconfig: paths.appTsConfig, tsconfig: paths.appTsConfig,
reportFiles: [ reportFiles: ['**', '!**/__tests__/**', '!**/?(*.)(spec|test).*', '!**/src/setupProxy.*', '!**/src/setupTests.*'],
'**',
'!**/__tests__/**',
'!**/?(*.)(spec|test).*',
'!**/src/setupProxy.*',
'!**/src/setupTests.*',
],
silent: true, silent: true,
// The formatter is invoked directly in WebpackDevServerUtils during development // The formatter is invoked directly in WebpackDevServerUtils during development
formatter: isEnvProduction ? typescriptFormatter : undefined, formatter: isEnvProduction ? typescriptFormatter : undefined
}), })
// new vConsolePlugin({ // new vConsolePlugin({
// enable: (process.env.DEPLOY_ENV === 'prod' || process.env.DEPLOY_ENV === 'beta') ? false : true // enable: (process.env.DEPLOY_ENV === 'prod' || process.env.DEPLOY_ENV === 'beta') ? false : true
// }) // })
...@@ -677,10 +628,10 @@ module.exports = function (webpackEnv) { ...@@ -677,10 +628,10 @@ module.exports = function (webpackEnv) {
http2: 'empty', http2: 'empty',
net: 'empty', net: 'empty',
tls: 'empty', tls: 'empty',
child_process: 'empty', child_process: 'empty'
}, },
// Turn off performance processing because we utilize // Turn off performance processing because we utilize
// our own hints via the FileSizeReporter // our own hints via the FileSizeReporter
performance: false, performance: false
}; }
}; }
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
"case-sensitive-paths-webpack-plugin": "2.3.0", "case-sensitive-paths-webpack-plugin": "2.3.0",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"cropper": "^3.1.4", "cropper": "^3.1.4",
"cross-env": "^7.0.2", "cross-env": "^7.0.3",
"css-loader": "3.4.2", "css-loader": "3.4.2",
"dom-to-image": "^2.6.0", "dom-to-image": "^2.6.0",
"dotenv": "8.2.0", "dotenv": "8.2.0",
......
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-07-23 14:54:16 * @Date: 2020-07-23 14:54:16
* @LastEditors: wufan * @LastEditors: fusanqiasng
* @LastEditTime: 2021-02-02 19:32:21 * @LastEditTime: 2021-05-24 21:04:42
* @Description: 大班直播课预览弹窗 * @Description: 大班直播课预览弹窗
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
import React from 'react'; import React from 'react'
import { Modal } from 'antd'; import { Modal } from 'antd'
import moment from 'moment'; import moment from 'moment'
import './PreviewCourseModal.less'; import './PreviewCourseModal.less'
class PreviewCourseModal extends React.Component { class PreviewCourseModal extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props)
this.state = { this.state = {}
}
} }
dealWithTime = (startTime, endTime) => { dealWithTime = (startTime, endTime) => {
const startDate = new Date(Number(startTime)); const startDate = new Date(Number(startTime))
const endDate = new Date(Number(endTime)); const endDate = new Date(Number(endTime))
const year = startDate.getFullYear(); const year = startDate.getFullYear()
const month = (startDate.getMonth() + 1) < 10 ? `0${startDate.getMonth() + 1}` : startDate.getMonth() + 1; const month = startDate.getMonth() + 1 < 10 ? `0${startDate.getMonth() + 1}` : startDate.getMonth() + 1
const day = startDate.getDate() < 10 ? `0${startDate.getDate()}` : startDate.getDate(); const day = startDate.getDate() < 10 ? `0${startDate.getDate()}` : startDate.getDate()
const startHour = startDate.getHours() < 10 ? `0${startDate.getHours()}` : startDate.getHours(); const startHour = startDate.getHours() < 10 ? `0${startDate.getHours()}` : startDate.getHours()
const startMinute = startDate.getMinutes() < 10 ? `0${startDate.getMinutes()}` : startDate.getMinutes(); const startMinute = startDate.getMinutes() < 10 ? `0${startDate.getMinutes()}` : startDate.getMinutes()
const endHour = endDate.getHours() < 10 ? `0${endDate.getHours()}` : endDate.getHours(); const endHour = endDate.getHours() < 10 ? `0${endDate.getHours()}` : endDate.getHours()
const endMinute = endDate.getMinutes() < 10 ? `0${endDate.getMinutes()}` : endDate.getMinutes(); const endMinute = endDate.getMinutes() < 10 ? `0${endDate.getMinutes()}` : endDate.getMinutes()
const liveDateStr = `${year}-${month}-${day}`; const liveDateStr = `${year}-${month}-${day}`
const startTimeStr = `${startHour}:${startMinute}`; const startTimeStr = `${startHour}:${startMinute}`
const endTimeStr = `${endHour}:${endMinute}`; const endTimeStr = `${endHour}:${endMinute}`
return { return {
liveDateStr, liveDateStr,
startTimeStr, startTimeStr,
endTimeStr, endTimeStr
}; }
} }
render() { render() {
const { courseBasinInfo, courseClassInfo = {}, courseIntroInfo, type } = this.props; const { courseBasinInfo, courseClassInfo = {}, courseIntroInfo, type } = this.props
const { coverUrl, courseName, scheduleVideoUrl } = courseBasinInfo; const { coverUrl, courseName, scheduleVideoUrl } = courseBasinInfo
const { liveDate, timeHorizonStart, timeHorizonEnd, nickname } = courseClassInfo; const { liveDate, timeHorizonStart, timeHorizonEnd, nickname } = courseClassInfo
const { liveCourseMediaRequests } = courseIntroInfo; const { liveCourseMediaRequests } = courseIntroInfo
let liveDateStr, startTimeStr, endTimeStr; let liveDateStr, startTimeStr, endTimeStr
if (liveDate) { if (liveDate) {
const _liveDate = moment(liveDate).format("YYYY-MM-DD"); const _liveDate = moment(liveDate).format('YYYY-MM-DD')
const _timeHorizonStart = moment(timeHorizonStart).format('HH:mm'); const _timeHorizonStart = moment(timeHorizonStart).format('HH:mm')
const _timeHorizonEnd = moment(timeHorizonEnd).format('HH:mm'); const _timeHorizonEnd = moment(timeHorizonEnd).format('HH:mm')
const startTime = moment(_liveDate + ' ' + _timeHorizonStart).format('x'); const startTime = moment(_liveDate + ' ' + _timeHorizonStart).format('x')
const endTime = moment(_liveDate + ' ' + _timeHorizonEnd).format('x'); const endTime = moment(_liveDate + ' ' + _timeHorizonEnd).format('x')
const { const { liveDateStr: _liveDateStr, startTimeStr: _startTimeStr, endTimeStr: _endTimeStr } = this.dealWithTime(startTime, endTime)
liveDateStr: _liveDateStr,
startTimeStr: _startTimeStr, liveDateStr = _liveDateStr
endTimeStr: _endTimeStr startTimeStr = _startTimeStr
} = this.dealWithTime(startTime, endTime); endTimeStr = _endTimeStr
liveDateStr = _liveDateStr;
startTimeStr = _startTimeStr;
endTimeStr = _endTimeStr;
} }
return ( return (
<Modal <Modal
title="预览" title='预览'
visible={true} visible={true}
width={680} width={680}
onCancel={this.props.close} onCancel={this.props.close}
footer={null} footer={null}
maskClosable={false} maskClosable={false}
className="preview-live-course-modal" className='preview-live-course-modal'
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>} closeIcon={<span className='icon iconfont modal-close-icon'>&#xe6ef;</span>}>
> <div className='container__wrap'>
<div className="container__wrap"> <div className='container'>
<div className="container"> <div className='container__header'>
<div className="container__header">
<Choose> <Choose>
<When condition={type === 'videoCourse'}> <When condition={type === 'videoCourse'}>
<video <video
controls controls
src={scheduleVideoUrl} src={scheduleVideoUrl}
poster={coverUrl ? coverUrl : `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`} poster={coverUrl ? coverUrl : `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`}
className="course-url" className='course-url'
/> />
</When> </When>
<Otherwise> <Otherwise>
<img src={coverUrl} className="course-cover" alt="course-cover" /> <img src={coverUrl} className='course-cover' alt='course-cover' />
</Otherwise> </Otherwise>
</Choose> </Choose>
</div> </div>
<Choose> <Choose>
<When condition={type === 'videoCourse'}> <When condition={type === 'videoCourse'}>
<div className="container__body"> <div className='container__body'>
<div className="title__name">{courseName}</div> <div className='title__name'>{courseName}</div>
<div className="title__inst-name">{window.currentUserInstInfo.name}</div> <div className='title__inst-name'>{window.currentUserInstInfo.name}</div>
</div> </div>
</When> </When>
<Otherwise> <Otherwise>
<div className="container__body"> <div className='container__body'>
<div className="container__body__title"> <div className='container__body__title'>
<div className="title__name">{courseName}</div> <div className='title__name'>{courseName}</div>
<div className="title__state">待开课</div> <div className='title__state'>待开课</div>
</div> </div>
<div className="container__body__time"> <div className='container__body__time'>
<span className="time__label">上课时间:</span> <span className='time__label'>上课时间:</span>
<span className="time__value"> <span className='time__value'>
{ {liveDate &&
liveDate && timeHorizonStart && timeHorizonEnd && timeHorizonStart &&
[ timeHorizonEnd && [
<span>{liveDateStr}&nbsp;</span>, <span>{liveDateStr}&nbsp;</span>,
<span>{startTimeStr}~{endTimeStr }</span> <span>
] {startTimeStr}~{endTimeStr}
} </span>
]}
</span> </span>
</div> </div>
<div className="container__body__teacher"> <div className='container__body__teacher'>
<span className="teacher__label">上课老师:</span> <span className='teacher__label'>上课老师:</span>
<span className="teacher__value">{nickname}</span> <span className='teacher__value'>{nickname}</span>
</div> </div>
</div> </div>
</Otherwise> </Otherwise>
</Choose> </Choose>
<div className="container__introduction"> <div className='container__introduction'>
<div className="container__introduction__title">直播课简介</div> <div className='container__introduction__title'>直播课简介</div>
<div className="container__introduction__list editor-box"> <div className='container__introduction__list editor-box'>
{ {liveCourseMediaRequests.map((item, index) => {
liveCourseMediaRequests.map((item, index) => {
if (item.mediaType === 'TEXT') { if (item.mediaType === 'TEXT') {
return ( return (
<div <div
className="intro-item text" className='intro-item text'
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: item.mediaContent __html: item.mediaContent
}} }}
...@@ -153,14 +143,13 @@ class PreviewCourseModal extends React.Component { ...@@ -153,14 +143,13 @@ class PreviewCourseModal extends React.Component {
if (item.mediaType === 'PICTURE') { if (item.mediaType === 'PICTURE') {
return ( return (
<div className="intro-item picture"> <div className='intro-item picture'>
<img src={item.mediaUrl} alt="intro-item__picture" /> <img src={item.mediaUrl} alt='intro-item__picture' />
</div> </div>
) )
} }
return item; return item
}) })}
}
</div> </div>
</div> </div>
</div> </div>
...@@ -170,4 +159,4 @@ class PreviewCourseModal extends React.Component { ...@@ -170,4 +159,4 @@ class PreviewCourseModal extends React.Component {
} }
} }
export default PreviewCourseModal; export default PreviewCourseModal
@import '../core/variables.less'; @import "../core/variables.less";
.xm-breadCrumb{ .xm-breadCrumb {
margin-left: 16px; margin-left: 16px;
color: #989898; color: #989898;
margin-top:10px; margin-top: 10px;
margin-bottom: 10px; margin-bottom: 10px;
+.statistic-tips{ + .statistic-tips {
position: relative; position: relative;
top: -8px; top: -8px;
margin-bottom: 0px !important; margin-bottom: 0px !important;
...@@ -20,26 +20,25 @@ ...@@ -20,26 +20,25 @@
font-size: @xm-font-size-m; font-size: @xm-font-size-m;
line-height: 25px; line-height: 25px;
} }
.ant-breadcrumb{ .ant-breadcrumb {
display: inline-block; display: inline-block;
span{ span {
color: #333; color: #333;
font-weight: 400; font-weight: 400;
} }
} }
.divide{ .divide {
display: inline-block; display: inline-block;
position: relative; position: relative;
height: 12px; height: 12px;
width: 25px; width: 25px;
&:after{ &:after {
content:''; content: "";
position: absolute; position: absolute;
left: 12px; left: 12px;
height: 16px; height: 16px;
top: 0px; top: 0px;
border-left:1px solid #989898; border-left: 1px solid #989898;
} }
} }
} }
...@@ -2,28 +2,26 @@ ...@@ -2,28 +2,26 @@
* @Description: * @Description:
* @Author: zangsuyun * @Author: zangsuyun
* @Date: 2021-03-13 10:57:14 * @Date: 2021-03-13 10:57:14
* @LastEditors: zangsuyun * @LastEditors: fusanqiasng
* @LastEditTime: 2021-03-13 17:16:44 * @LastEditTime: 2021-05-24 22:10:50
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import PropTypes from 'prop-types'; import PropTypes from 'prop-types'
import React from 'react' import React from 'react'
// import { Modal } from 'antd'; // import { Modal } from 'antd';
import './TableSelectedData.less'; import './TableSelectedData.less'
class TableSelectedData extends React.Component { class TableSelectedData extends React.Component {
constructor(props) {
super(props);
}
render() { render() {
return ( return (
<div className={this.props.className+' selected-data-box'}> <div className={this.props.className + ' selected-data-box'}>
<span className="icon iconfont">&#xe61d;</span> <span className='icon iconfont'>&#xe61d;</span>
<span className="selected-text">{'已选择'+this.props.selectedNum+'项'}</span> <span className='selected-text'>{'已选择' + this.props.selectedNum + '项'}</span>
<span className="click-clear" onClick={this.props.clearSelectedData}>清空</span> <span className='click-clear' onClick={this.props.clearSelectedData}>
清空
</span>
</div> </div>
) )
} }
...@@ -32,14 +30,13 @@ class TableSelectedData extends React.Component { ...@@ -32,14 +30,13 @@ class TableSelectedData extends React.Component {
TableSelectedData.propTypes = { TableSelectedData.propTypes = {
className: PropTypes.string, // class className: PropTypes.string, // class
selectedNum: PropTypes.number, // 已选择人数 selectedNum: PropTypes.number, // 已选择人数
clearSelectedData: PropTypes.func, // 取消全部选择 clearSelectedData: PropTypes.func // 取消全部选择
}; }
TableSelectedData.defaultProps = { TableSelectedData.defaultProps = {
className: '', className: '',
selectedNum: 0, selectedNum: 0,
clearSelectedData: function () { clearSelectedData: function () {}
}
} }
export default TableSelectedData export default TableSelectedData
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
// 消息提示框 // 消息提示框
.ant-message { .ant-message {
&>span { & > span {
display: block !important; display: block !important;
} }
} }
...@@ -21,13 +21,12 @@ ...@@ -21,13 +21,12 @@
} }
} }
.ant-steps-item .ant-steps-item-icon>.ant-steps-icon { .ant-steps-item .ant-steps-item-icon > .ant-steps-icon {
top: -6%; top: -6%;
} }
.ant-calendar-month-panel { .ant-calendar-month-panel {
.ant-calendar-month-panel-header { .ant-calendar-month-panel-header {
.ant-calendar-month-panel-next-year-btn, .ant-calendar-month-panel-next-year-btn,
.ant-calendar-month-panel-prev-year-btn { .ant-calendar-month-panel-prev-year-btn {
height: auto; height: auto;
...@@ -35,12 +34,10 @@ ...@@ -35,12 +34,10 @@
} }
} }
.ant-form-item-children { .ant-form-item-children {
display: block; display: block;
} }
.ant-switch-small:after { .ant-switch-small:after {
top: 0.3px; top: 0.3px;
} }
...@@ -88,7 +85,7 @@ ...@@ -88,7 +85,7 @@
} }
.ant-dropdown-link { .ant-dropdown-link {
color: #5D5D5E !important; color: #5d5d5e !important;
} }
.ant-table-fixed-header { .ant-table-fixed-header {
...@@ -135,7 +132,7 @@ ...@@ -135,7 +132,7 @@
} }
.ant-input[disabled] { .ant-input[disabled] {
background-color: #F0F2F5 !important; background-color: #f0f2f5 !important;
} }
.ant-dropdown-link { .ant-dropdown-link {
...@@ -171,7 +168,6 @@ background-color: #F0F2F5 !important; ...@@ -171,7 +168,6 @@ background-color: #F0F2F5 !important;
td { td {
background: @xm-table-body-active !important; background: @xm-table-body-active !important;
} }
} }
tr { tr {
...@@ -189,18 +185,17 @@ background-color: #F0F2F5 !important; ...@@ -189,18 +185,17 @@ background-color: #F0F2F5 !important;
td { td {
background: @xm-table-body-active !important; background: @xm-table-body-active !important;
} }
} }
} }
} }
} }
.ant-table-bordered { .ant-table-bordered {
.ant-table-body { .ant-table-body {
border: 1px solid #e8e8e8; border: 1px solid #e8e8e8;
} }
.ant-table-header>table,.ant-table-body>table { .ant-table-header > table,
.ant-table-body > table {
border: none !important; border: none !important;
border-radius: 3px; border-radius: 3px;
.icon { .icon {
...@@ -217,14 +212,10 @@ background-color: #F0F2F5 !important; ...@@ -217,14 +212,10 @@ background-color: #F0F2F5 !important;
border-right: 1px solid #e8e8e8 !important; border-right: 1px solid #e8e8e8 !important;
} }
.ant-input-search-button { .ant-input-search-button {
height: 32px !important; height: 32px !important;
} }
.ant-avatar { .ant-avatar {
width: 35px; width: 35px;
height: 35px; height: 35px;
...@@ -237,7 +228,7 @@ background-color: #F0F2F5 !important; ...@@ -237,7 +228,7 @@ background-color: #F0F2F5 !important;
padding: 8px 20px 12px !important; padding: 8px 20px 12px !important;
font-size: 16px !important; font-size: 16px !important;
>span { > span {
font-size: 16px !important; font-size: 16px !important;
} }
} }
...@@ -282,7 +273,7 @@ background-color: #F0F2F5 !important; ...@@ -282,7 +273,7 @@ background-color: #F0F2F5 !important;
} }
} }
.ant-checkbox-wrapper+.ant-checkbox-wrapper { .ant-checkbox-wrapper + .ant-checkbox-wrapper {
margin-left: 0 !important; margin-left: 0 !important;
} }
.ant-checkbox-inner { .ant-checkbox-inner {
...@@ -310,8 +301,6 @@ background-color: #F0F2F5 !important; ...@@ -310,8 +301,6 @@ background-color: #F0F2F5 !important;
left: 0px; left: 0px;
} }
.ml16 { .ml16 {
margin-left: 16px !important; margin-left: 16px !important;
} }
...@@ -322,7 +311,6 @@ background-color: #F0F2F5 !important; ...@@ -322,7 +311,6 @@ background-color: #F0F2F5 !important;
ml0 { ml0 {
margin-left: 0 !important; margin-left: 0 !important;
} }
mr0 { mr0 {
...@@ -339,28 +327,24 @@ mr0 { ...@@ -339,28 +327,24 @@ mr0 {
transform: translate(-8px, -8px) scale(0.7) !important; transform: translate(-8px, -8px) scale(0.7) !important;
} }
.ant-select-selection { .ant-select-selection {
border-color: @xm-color-border !important; border-color: @xm-color-border !important;
} }
.ant-select-dropdown-menu-item-active:not(.ant-select-dropdown-menu-item-disabled) { .ant-select-dropdown-menu-item-active:not(.ant-select-dropdown-menu-item-disabled) {
background: #F3F6FA; background: #f3f6fa;
.ant-select-selected-icon { .ant-select-selected-icon {
color:#ffb000 !important; color: #ffb000 !important;
} }
} }
.ant-select-dropdown-menu-item-selected { .ant-select-dropdown-menu-item-selected {
background: none; background: none;
font-weight: 400 !important; font-weight: 400 !important;
color:#ffb000; color: #ffb000;
} }
.ant-select-open .ant-select-selection { .ant-select-open .ant-select-selection {
box-shadow: none; box-shadow: none;
} }
...@@ -391,19 +375,17 @@ mr0 { ...@@ -391,19 +375,17 @@ mr0 {
} }
} }
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 6px; width: 6px;
height: 6px; height: 6px;
display: block; display: block;
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/ /*滚动条里面小方块*/
border-radius: 3px; // background:rgba(204,204,204,1); border-radius: 3px; // background:rgba(204,204,204,1);
background: rgba(204, 204, 204, 1); background: rgba(204, 204, 204, 1);
} }
.ant-avatar { .ant-avatar {
background: #e8e8e8; background: #e8e8e8;
...@@ -413,7 +395,7 @@ mr0 { ...@@ -413,7 +395,7 @@ mr0 {
border-radius: 0 !important; border-radius: 0 !important;
} }
.ant-table-small>.ant-table-content>.ant-table-body { .ant-table-small > .ant-table-content > .ant-table-body {
margin: 0px; margin: 0px;
} }
...@@ -444,14 +426,13 @@ mr0 { ...@@ -444,14 +426,13 @@ mr0 {
} }
} }
.table-no-scrollbar { .table-no-scrollbar {
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 0; width: 0;
} }
} }
.ant-table-small>.ant-table-content>.ant-table-body { .ant-table-small > .ant-table-content > .ant-table-body {
margin: 0 0px !important; margin: 0 0px !important;
} }
...@@ -488,10 +469,8 @@ mr0 { ...@@ -488,10 +469,8 @@ mr0 {
margin: 0 12px; margin: 0 12px;
} }
.ant-modal-confirm-info .ant-modal-confirm-body > .anticon { .ant-modal-confirm-info .ant-modal-confirm-body > .anticon {
color: #ffb000!important; color: #ffb000 !important;
} }
.ant-breadcrumb > span:last-child .ant-breadcrumb-separator { .ant-breadcrumb > span:last-child .ant-breadcrumb-separator {
...@@ -511,18 +490,18 @@ mr0 { ...@@ -511,18 +490,18 @@ mr0 {
text-align: inherit !important; text-align: inherit !important;
} }
.ant-modal-confirm-info .ant-modal-confirm-body>.anticon { .ant-modal-confirm-info .ant-modal-confirm-body > .anticon {
color: #FFBB54 !important; color: #ffbb54 !important;
} }
.ant-modal-confirm-info .ant-modal-confirm-body>.default-confirm-icon { .ant-modal-confirm-info .ant-modal-confirm-body > .default-confirm-icon {
font-size: 22px !important; font-size: 22px !important;
line-height: 22px !important; line-height: 22px !important;
float: left !important; float: left !important;
color:#ffb000 !important; color: #ffb000 !important;
margin-right: 16px !important; margin-right: 16px !important;
&.blue { &.blue {
color: #5CBAFF !important; color: #5cbaff !important;
} }
} }
...@@ -537,19 +516,19 @@ mr0 { ...@@ -537,19 +516,19 @@ mr0 {
// confirm弹窗自定义图标 相关样式调整 // confirm弹窗自定义图标 相关样式调整
.ant-modal-body .ant-modal-confirm-body-wrapper .ant-modal-confirm-body { .ant-modal-body .ant-modal-confirm-body-wrapper .ant-modal-confirm-body {
>.solid-icon { > .solid-icon {
color: #faad14; color: #faad14;
font-size: 22px; font-size: 22px;
line-height: 22px; line-height: 22px;
float: left; float: left;
margin-right: 16px; margin-right: 16px;
} }
>.confirm-icon{ > .confirm-icon {
color: #ffb000; color: #ffb000;
} }
.ant-modal-confirm-content { .ant-modal-confirm-content {
margin-left: 38px; margin-left: 38px;
>.solid-icon-content { > .solid-icon-content {
margin-left: 40px; margin-left: 40px;
} }
} }
...@@ -592,47 +571,43 @@ mr0 { ...@@ -592,47 +571,43 @@ mr0 {
} }
//滚动条的公共样式处理 //滚动条的公共样式处理
.ant-select-dropdown .rc-virtual-list-scrollbar .rc-virtual-list-scrollbar-thumb{ .ant-select-dropdown .rc-virtual-list-scrollbar .rc-virtual-list-scrollbar-thumb {
background: #D6D6D6 !important; background: #d6d6d6 !important;
width:6px !important; width: 6px !important;
height:80px !important; height: 80px !important;
} }
.ant-select-dropdown .rc-virtual-list-scrollbar .rc-virtual-list-scrollbar-thumb:hover{ .ant-select-dropdown .rc-virtual-list-scrollbar .rc-virtual-list-scrollbar-thumb:hover {
background: #ADADAD !important; background: #adadad !important;
} }
//table的公共的样式的处理 //table的公共的样式的处理
.ant-table.ant-table-bordered > .ant-table-container > .ant-table-content > table > thead > tr > .ant-table-cell-fix-right-first::after, .ant-table.ant-table-bordered > .ant-table-container > .ant-table-content > table > thead > tr > .ant-table-cell-fix-right-first::after,
.ant-table.ant-table-bordered > .ant-table-container > .ant-table-content > table > tbody > tr > .ant-table-cell-fix-right-first::after .ant-table.ant-table-bordered > .ant-table-container > .ant-table-content > table > tbody > tr > .ant-table-cell-fix-right-first::after {
{ border-right: none !important;
border-right:none !important;
} }
// .ant-table tbody tr:nth-child(2n) td{ // .ant-table tbody tr:nth-child(2n) td{
// background: #FAFAFA !important; // background: #FAFAFA !important;
// } // }
.ant-table-thead > tr > th{ .ant-table-thead > tr > th {
font-weight:normal !important; font-weight: normal !important;
} }
td.ant-table-column-sort{ td.ant-table-column-sort {
background: none; background: none;
} }
.ant-modal-content .ant-table-thead > tr > th{ .ant-modal-content .ant-table-thead > tr > th {
padding:9px 24px; padding: 9px 24px;
} }
.ant-modal-content tr > td{ .ant-modal-content tr > td {
padding:14px 24px !important; padding: 14px 24px !important;
} }
//弹框里的table样式的处理 //弹框里的table样式的处理
//按钮的样式的公共处理 //按钮的样式的公共处理
.ant-btn-loading { .ant-btn-loading {
padding-left:18px !important; padding-left: 18px !important;
} }
.ant-input, .ant-input,
...@@ -640,27 +615,25 @@ td.ant-table-column-sort{ ...@@ -640,27 +615,25 @@ td.ant-table-column-sort{
border-color: @xm-color-border; border-color: @xm-color-border;
} }
//普通按钮样式 //普通按钮样式
.ant-btn { .ant-btn {
height:28px !important; height: 28px !important;
font-weight: normal !important; font-weight: normal !important;
border: 1px solid #e8e8e8; border: 1px solid #e8e8e8;
box-shadow: none !important; box-shadow: none !important;
padding:0px 12px !important; padding: 0px 12px !important;
color:#666 !important; color: #666 !important;
.span{ .span {
line-height:1; line-height: 1;
} }
&:hover { &:hover {
border:1px solid rgba(232, 232, 232, 1) !important; border: 1px solid rgba(232, 232, 232, 1) !important;
opacity: 0.7; opacity: 0.7;
} }
&:focus, &:focus,
&:active{ &:active {
color:#666 !important; color: #666 !important;
border:1px solid #C6C6C6 !important; border: 1px solid #c6c6c6 !important;
} }
} }
...@@ -677,62 +650,66 @@ td.ant-table-column-sort{ ...@@ -677,62 +650,66 @@ td.ant-table-column-sort{
} }
background-color: @xm-color-text-select-primary !important; background-color: @xm-color-text-select-primary !important;
border-color: @xm-color-text-select-primary !important; border-color: @xm-color-text-select-primary !important;
border:none !important; border: none !important;
&:hover { &:hover {
background-color: #FFB714 !important; background-color: #ffb714 !important;
opacity: 0.8 !important; opacity: 0.8 !important;
} }
&:focus, &:focus,
&:active{ &:active {
background-color:#FFA100 !important; background-color: #ffa100 !important;
} }
} }
//警示按钮样式 //警示按钮样式
.ant-btn-dangerous{ .ant-btn-dangerous {
background:rgba(255, 79, 79, 1) !important; background: rgba(255, 79, 79, 1) !important;
color:#FFF !important; color: #fff !important;
border:none !important; border: none !important;
} }
.ant-btn-dangerous:hover{ .ant-btn-dangerous:hover {
background:rgba(255, 79, 79, 0.7) !important; background: rgba(255, 79, 79, 0.7) !important;
color:#FFF !important; color: #fff !important;
border:none !important; border: none !important;
} }
.ant-btn-dangerous:focus, .ant-btn-dangerous:focus,
.ant-btn-dangerous:active{ .ant-btn-dangerous:active {
background:rgba(255, 79, 79,1) !important; background: rgba(255, 79, 79, 1) !important;
color:#FFF !important; color: #fff !important;
border:none !important; border: none !important;
} }
//disabled的按钮的样式 //disabled的按钮的样式
.ant-btn-primary[disabled], .ant-btn-primary[disabled]:hover, .ant-btn-primary[disabled]:focus, .ant-btn-primary[disabled]:active{ .ant-btn-primary[disabled],
background: #F7F8F9 !important; .ant-btn-primary[disabled]:hover,
border: 1px solid #E8E8E8 !important; .ant-btn-primary[disabled]:focus,
color: #CCCCCC !important; .ant-btn-primary[disabled]:active {
span{ background: #f7f8f9 !important;
color: #CCCCCC !important; border: 1px solid #e8e8e8 !important;
color: #cccccc !important;
span {
color: #cccccc !important;
} }
} }
//时间选择器后的按钮样式 //时间选择器后的按钮样式
.ant-picker-ok{ .ant-picker-ok {
.ant-btn{ .ant-btn {
padding:0 8px !important; padding: 0 8px !important;
} }
} }
//搜索框后面的按钮样式 //搜索框后面的按钮样式
.ant-input-search-button{ .ant-input-search-button {
height:32px !important; height: 32px !important;
} }
.ant-input-search > .ant-input-group > .ant-input-group-addon:last-child .ant-input-search-button{ .ant-input-search > .ant-input-group > .ant-input-group-addon:last-child .ant-input-search-button {
background: #FFF !important; background: #fff !important;
border-top:1px solid #dfdfdf !important; border-top: 1px solid #dfdfdf !important;
border-right:1px solid #dfdfdf !important; border-right: 1px solid #dfdfdf !important;
border-bottom:1px solid #dfdfdf !important; border-bottom: 1px solid #dfdfdf !important;
} }
.ant-input-search .ant-input:hover, .ant-input-search .ant-input:focus{ .ant-input-search .ant-input:hover,
.ant-input-search .ant-input:focus {
border-color: #ffcb3d; border-color: #ffcb3d;
border: 1px solid #d9d9d9 !important; border: 1px solid #d9d9d9 !important;
box-shadow: none !important; box-shadow: none !important;
...@@ -743,9 +720,9 @@ td.ant-table-column-sort{ ...@@ -743,9 +720,9 @@ td.ant-table-column-sort{
// border-right:1px solid #FFA100 !important; // border-right:1px solid #FFA100 !important;
// border-bottom:1px solid #FFA100 !important; // border-bottom:1px solid #FFA100 !important;
// } // }
.ant-input-search > .ant-input-group > .ant-input-group-addon:last-child .ant-input-search-button span{ .ant-input-search > .ant-input-group > .ant-input-group-addon:last-child .ant-input-search-button span {
color:#bfbfbf !important; color: #bfbfbf !important;
font-size:12px; font-size: 12px;
} }
.ant-modal-footer { .ant-modal-footer {
...@@ -756,44 +733,44 @@ td.ant-table-column-sort{ ...@@ -756,44 +733,44 @@ td.ant-table-column-sort{
//模态框的样式的公共处理 //模态框的样式的公共处理
//删除模态框的样式的的处理 //删除模态框的样式的的处理
.ant-modal-confirm{ .ant-modal-confirm {
.ant-modal-body{ .ant-modal-body {
padding:32px 32px 24px 32px !important; padding: 32px 32px 24px 32px !important;
.ant-modal-confirm-title{ .ant-modal-confirm-title {
color: rgba(0, 0, 0, 0.85) color: rgba(0, 0, 0, 0.85);
} }
.ant-modal-confirm-content{ .ant-modal-confirm-content {
min-height:44px; min-height: 44px;
color: rgba(0, 0, 0, 0.65) color: rgba(0, 0, 0, 0.65);
} }
} }
} }
//普通模态框的样式的处理 //普通模态框的样式的处理
.ant-modal{ .ant-modal {
.ant-modal-title{ .ant-modal-title {
color:#333; color: #333;
font-weight:400; font-weight: 400;
} }
.ant-modal-close-x{ .ant-modal-close-x {
.modal-close-icon{ .modal-close-icon {
color:#999; color: #999;
font-size:12px; font-size: 12px;
margin-right:6px; margin-right: 6px;
font-weight:400; font-weight: 400;
} }
} }
.ant-modal-footer{ .ant-modal-footer {
padding:10px 24px; display: flex;
padding: 10px 24px;
} }
} }
// 排序小三角 // 排序小三角
.ant-table-column-sorter { .ant-table-column-sorter {
margin-left: 2px!important; margin-left: 2px !important;
} }
.ant-table-column-sorter-full{ .ant-table-column-sorter-full {
margin-top:-0.32rem !important; margin-top: -0.32rem !important;
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
right: 0; right: 0;
bottom: 0; bottom: 0;
z-index: 101; z-index: 101;
background-color: #F0F2F5; background-color: #f0f2f5;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
.page { .page {
...@@ -19,14 +19,14 @@ ...@@ -19,14 +19,14 @@
bottom: 0; bottom: 0;
z-index: 102; z-index: 102;
overflow: auto; overflow: auto;
.box{ .box {
&:first-child{ &:first-child {
margin-bottom: 8px; margin-bottom: 8px;
} }
&+.box{ & + .box {
margin: 8px 16px; margin: 8px 16px;
} }
&:last-child{ &:last-child {
margin-bottom: 16px; margin-bottom: 16px;
} }
} }
...@@ -42,38 +42,40 @@ ...@@ -42,38 +42,40 @@
animation: all 0.75; animation: all 0.75;
padding-bottom: 16px; padding-bottom: 16px;
} }
.content-sub-header{ .content-sub-header {
padding: 0px 16px 0; padding: 0px 16px 0;
line-height: 30px; line-height: 30px;
} }
.content-header { .content-header {
padding: 10px 16px; padding: 16px 16px;
line-height: 30px; line-height: 30px;
background: #fff;
margin: 16px 16px 0;
font-size: 24px;
color: #333;
font-weight: 500;
h1 { h1 {
font-size: 14px;
color: #898989;
font-weight: normal; font-weight: normal;
display: inline-block; display: inline-block;
} }
} }
.box{ .box {
padding: 16px; padding: 16px;
margin: 0 16px 16px; margin: 0 16px;
margin-bottom: 8px;
background: #ffffff; background: #ffffff;
// min-height: 400px; // min-height: 400px;
.box-header { .box-header {
line-height: 30px; line-height: 30px;
padding-bottom: 12px; padding-bottom: 12px;
&.searchOnly{ &.searchOnly {
padding-bottom: 0px; padding-bottom: 0px;
} }
.filter-row { .filter-row {
min-height: 30px; min-height: 30px;
margin-bottom: 10px; margin-bottom: 10px;
>* { > * {
float: left; float: left;
margin-left: 16px; margin-left: 16px;
height: 40px; height: 40px;
...@@ -89,16 +91,12 @@ ...@@ -89,16 +91,12 @@
.box-footer { .box-footer {
margin-top: 16px; margin-top: 16px;
} }
&:first-child{ &:first-child {
margin-bottom: 8px; margin-bottom: 8px;
} }
&+.box{ & + .box {
margin: 8px 16px; margin: 8px 16px;
} }
&:last-child{
margin-bottom: 13px;
}
} }
// .ant-calendar-picker{ // .ant-calendar-picker{
// top:-1px; // top:-1px;
...@@ -108,26 +106,25 @@ ...@@ -108,26 +106,25 @@
.box-header { .box-header {
.ant-row-flex { .ant-row-flex {
padding-top: 2px; padding-top: 2px;
>div:nth-child(1) { > div:nth-child(1) {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items:space-between; align-items: space-between;
.flex(1); .flex(1);
>*{ > * {
flex-basis: 30%; flex-basis: 30%;
margin-right: 3%; margin-right: 3%;
margin-bottom: 16px; margin-bottom: 16px;
} }
} }
&.lastRow{ &.lastRow {
>div:nth-child(1) { > div:nth-child(1) {
>*{ > * {
margin-bottom: 0px; margin-bottom: 0px;
} }
} }
} }
} }
} }
.full-screen-page { .full-screen-page {
...@@ -139,5 +136,5 @@ ...@@ -139,5 +136,5 @@
bottom: 0; bottom: 0;
right: 0; right: 0;
user-select: none; user-select: none;
background-color: #F0F2F5; background-color: #f0f2f5;
} }
/* /*
* @Author: yuananting * @Author: yuananting
* @Date: 2021-03-03 15:13:12 * @Date: 2021-03-03 15:13:12
* @LastEditors: yuananting * @LastEditors: fusanqiasng
* @LastEditTime: 2021-04-13 13:58:40 * @LastEditTime: 2021-05-25 10:07:03
* @Description: 助学工具接口 * @Description: 助学工具接口
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import Service from "@/common/js/service"; import Service from '@/common/js/service'
export function queryExternalCategoryTree(params: object) {
return Service.Hades('public/externalHades/queryCategoryTree', params)
}
export function queryCategoryTree(params: object) { export function queryCategoryTree(params: object) {
return Service.Hades("public/hades/queryCategoryTree", params); return Service.Hades('public/hades/queryCategoryTree', params)
} }
export function addCategory(params: object) { export function addCategory(params: object) {
return Service.Hades("public/hades/addCategory", params); return Service.Hades('public/hades/addCategory', params)
} }
export function delCategory(params: object) { export function delCategory(params: object) {
return Service.Hades("public/hades/delCategory", params); return Service.Hades('public/hades/delCategory', params)
} }
export function editCategory(params: object) { export function editCategory(params: object) {
return Service.Hades("public/hades/editCategory", params); return Service.Hades('public/hades/editCategory', params)
} }
export function editCategoryTree(params: object) { export function editCategoryTree(params: object) {
return Service.Hades("public/hades/editCategoryTree", params); return Service.Hades('public/hades/editCategoryTree', params)
} }
export function queryQuestionPageList(params: object) { export function queryQuestionPageList(params: object) {
return Service.Hades("public/hades/queryQuestionPageList", params); return Service.Hades('public/hades/queryQuestionPageList', params)
} }
export function addQuestion(params: object) { export function addQuestion(params: object) {
return Service.Hades("public/hades/addQuestion", params); return Service.Hades('public/hades/addQuestion', params)
} }
export function deleteQuestion(params: object) { export function deleteQuestion(params: object) {
return Service.Hades("public/hades/deleteQuestion", params); return Service.Hades('public/hades/deleteQuestion', params)
} }
export function queryQuestionDetails(params: object) { export function queryQuestionDetails(params: object) {
return Service.Hades("public/hades/queryQuestionDetails", params); return Service.Hades('public/hades/queryQuestionDetails', params)
} }
export function editQuestion(params: object) { export function editQuestion(params: object) {
return Service.Hades("public/hades/editQuestion", params); return Service.Hades('public/hades/editQuestion', params)
} }
export function batchImport(params: object) { export function batchImport(params: object) {
return Service.Hades("public/hades/batchImport", params); return Service.Hades('public/hades/batchImport', params)
} }
export function createPaper(params: object) { export function createPaper(params: object) {
return Service.Hades("public/hades/createPaper", params); return Service.Hades('public/hades/createPaper', params)
} }
export function queryPaperPageList(params: object) { export function queryPaperPageList(params: object) {
return Service.Hades("public/hades/queryPaperPageList", params); return Service.Hades('public/hades/queryPaperPageList', params)
} }
export function deletePaper(params: object) { export function deletePaper(params: object) {
return Service.Hades("public/hades/deletePaper", params); return Service.Hades('public/hades/deletePaper', params)
} }
export function queryPaperDetail(params: object) { export function queryPaperDetail(params: object) {
return Service.Hades("public/hades/queryPaperDetail", params); return Service.Hades('public/hades/queryPaperDetail', params)
} }
export function viewPaper(params: object) { export function viewPaper(params: object) {
return Service.Hades("public/hades/viewPaper", params); return Service.Hades('public/hades/viewPaper', params)
} }
export function editPaper(params: object) { export function editPaper(params: object) {
return Service.Hades("public/hades/editPaper", params); return Service.Hades('public/hades/editPaper', params)
} }
export function batchQueryQuestionDetails(params: object) { export function batchQueryQuestionDetails(params: object) {
return Service.Hades("public/hades/batchQueryQuestionDetails", params); return Service.Hades('public/hades/batchQueryQuestionDetails', params)
} }
export function queryQuestionPageListWithContent(params: object) { export function queryQuestionPageListWithContent(params: object) {
return Service.Hades("public/hades/queryQuestionPageListWithContent", params); return Service.Hades('public/hades/queryQuestionPageListWithContent', params)
} }
/* /*
* @Author: yuananting * @Author: yuananting
* @Date: 2021-03-11 11:34:37 * @Date: 2021-03-11 11:34:37
* @LastEditors: yuananting * @LastEditors: fusanqiasng
* @LastEditTime: 2021-04-13 13:58:11 * @LastEditTime: 2021-05-24 23:44:39
* @Description: 助学工具接口 * @Description: 助学工具接口
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import { import {
queryExternalCategoryTree,
queryCategoryTree, queryCategoryTree,
addCategory, addCategory,
delCategory, delCategory,
...@@ -25,101 +26,110 @@ import { ...@@ -25,101 +26,110 @@ import {
viewPaper, viewPaper,
editPaper, editPaper,
batchQueryQuestionDetails, batchQueryQuestionDetails,
queryQuestionPageListWithContent, queryQuestionPageListWithContent
} from '@/data-source/aidTool/request-apis'; } from '@/data-source/aidTool/request-apis'
export default class AidToolService { export default class AidToolService {
/**
* 查询运营端分类书
* @param parmas
* @returns
*/
static queryExternalCategoryTree(parmas: any) {
return queryExternalCategoryTree(parmas)
}
// 获取题目分类树 // 获取题目分类树
static queryCategoryTree(params: any) { static queryCategoryTree(params: any) {
return queryCategoryTree(params); return queryCategoryTree(params)
} }
// 新增题目分类 // 新增题目分类
static addCategory(params: any) { static addCategory(params: any) {
return addCategory(params); return addCategory(params)
} }
// 删除分类 // 删除分类
static delCategory(params: any) { static delCategory(params: any) {
return delCategory(params); return delCategory(params)
} }
// 编辑分类 // 编辑分类
static editCategory(params: any) { static editCategory(params: any) {
return editCategory(params); return editCategory(params)
} }
// 编辑分类树(拖拽) // 编辑分类树(拖拽)
static editCategoryTree(params: any) { static editCategoryTree(params: any) {
return editCategoryTree(params); return editCategoryTree(params)
} }
// 查询题目列表 // 查询题目列表
static queryQuestionPageList(params: any) { static queryQuestionPageList(params: any) {
return queryQuestionPageList(params); return queryQuestionPageList(params)
} }
// 添加题目 // 添加题目
static addQuestion(params: any) { static addQuestion(params: any) {
return addQuestion(params); return addQuestion(params)
} }
// 删除题目 // 删除题目
static deleteQuestion(params: any) { static deleteQuestion(params: any) {
return deleteQuestion(params); return deleteQuestion(params)
} }
// 预览题目 // 预览题目
static queryQuestionDetails(params: any) { static queryQuestionDetails(params: any) {
return queryQuestionDetails(params); return queryQuestionDetails(params)
} }
// 编辑题目 // 编辑题目
static editQuestion(params: any) { static editQuestion(params: any) {
return editQuestion(params); return editQuestion(params)
} }
// 批量导入 // 批量导入
static batchImport(params: any) { static batchImport(params: any) {
return batchImport(params); return batchImport(params)
} }
// 创建试卷 // 创建试卷
static createPaper(params: any) { static createPaper(params: any) {
return createPaper(params); return createPaper(params)
} }
// 查询试卷列表 // 查询试卷列表
static queryPaperPageList(params: any) { static queryPaperPageList(params: any) {
return queryPaperPageList(params); return queryPaperPageList(params)
} }
// 删除试卷 // 删除试卷
static deletePaper(params: any) { static deletePaper(params: any) {
return deletePaper(params); return deletePaper(params)
} }
// 编辑前查询试卷信息 // 编辑前查询试卷信息
static queryPaperDetail(params: any) { static queryPaperDetail(params: any) {
return queryPaperDetail(params); return queryPaperDetail(params)
} }
// 预览试卷 // 预览试卷
static viewPaper(params: any) { static viewPaper(params: any) {
return viewPaper(params); return viewPaper(params)
} }
// 编辑试卷 // 编辑试卷
static editPaper(params: any) { static editPaper(params: any) {
return editPaper(params); return editPaper(params)
} }
// 操作试卷-预览查询多题目信息 // 操作试卷-预览查询多题目信息
static batchQueryQuestionDetails(params: any) { static batchQueryQuestionDetails(params: any) {
return batchQueryQuestionDetails(params); return batchQueryQuestionDetails(params)
} }
// 操作试卷-选择题目列表带题目详情 // 操作试卷-选择题目列表带题目详情
static queryQuestionPageListWithContent(params: any) { static queryQuestionPageListWithContent(params: any) {
return queryQuestionPageListWithContent(params); return queryQuestionPageListWithContent(params)
} }
} }
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-07-23 14:54:16 * @Date: 2020-07-23 14:54:16
* @LastEditors: wufan * @LastEditors: fusanqiasng
* @LastEditTime: 2021-02-01 16:33:18 * @LastEditTime: 2021-05-24 21:02:21
* @Description: 大班直播课预览弹窗 * @Description: 大班直播课预览弹窗
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
import React from 'react'; import React from 'react'
import { Modal } from 'antd'; import { Modal } from 'antd'
import moment from 'moment'; import moment from 'moment'
import './PreviewCourseModal.less'; import './PreviewCourseModal.less'
const courseStateShow = { const courseStateShow = {
UN_START: { UN_START: {
title: "待开课", title: '待开课'
}, },
STARTING: { STARTING: {
title: "上课中", title: '上课中'
}, },
FINISH: { FINISH: {
title: "已完成", title: '已完成'
}, },
EXPIRED: { EXPIRED: {
code: 4, code: 4,
title: "未成功开课", title: '未成功开课',
color: "#CCCCCC", color: '#CCCCCC'
}, }
}; }
class PreviewCourseModal extends React.Component { class PreviewCourseModal extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props)
this.state = { this.state = {}
}
} }
dealTimeDuration = (time) => { dealTimeDuration = (time) => {
const diff = Math.floor(time % 3600); const diff = Math.floor(time % 3600)
let hours = Math.floor(time / 3600); let hours = Math.floor(time / 3600)
let mins = Math.floor(diff / 60); let mins = Math.floor(diff / 60)
let seconds = Math.floor(time % 60); let seconds = Math.floor(time % 60)
hours = hours < 10 ? ("0" + hours) : hours; hours = hours < 10 ? '0' + hours : hours
mins = mins < 10 ? ("0" + mins) : mins; mins = mins < 10 ? '0' + mins : mins
seconds = seconds < 10 ? ("0" + seconds) : seconds; seconds = seconds < 10 ? '0' + seconds : seconds
return hours + ":" + mins + ":" + seconds; return hours + ':' + mins + ':' + seconds
} }
dealWithTime = (startTime, endTime) => { dealWithTime = (startTime, endTime) => {
const startDate = new Date(Number(startTime)); const startDate = new Date(Number(startTime))
const endDate = new Date(Number(endTime)); const endDate = new Date(Number(endTime))
const year = startDate.getFullYear(); const year = startDate.getFullYear()
const month = (startDate.getMonth() + 1) < 10 ? `0${startDate.getMonth() + 1}` : startDate.getMonth() + 1; const month = startDate.getMonth() + 1 < 10 ? `0${startDate.getMonth() + 1}` : startDate.getMonth() + 1
const day = startDate.getDate() < 10 ? `0${startDate.getDate()}` : startDate.getDate(); const day = startDate.getDate() < 10 ? `0${startDate.getDate()}` : startDate.getDate()
const startHour = startDate.getHours() < 10 ? `0${startDate.getHours()}` : startDate.getHours(); const startHour = startDate.getHours() < 10 ? `0${startDate.getHours()}` : startDate.getHours()
const startMinute = startDate.getMinutes() < 10 ? `0${startDate.getMinutes()}` : startDate.getMinutes(); const startMinute = startDate.getMinutes() < 10 ? `0${startDate.getMinutes()}` : startDate.getMinutes()
const endHour = endDate.getHours() < 10 ? `0${endDate.getHours()}` : endDate.getHours(); const endHour = endDate.getHours() < 10 ? `0${endDate.getHours()}` : endDate.getHours()
const endMinute = endDate.getMinutes() < 10 ? `0${endDate.getMinutes()}` : endDate.getMinutes(); const endMinute = endDate.getMinutes() < 10 ? `0${endDate.getMinutes()}` : endDate.getMinutes()
const liveDateStr = `${year}-${month}-${day}`; const liveDateStr = `${year}-${month}-${day}`
const startTimeStr = `${startHour}:${startMinute}`; const startTimeStr = `${startHour}:${startMinute}`
const endTimeStr = `${endHour}:${endMinute}`; const endTimeStr = `${endHour}:${endMinute}`
return { return {
liveDateStr, liveDateStr,
startTimeStr, startTimeStr,
endTimeStr, endTimeStr
}; }
} }
render() { render() {
const { courseBasicInfo, courseClassInfo = {}, courseIntroInfo, type,courseState,origin} = this.props; const { courseBasicInfo, courseClassInfo = {}, courseIntroInfo, type, courseState, origin } = this.props
const { coverUrl, courseName, scheduleVideoUrl,videoDuration} = courseBasicInfo; const { coverUrl, courseName, scheduleVideoUrl, videoDuration } = courseBasicInfo
const { liveDate, calendarTime,startTime,endTime,timeHorizonStart, timeHorizonEnd, teacherName } = courseClassInfo; const { liveDate, calendarTime, startTime, endTime, timeHorizonStart, timeHorizonEnd, teacherName } = courseClassInfo
const { introduce } = courseIntroInfo; const { introduce } = courseIntroInfo
let liveDateStr, startTimeStr, endTimeStr; let liveDateStr, startTimeStr, endTimeStr
if (type === 'add') { if (type === 'add') {
const _liveDate = moment(calendarTime[0]).format("YYYY-MM-DD"); const _liveDate = moment(calendarTime[0]).format('YYYY-MM-DD')
console.log("_liveDate",_liveDate); console.log('_liveDate', _liveDate)
const _timeHorizonStart = moment(startTime).format('HH:mm'); const _timeHorizonStart = moment(startTime).format('HH:mm')
const _timeHorizonEnd = moment(endTime).format('HH:mm'); const _timeHorizonEnd = moment(endTime).format('HH:mm')
const _startTime = moment(_liveDate + ' ' + _timeHorizonStart).format('x'); const _startTime = moment(_liveDate + ' ' + _timeHorizonStart).format('x')
const _endTime = moment(_liveDate + ' ' + _timeHorizonEnd).format('x'); const _endTime = moment(_liveDate + ' ' + _timeHorizonEnd).format('x')
const { const { liveDateStr: _liveDateStr, startTimeStr: _startTimeStr, endTimeStr: _endTimeStr } = this.dealWithTime(_startTime, _endTime)
liveDateStr: _liveDateStr,
startTimeStr: _startTimeStr, liveDateStr = _liveDateStr
endTimeStr: _endTimeStr startTimeStr = _startTimeStr
} = this.dealWithTime(_startTime, _endTime); endTimeStr = _endTimeStr
} else {
liveDateStr = _liveDateStr; const _liveDate = moment(liveDate).format('YYYY-MM-DD')
startTimeStr = _startTimeStr; const _timeHorizonStart = moment(timeHorizonStart).format('HH:mm')
endTimeStr = _endTimeStr; const _timeHorizonEnd = moment(timeHorizonEnd).format('HH:mm')
}else{ const startTime = moment(_liveDate + ' ' + _timeHorizonStart).format('x')
const _liveDate = moment(liveDate).format("YYYY-MM-DD"); const endTime = moment(_liveDate + ' ' + _timeHorizonEnd).format('x')
const _timeHorizonStart = moment(timeHorizonStart).format('HH:mm'); const { liveDateStr: _liveDateStr, startTimeStr: _startTimeStr, endTimeStr: _endTimeStr } = this.dealWithTime(startTime, endTime)
const _timeHorizonEnd = moment(timeHorizonEnd).format('HH:mm');
const startTime = moment(_liveDate + ' ' + _timeHorizonStart).format('x'); liveDateStr = _liveDateStr
const endTime = moment(_liveDate + ' ' + _timeHorizonEnd).format('x'); startTimeStr = _startTimeStr
const { endTimeStr = _endTimeStr
liveDateStr: _liveDateStr,
startTimeStr: _startTimeStr,
endTimeStr: _endTimeStr
} = this.dealWithTime(startTime, endTime);
liveDateStr = _liveDateStr;
startTimeStr = _startTimeStr;
endTimeStr = _endTimeStr;
} }
return ( return (
<Modal <Modal
title="预览" title='预览'
visible={true} visible={true}
width={680} width={680}
onCancel={this.props.close} onCancel={this.props.close}
footer={null} footer={null}
maskClosable={false} maskClosable={false}
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>} closeIcon={<span className='icon iconfont modal-close-icon'>&#xe6ef;</span>}
className="preview-live-course-modal" className='preview-live-course-modal'>
> <div className='container__wrap'>
<div className="container__wrap"> <div className='container'>
<div className="container"> <div className='container__header'>
<div className="container__header"> {type === 'videoCourse' ? (
{
type === 'videoCourse' ?
<video <video
controls controls
src={scheduleVideoUrl} src={scheduleVideoUrl}
poster={coverUrl ? coverUrl : `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`} poster={coverUrl ? coverUrl : `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`}
className="course-url" className='course-url'
/> : />
<img src={coverUrl} className="course-cover" /> ) : (
} <img src={coverUrl} className='course-cover' />
)}
</div> </div>
{ {type === 'videoCourse' ? (
type === 'videoCourse' ? <div className='container__body'>
<div className="container__body"> <div className='title__name'>{courseName}</div>
<div className="title__name">{courseName}</div> {videoDuration && <div>视频时长:{this.dealTimeDuration(videoDuration)}</div>}
{videoDuration &&
<div>视频时长:{this.dealTimeDuration(videoDuration)}</div>
}
</div> </div>
: ) : (
<div className="container__body"> <div className='container__body'>
<div className="container__body__title"> <div className='container__body__title'>
<div className="title__name">{courseName}</div> <div className='title__name'>{courseName}</div>
<div className="title__state">{courseStateShow[courseState].title}</div> <div className='title__state'>{courseStateShow[courseState].title}</div>
</div> </div>
<div className="container__body__time"> <div className='container__body__time'>
<span className="time__label">上课时间:</span> <span className='time__label'>上课时间:</span>
<span className="time__value"> <span className='time__value'>
{ {[
[
<span>{liveDateStr}&nbsp;</span>, <span>{liveDateStr}&nbsp;</span>,
<span>{startTimeStr}~{endTimeStr }</span> <span>
] {startTimeStr}~{endTimeStr}
} </span>
]}
</span> </span>
</div> </div>
<div className="container__body__teacher"> <div className='container__body__teacher'>
<span className="teacher__label">上课老师:</span> <span className='teacher__label'>上课老师:</span>
<span className="teacher__value">{teacherName}</span> <span className='teacher__value'>{teacherName}</span>
</div> </div>
</div> </div>
} )}
<div className="container__introduction"> <div className='container__introduction'>
{ type === 'videoCourse' ? {type === 'videoCourse' ? (
<div className="container__introduction__title">视频课简介</div> <div className='container__introduction__title'>视频课简介</div>
: ) : (
<div className="container__introduction__title">直播课简介</div> <div className='container__introduction__title'>直播课简介</div>
} )}
<div className="container__introduction__list editor-box"> <div className='container__introduction__list editor-box'>
<div <div
className="intro-item text" className='intro-item text'
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: introduce __html: introduce
}} }}
...@@ -192,4 +176,4 @@ class PreviewCourseModal extends React.Component { ...@@ -192,4 +176,4 @@ class PreviewCourseModal extends React.Component {
} }
} }
export default PreviewCourseModal; export default PreviewCourseModal
import React from 'react'; import React from 'react'
import {Table, Modal,Input} from 'antd'; import { Table, Modal, Input } from 'antd'
import { PageControl } from "@/components"; import { PageControl } from '@/components'
import CourseService from "@/domains/course-domain/CourseService"; import CourseService from '@/domains/course-domain/CourseService'
import PlanService from "@/domains/plan-domain/planService"; import PlanService from '@/domains/plan-domain/planService'
import User from '@/common/js/user' import User from '@/common/js/user'
import './RelatedPlanModal.less'; import './RelatedPlanModal.less'
import _ from "underscore"; import _ from 'underscore'
const { Search } = Input; const { Search } = Input
class RelatedPlanModal extends React.Component { class RelatedPlanModal extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props)
this.state = { this.state = {
dataSource:[], dataSource: [],
size:10, size: 10,
query: { query: {
current: 1, current: 1
}, },
totalCount:0, totalCount: 0,
selectPlanList:{}, selectPlanList: {}
}; }
} }
componentDidMount() { componentDidMount() {
this.handleFetchDataList(); this.handleFetchDataList()
} }
// 获取培训计划列表 // 获取培训计划列表
handleFetchDataList = () => { handleFetchDataList = () => {
const {query,size,totalCount} = this.state const { query, size } = this.state
const params ={ const params = {
...query, ...query,
size, size,
storeId:User.getStoreId() storeId: User.getStoreId()
} }
PlanService.getStorePlanAll(params).then((res) => { PlanService.getStorePlanAll(params).then((res) => {
const { result = {} } = res ; const { result = {} } = res
const { records = [], total = 0 } = result; const { records = [], total = 0 } = result
this.setState({ this.setState({
dataSource: records, dataSource: records,
totalCount: Number(total) totalCount: Number(total)
}); })
}); })
} }
handleChangePlanName = (value)=>{ handleChangePlanName = (value) => {
const {query} = this.state; const { query } = this.state
query.planName = value; query.planName = value
query.current = 1; query.current = 1
this.setState({ this.setState({
query query
}) })
...@@ -54,9 +54,14 @@ class RelatedPlanModal extends React.Component { ...@@ -54,9 +54,14 @@ class RelatedPlanModal extends React.Component {
if (current == size) { if (current == size) {
return return
} }
this.setState({ this.setState(
{
size size
},()=>{this.handleFetchDataList()}) },
() => {
this.handleFetchDataList()
}
)
} }
// 请求表头 // 请求表头
...@@ -66,14 +71,12 @@ class RelatedPlanModal extends React.Component { ...@@ -66,14 +71,12 @@ class RelatedPlanModal extends React.Component {
title: '培训计划', title: '培训计划',
key: 'planName', key: 'planName',
dataIndex: 'planName', dataIndex: 'planName',
render:(val,record)=>{ render: (val, record) => {
return ( return <span>{val}</span>
<span>{val}</span>
)
} }
} }
]; ]
return columns; return columns
} }
parseTaskColumns = (parentIndex) => { parseTaskColumns = (parentIndex) => {
...@@ -82,173 +85,189 @@ class RelatedPlanModal extends React.Component { ...@@ -82,173 +85,189 @@ class RelatedPlanModal extends React.Component {
title: '任务名称', title: '任务名称',
key: 'taskName', key: 'taskName',
dataIndex: 'taskName', dataIndex: 'taskName',
render:(val,record)=>{ render: (val, record) => {
return ( return <span>{val}</span>
<span>{val}</span>
)
} }
} }
]; ]
return columns; return columns
} }
selectPlanList = (record,selected,planId) =>{ selectPlanList = (record, selected, planId) => {
const { selectPlanList } = this.props; const { selectPlanList } = this.props
let _selectPlanList = {...selectPlanList}; let _selectPlanList = { ...selectPlanList }
if (selected) { if (selected) {
if(!_selectPlanList[planId]){ if (!_selectPlanList[planId]) {
_selectPlanList[planId] = {} _selectPlanList[planId] = {}
} }
_selectPlanList[planId].taskBaseVOList = []; _selectPlanList[planId].taskBaseVOList = []
_selectPlanList[planId].planId = planId; _selectPlanList[planId].planId = planId
_selectPlanList[planId].taskBaseVOList.push(record); _selectPlanList[planId].taskBaseVOList.push(record)
} else { } else {
if(!_selectPlanList[planId]){ if (!_selectPlanList[planId]) {
_selectPlanList[planId] = {} _selectPlanList[planId] = {}
} }
_selectPlanList[planId].taskBaseVOList = []; _selectPlanList[planId].taskBaseVOList = []
_selectPlanList[planId].planId = planId; _selectPlanList[planId].planId = planId
} }
this.props.onChange(_selectPlanList); this.props.onChange(_selectPlanList)
// this.setState({selectPlanList:_selectPlanList}); // this.setState({selectPlanList:_selectPlanList});
} }
handleSelectPlanListData(selectPlanList){ handleSelectPlanListData(selectPlanList) {
let _selectPlanList = []; let _selectPlanList = []
for(let key in selectPlanList ){ for (let key in selectPlanList) {
let item = {}; let item = {}
if(selectPlanList[key].taskBaseVOList){ if (selectPlanList[key].taskBaseVOList) {
item.planId = selectPlanList[key].planId; item.planId = selectPlanList[key].planId
if(selectPlanList[key].taskBaseVOList[0]){ if (selectPlanList[key].taskBaseVOList[0]) {
item.taskId = selectPlanList[key].taskBaseVOList[0].taskId; item.taskId = selectPlanList[key].taskBaseVOList[0].taskId
} }
} }
if(item.taskId){ if (item.taskId) {
_selectPlanList.push(item) _selectPlanList.push(item)
} }
} }
return _selectPlanList; return _selectPlanList
} }
confirmRelatedPlan =()=>{ confirmRelatedPlan = () => {
const {selectPlanList } = this.props; const { selectPlanList } = this.props
const params = { const params = {
courseId:this.props.selectCourseId, courseId: this.props.selectCourseId,
relatedPlanList:this.handleSelectPlanListData(selectPlanList), relatedPlanList: this.handleSelectPlanListData(selectPlanList),
storeId:User.getStoreId(), storeId: User.getStoreId()
} }
CourseService.relatedCourseToPlan(params).then((res) => { CourseService.relatedCourseToPlan(params).then((res) => {
this.props.onConfirm(); this.props.onConfirm()
}); })
} }
getSelectLength = (selectList)=>{ getSelectLength = (selectList) => {
let num = 0; let num = 0
for(let key in selectList ){ for (let key in selectList) {
if(selectList[key].taskBaseVOList.length > 0){ if (selectList[key].taskBaseVOList.length > 0) {
num = num + 1 num = num + 1
} }
} }
return num; return num
} }
clearSelect = ()=>{ clearSelect = () => {
const _selectPlanList = {}; const _selectPlanList = {}
this.props.onChange(_selectPlanList); this.props.onChange(_selectPlanList)
} }
render() { render() {
const { size,dataSource,totalCount,query} = this.state; const { size, dataSource, totalCount, query } = this.state
const { visible,selectPlanList} = this.props; const { visible, selectPlanList } = this.props
return ( return (
<Modal <Modal
title="关联培训计划" title='关联培训计划'
onCancel={this.props.onClose} onCancel={this.props.onClose}
maskClosable={false} maskClosable={false}
visible={visible} visible={visible}
className="related-plan-modal" className='related-plan-modal'
closable={true} closable={true}
width={800} width={800}
onOk={() => this.confirmRelatedPlan() } onOk={() => this.confirmRelatedPlan()}
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>} closeIcon={<span className='icon iconfont modal-close-icon'>&#xe6ef;</span>}>
> <div className='search-container'>
<div className="search-container"> <Search
<Search placeholder="搜索培训计划名称" placeholder='搜索培训计划名称'
style={{ width: 207 }} style={{ width: 207 }}
onChange={(e) => { this.handleChangePlanName(e.target.value)}} onChange={(e) => {
onSearch={ () => { this.handleFetchDataList()}} this.handleChangePlanName(e.target.value)
enterButton={<span className="icon iconfont">&#xe832;</span>} }}
onSearch={() => {
this.handleFetchDataList()
}}
enterButton={<span className='icon iconfont'>&#xe832;</span>}
/> />
</div> </div>
<div className="select-container"> <div className='select-container'>
<span className="con"> <span className='con'>
<div> <div>
<span className="icon iconfont tip">&#xe6f2;</span> <span className='icon iconfont tip'>&#xe6f2;</span>
<span className="text">已选择{this.getSelectLength(selectPlanList)}个任务</span> <span className='text'>已选择{this.getSelectLength(selectPlanList)}个任务</span>
</div> </div>
<div> <div>
<span className="clear" onClick={this.clearSelect}>清空</span> <span className='clear' onClick={this.clearSelect}>
清空
</span>
</div> </div>
</span> </span>
</div> </div>
<div> <div>
<Table <Table
rowKey={record => record.planId} rowKey={(record) => record.planId}
className="plan-table" className='plan-table'
dataSource={dataSource} dataSource={dataSource}
columns={this.parsePlanColumns()} columns={this.parsePlanColumns()}
pagination={false} pagination={false}
expandedRowRender={(_record,index) => { expandedRowRender={(_record, index) => {
if(!_record.taskBaseVOList){ if (!_record.taskBaseVOList) {
return return
} }
if (_record.taskBaseVOList.length !== 0 ){ if (_record.taskBaseVOList.length !== 0) {
const selectPlan = selectPlanList[_record.planId] const selectPlan = selectPlanList[_record.planId]
let taskBaseVOList = []; let taskBaseVOList = []
if(selectPlan){ if (selectPlan) {
taskBaseVOList = selectPlan.taskBaseVOList; taskBaseVOList = selectPlan.taskBaseVOList
} }
console.log('taskBaseVOList',taskBaseVOList); console.log('taskBaseVOList', taskBaseVOList)
return <div> return (
<div>
<Table <Table
rowKey={record => record.taskId} rowKey={(record) => record.taskId}
pagination={false} pagination={false}
dataSource={_record.taskBaseVOList} dataSource={_record.taskBaseVOList}
columns={this.parseTaskColumns(index)} columns={this.parseTaskColumns(index)}
className="child-table" className='child-table'
rowSelection={{ rowSelection={{
type: 'checkbox', type: 'checkbox',
selectedRowKeys: _.pluck(taskBaseVOList, 'taskId'), selectedRowKeys: _.pluck(taskBaseVOList, 'taskId'),
onSelect: (record, selected) => { onSelect: (record, selected) => {
this.selectPlanList(record,selected,_record.planId); this.selectPlanList(record, selected, _record.planId)
},
onSelectAll: (selected, _selectedRows, changeRows) => {
}, },
onSelectAll: (selected, _selectedRows, changeRows) => {}
}} }}
/> />
</div> </div>
)
}
}}
rowClassName={(record, index) => {
if (index % 2 === 0) {
return 'odd-row'
} else {
return 'even-row'
} }
}} }}
rowClassName={(record,index)=>{if(index%2===0){return 'odd-row'}else{ return 'even-row'}}}
/> />
{dataSource.length >0 && {dataSource.length > 0 && (
<div className="box-footer"> <div className='box-footer'>
<PageControl <PageControl
current={query.current - 1} current={query.current - 1}
pageSize={size} pageSize={size}
total={totalCount} total={totalCount}
size="small" size='small'
toPage={(page) => { toPage={(page) => {
const _query = {...query, current: page + 1}; const _query = { ...query, current: page + 1 }
this.setState({ this.setState(
query:_query {
},()=>{ this.handleFetchDataList()}) query: _query
},
() => {
this.handleFetchDataList()
}
)
}} }}
onShowSizeChange={this.onShowSizeChange} onShowSizeChange={this.onShowSizeChange}
/> />
</div> </div>
} )}
</div> </div>
</Modal> </Modal>
) )
} }
} }
export default RelatedPlanModal; export default RelatedPlanModal
\ No newline at end of file
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-05 10:07:47 * @Date: 2020-08-05 10:07:47
* @LastEditors: zhangleyuan * @LastEditors: fusanqiasng
* @LastEditTime: 2021-05-10 10:15:46 * @LastEditTime: 2021-05-24 21:04:03
* @Description: 视频课新增/编辑页 * @Description: 视频课新增/编辑页
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
import React from 'react'; import React from 'react'
import { Button, Input, Radio, message, Modal,Cascader} from 'antd'; import { Button, Input, Radio, message, Modal, Cascader } from 'antd'
import { DISK_MAP, FileTypeIcon, FileVerifyMap } from '@/common/constants/academic/lessonEnum'; import { DISK_MAP, FileTypeIcon, FileVerifyMap } from '@/common/constants/academic/lessonEnum'
import { ImgCutModalNew } from '@/components'; import { ImgCutModalNew } from '@/components'
import ShowTips from "@/components/ShowTips"; import ShowTips from '@/components/ShowTips'
import Breadcrumbs from "@/components/Breadcrumbs"; import Breadcrumbs from '@/components/Breadcrumbs'
import AddVideoIntro from './components/AddVideoIntro'; import AddVideoIntro from './components/AddVideoIntro'
import SelectStudent from '../modal/select-student'; import SelectStudent from '../modal/select-student'
import SelectPrepareFileModal from '../../prepare-lesson/modal/SelectPrepareFileModal'; import SelectPrepareFileModal from '../../prepare-lesson/modal/SelectPrepareFileModal'
import PreviewCourseModal from '../modal/PreviewCourseModal'; import PreviewCourseModal from '../modal/PreviewCourseModal'
import StoreService from "@/domains/store-domain/storeService"; import StoreService from '@/domains/store-domain/storeService'
import CourseService from "@/domains/course-domain/CourseService"; import CourseService from '@/domains/course-domain/CourseService'
import Service from '@/common/js/service'; import Service from '@/common/js/service'
import User from '@/common/js/user'; import User from '@/common/js/user'
import _ from "underscore"; import _ from 'underscore'
import Upload from '@/core/upload'; import Upload from '@/core/upload'
import { randomString } from '@/domains/basic-domain/utils'; import { randomString } from '@/domains/basic-domain/utils'
import $ from 'jquery'; import $ from 'jquery'
// import PhotoClip from 'photoclip'; // import PhotoClip from 'photoclip';
import './AddVideoCourse.less'; import './AddVideoCourse.less'
const EDIT_BOX_KEY = Math.random(); const EDIT_BOX_KEY = Math.random()
const fieldNames = { label: 'categoryName', value: 'id', children: 'sonCategoryList' }; const fieldNames = { label: 'categoryName', value: 'id', children: 'sonCategoryList' }
//添加课程时课程默认的一些值 //添加课程时课程默认的一些值
const defaultShelfState = 'YES'; const defaultShelfState = 'YES'
const defaultScheduleMedia = [{ const defaultScheduleMedia = [
contentType:'INTRO', {
contentType: 'INTRO',
mediaType: 'TEXT', mediaType: 'TEXT',
mediaContent: '', mediaContent: '',
key: EDIT_BOX_KEY key: EDIT_BOX_KEY
}] }
]
const whetherVisitorsJoin = 'NO' const whetherVisitorsJoin = 'NO'
let cutFlag = false; let cutFlag = false
class AddVideoCourse extends React.Component { class AddVideoCourse extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props)
const id = getParameterByName("id"); const id = getParameterByName('id')
const pageType = getParameterByName("type"); const pageType = getParameterByName('type')
this.state = { this.state = {
id, // 视频课ID,编辑的时候从URL上带过来 id, // 视频课ID,编辑的时候从URL上带过来
...@@ -61,57 +62,60 @@ class AddVideoCourse extends React.Component { ...@@ -61,57 +62,60 @@ class AddVideoCourse extends React.Component {
coverId: null, // 视频封面的recourceId coverId: null, // 视频封面的recourceId
coverUrl: null, // 视频课封面 coverUrl: null, // 视频课封面
studentList: [], // 上课学员列表 studentList: [], // 上课学员列表
shelfState:'YES', //是否开启学院展示 shelfState: 'YES', //是否开启学院展示
scheduleMedia: [{ // 视频课媒体资源 scheduleMedia: [
contentType:"INTRO", {
// 视频课媒体资源
contentType: 'INTRO',
mediaType: 'TEXT', mediaType: 'TEXT',
mediaContent: '', mediaContent: '',
key: EDIT_BOX_KEY key: EDIT_BOX_KEY
}], }
],
diskList: [], // 机构可见磁盘目录 diskList: [], // 机构可见磁盘目录
selectedFileList: [], // 已经从资料云盘中勾选的文件 selectedFileList: [], // 已经从资料云盘中勾选的文件
showCutModal: false, // 是否显示截图弹窗 showCutModal: false, // 是否显示截图弹窗
showSelectFileModal: false, showSelectFileModal: false,
studentModal: false, studentModal: false,
categoryName:null, //分类名称 categoryName: null, //分类名称
courseCatalogList:[], //分类列表 courseCatalogList: [], //分类列表
categoryId:null, //分类的Id值 categoryId: null, //分类的Id值
whetherVisitorsJoin:'NO', // 是否允许游客加入 whetherVisitorsJoin: 'NO', // 是否允许游客加入
showSelectCoverModal:false, showSelectCoverModal: false,
cutImageBlob: null, cutImageBlob: null,
introduce: '', introduce: ''
} }
} }
componentWillMount() { componentWillMount() {
const { id, pageType } = this.state; const { id, pageType } = this.state
this.getCourseCatalogList(); this.getCourseCatalogList()
if (pageType === 'edit') { if (pageType === 'edit') {
this.handleFetchScheudleDetail(id); this.handleFetchScheudleDetail(id)
} }
} }
//获取分类列表 //获取分类列表
getCourseCatalogList = ()=>{ getCourseCatalogList = () => {
StoreService.getCourseCatalogList({current:1,size:1000}).then((res) => { StoreService.getCourseCatalogList({ current: 1, size: 1000 }).then((res) => {
this.setState({ this.setState({
courseCatalogList:res.result.records courseCatalogList: res.result.records
})
}) })
});
} }
catalogChange= (value) => { catalogChange = (value) => {
const changeValueLength = value.length; const changeValueLength = value.length
switch (changeValueLength){ switch (changeValueLength) {
case 1: case 1:
this.setState({categoryId:value[0]}); this.setState({ categoryId: value[0] })
break; break
case 2: case 2:
this.setState({categoryId:value[1]}); this.setState({ categoryId: value[1] })
break; break
default: default:
this.setState({categoryId:null}); this.setState({ categoryId: null })
break; break
} }
} }
// 获取视频课详情 // 获取视频课详情
...@@ -119,54 +123,46 @@ class AddVideoCourse extends React.Component { ...@@ -119,54 +123,46 @@ class AddVideoCourse extends React.Component {
CourseService.videoScheduleDetail({ CourseService.videoScheduleDetail({
courseId courseId
}).then((res) => { }).then((res) => {
const { result = {} } = res || {}; const { result = {} } = res || {}
const { const { courseName, shelfState, whetherVisitorsJoin, courseMediaVOS, categoryOneName, categoryTwoName, categoryId } = result
courseName, let coverId
shelfState, let coverUrl
whetherVisitorsJoin, let videoType
courseMediaVOS, let videoDuration
categoryOneName, let videoName
categoryTwoName, let scheduleMedia = []
categoryId let scheduleVideoId
} = result; let scheduleVideoUrl
let coverId; let hasIntro
let coverUrl;
let videoType;
let videoDuration;
let videoName;
let scheduleMedia = [];
let scheduleVideoId;
let scheduleVideoUrl;
let hasIntro;
courseMediaVOS.map((item) => { courseMediaVOS.map((item) => {
switch (item.contentType){ switch (item.contentType) {
case "COVER": case 'COVER':
coverId = item.mediaContent; coverId = item.mediaContent
coverUrl = item.mediaUrl; coverUrl = item.mediaUrl
break; break
case "SCHEDULE": case 'SCHEDULE':
videoDuration = item.videoDuration; videoDuration = item.videoDuration
videoName = item.mediaName; videoName = item.mediaName
scheduleVideoId = item.mediaContent; scheduleVideoId = item.mediaContent
scheduleVideoUrl = item.mediaUrl; scheduleVideoUrl = item.mediaUrl
videoType = item.mediaType; videoType = item.mediaType
break; break
case "INTRO": case 'INTRO':
hasIntro = true; hasIntro = true
this.getTextDetail('introduce', item.mediaUrl); this.getTextDetail('introduce', item.mediaUrl)
break; break
default: default:
break; break
} }
return item; return item
}) })
let categoryName; let categoryName
if( categoryTwoName ){ if (categoryTwoName) {
categoryName = `${categoryOneName}-${categoryTwoName}`; categoryName = `${categoryOneName}-${categoryTwoName}`
}else{ } else {
categoryName = `${categoryOneName}`; categoryName = `${categoryOneName}`
} }
this.setState({ this.setState({
loadintroduce: !hasIntro, loadintroduce: !hasIntro,
...@@ -183,7 +179,7 @@ class AddVideoCourse extends React.Component { ...@@ -183,7 +179,7 @@ class AddVideoCourse extends React.Component {
whetherVisitorsJoin, whetherVisitorsJoin,
categoryName, categoryName,
categoryId categoryId
}); })
}) })
} }
...@@ -192,43 +188,42 @@ class AddVideoCourse extends React.Component { ...@@ -192,43 +188,42 @@ class AddVideoCourse extends React.Component {
data: {}, data: {},
type: 'GET', type: 'GET',
url, url,
contentType:'application/x-www-form-urlencoded; charset=UTF-8', contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
success: (res) => { success: (res) => {
this.setState({ [key]: res, [`load${key}`]: true }); this.setState({ [key]: res, [`load${key}`]: true })
} }
}) })
} }
handleGoBack = () => { handleGoBack = () => {
const { const { coverId, videoName, videoDuration, courseName, scheduleMedia, scheduleVideoId, categoryId, shelfState, whetherVisitorsJoin } = this.state
coverId, if (
videoName, videoName ||
videoDuration, videoDuration ||
courseName, scheduleVideoId ||
scheduleMedia, !_.isEqual(scheduleMedia, defaultScheduleMedia) ||
scheduleVideoId, categoryId ||
categoryId, courseName ||
shelfState, coverId ||
whetherVisitorsJoin shelfState !== defaultShelfState ||
} = this.state; whetherVisitorsJoin !== whetherVisitorsJoin
if(videoName || videoDuration || scheduleVideoId || !_.isEqual(scheduleMedia, defaultScheduleMedia) || categoryId || courseName || coverId || shelfState !== defaultShelfState || whetherVisitorsJoin !== whetherVisitorsJoin ){ ) {
Modal.confirm({ Modal.confirm({
title: '确认要返回吗?', title: '确认要返回吗?',
content: '返回后,本次编辑的内容将不被保存。', content: '返回后,本次编辑的内容将不被保存。',
okText: '确认返回', okText: '确认返回',
cancelText: '留在本页', cancelText: '留在本页',
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>, icon: <span className='icon iconfont default-confirm-icon'>&#xe6f4;</span>,
onOk: () => { onOk: () => {
window.RCHistory.push({ window.RCHistory.push({
pathname: `/video-course`, pathname: `/video-course`
}); })
} }
}); })
}else{ } else {
window.RCHistory.push({ window.RCHistory.push({
pathname: `/video-course`, pathname: `/video-course`
}); })
} }
} }
...@@ -237,51 +232,44 @@ class AddVideoCourse extends React.Component { ...@@ -237,51 +232,44 @@ class AddVideoCourse extends React.Component {
this.setState({ this.setState({
[field]: value, [field]: value,
coverUrl: coverUrl ? coverUrl : this.state.coverUrl coverUrl: coverUrl ? coverUrl : this.state.coverUrl
}); })
} }
// 显示选择学员弹窗 // 显示选择学员弹窗
handleShowSelectStuModal = () => { handleShowSelectStuModal = () => {
this.setState({ studentModal : true }); this.setState({ studentModal: true })
const { studentList, selectedStuList } = this.state; const { studentList, selectedStuList } = this.state
const studentModal = ( const studentModal = (
<SelectStudent <SelectStudent
showTabs={true} showTabs={true}
type="videoCourse" type='videoCourse'
onSelect={this.handleSelectStudent} onSelect={this.handleSelectStudent}
after={true} //表明是不是上课后的状态 after={true} //表明是不是上课后的状态
studentList={studentList} studentList={studentList}
close={() => { close={() => {
this.setState({ this.setState({
studentModal: null, studentModal: null
}); })
}} }}
/> />
) )
this.setState({ studentModal }); this.setState({ studentModal })
} }
handleSelectStudent = (studentIds) => { handleSelectStudent = (studentIds) => {
let studentList = []; let studentList = []
_.each(studentIds, (item) => { _.each(studentIds, (item) => {
studentList.push({ studentId: item }); studentList.push({ studentId: item })
}); })
// this.setState({ studentModal: null }); // this.setState({ studentModal: null });
this.setState({ studentList }); this.setState({ studentList })
this.setState({ studentModal : false }); this.setState({ studentModal: false })
} }
// 显示预览弹窗 // 显示预览弹窗
handleShowPreviewModal = () => { handleShowPreviewModal = () => {
const { const { coverUrl, scheduleVideoUrl, courseName, scheduleMedia, videoDuration, introduce } = this.state
coverUrl,
scheduleVideoUrl,
courseName,
scheduleMedia,
videoDuration,
introduce,
} = this.state;
const courseBasinInfo = { const courseBasinInfo = {
coverUrl, coverUrl,
...@@ -291,12 +279,12 @@ class AddVideoCourse extends React.Component { ...@@ -291,12 +279,12 @@ class AddVideoCourse extends React.Component {
} }
const courseIntroInfo = { const courseIntroInfo = {
liveCourseMediaRequests: scheduleMedia, liveCourseMediaRequests: scheduleMedia,
introduce, introduce
} }
const previewCourseModal = ( const previewCourseModal = (
<PreviewCourseModal <PreviewCourseModal
type="videoCourse" type='videoCourse'
courseBasicInfo={courseBasinInfo} courseBasicInfo={courseBasinInfo}
courseIntroInfo={courseIntroInfo} courseIntroInfo={courseIntroInfo}
close={() => { close={() => {
...@@ -305,9 +293,9 @@ class AddVideoCourse extends React.Component { ...@@ -305,9 +293,9 @@ class AddVideoCourse extends React.Component {
}) })
}} }}
/> />
); )
this.setState({ previewCourseModal }); this.setState({ previewCourseModal })
} }
// 选择视频 // 选择视频
...@@ -315,25 +303,25 @@ class AddVideoCourse extends React.Component { ...@@ -315,25 +303,25 @@ class AddVideoCourse extends React.Component {
this.setState({ this.setState({
showSelectFileModal: false showSelectFileModal: false
}) })
const { ossUrl, resourceId, folderName, folderFormat, folderSize } = file; const { ossUrl, resourceId, folderName, folderFormat, folderSize } = file
const videoDom = document.createElement('video'); const videoDom = document.createElement('video')
videoDom.src = ossUrl; videoDom.src = ossUrl
videoDom.onloadedmetadata = () => { videoDom.onloadedmetadata = () => {
this.setState({ this.setState({
size: folderSize, size: folderSize,
videoName: folderName, videoName: folderName,
videoType: folderFormat, videoType: folderFormat,
scheduleVideoUrl: ossUrl, scheduleVideoUrl: ossUrl,
scheduleVideoId : resourceId, scheduleVideoId: resourceId,
videoDuration: videoDom.duration videoDuration: videoDom.duration
}); })
} }
} }
// 保存 // 保存
handleSubmit = () => { handleSubmit = () => {
const { instId, adminId } = window.currentUserInstInfo; const { instId, adminId } = window.currentUserInstInfo
const { const {
id, id,
...@@ -352,113 +340,113 @@ class AddVideoCourse extends React.Component { ...@@ -352,113 +340,113 @@ class AddVideoCourse extends React.Component {
categoryId, categoryId,
shelfState, shelfState,
whetherVisitorsJoin, whetherVisitorsJoin,
introduce, introduce
} = this.state; } = this.state
const commonParams = { const commonParams = {
videoName, videoName,
videoDuration, videoDuration,
courseMediaId: scheduleVideoId, courseMediaId: scheduleVideoId,
scheduleMedia: scheduleMedia.filter(item => !!item.mediaContent), scheduleMedia: scheduleMedia.filter((item) => !!item.mediaContent),
categoryId, categoryId,
courseName, courseName,
coverId, coverId,
operatorId:User.getStoreUserId(), operatorId: User.getStoreUserId(),
storeId:User.getStoreId(), storeId: User.getStoreId(),
shelfState, shelfState,
whetherVisitorsJoin, whetherVisitorsJoin,
courseType: 'VOICE', courseType: 'VOICE'
}; }
// 校验必填字段:课程名称, 课程视频 // 校验必填字段:课程名称, 课程视频
this.handleValidate(courseName, scheduleVideoId,categoryId, scheduleMedia).then((res) => { this.handleValidate(courseName, scheduleVideoId, categoryId, scheduleMedia).then((res) => {
if (!res) return; if (!res) return
Upload.uploadTextToOSS(introduce, `${randomString()}.txt`, (introduceId) => { Upload.uploadTextToOSS(introduce, `${randomString()}.txt`, (introduceId) => {
this.submitRemote({ id, pageType, commonParams: { ...commonParams, introduceId } }) this.submitRemote({ id, pageType, commonParams: { ...commonParams, introduceId } })
}); })
}); })
} }
submitRemote = ({ id, pageType, commonParams }) => { submitRemote = ({ id, pageType, commonParams }) => {
if (pageType === 'add') { if (pageType === 'add') {
Service.Hades('public/hades/createMediaCourse', commonParams).then((res) => { Service.Hades('public/hades/createMediaCourse', commonParams).then((res) => {
if (!res) return; if (!res) return
message.success("新建成功"); message.success('新建成功')
window.RCHistory.push({ window.RCHistory.push({
pathname: `/video-course`, pathname: `/video-course`
}); })
}) })
} else { } else {
const editParams = { const editParams = {
courseId:id, courseId: id,
...commonParams, ...commonParams
} }
Service.Hades('public/hades/editMediaCourse', editParams).then((res) => { Service.Hades('public/hades/editMediaCourse', editParams).then((res) => {
if (!res) return; if (!res) return
message.success("保存成功"); message.success('保存成功')
window.RCHistory.push({ window.RCHistory.push({
pathname: `/video-course`, pathname: `/video-course`
}); })
}); })
} }
} }
handleValidate = (courseName, scheduleVideoId,categoryId,scheduleMedia) => { handleValidate = (courseName, scheduleVideoId, categoryId, scheduleMedia) => {
return new Promise((resolve) => { return new Promise((resolve) => {
if (!courseName) { if (!courseName) {
message.warning('请输入课程名称'); message.warning('请输入课程名称')
resolve(false); resolve(false)
return false return false
} }
if (!scheduleVideoId) { if (!scheduleVideoId) {
message.warning('请上传视频'); message.warning('请上传视频')
resolve(false); resolve(false)
return false return false
} }
if(!categoryId){ if (!categoryId) {
message.warning('请选择课程分类'); message.warning('请选择课程分类')
resolve(false); resolve(false)
return false return false
} }
const textMedia = scheduleMedia.filter((item) => item.mediaType === 'TEXT'); const textMedia = scheduleMedia.filter((item) => item.mediaType === 'TEXT')
for (let i = 0, len = textMedia.length; i < len; i++) { for (let i = 0, len = textMedia.length; i < len; i++) {
if (textMedia[i].mediaContentLength && textMedia[i].mediaContentLength.length > 1000) { if (textMedia[i].mediaContentLength && textMedia[i].mediaContentLength.length > 1000) {
message.warning(`第${i+1}个文字简介的字数超过了1000个字`); message.warning(`第${i + 1}个文字简介的字数超过了1000个字`)
resolve(false); resolve(false)
return false return false
} }
} }
resolve(true); resolve(true)
}); })
} }
handleSelectCover = (file)=> { handleSelectCover = (file) => {
this.uploadImage(file); this.uploadImage(file)
} }
//上传图片 //上传图片
uploadImage = (imageFile) => { uploadImage = (imageFile) => {
const { folderName } = imageFile; const { folderName } = imageFile
const fileName = window.random_string(16) + folderName.slice(folderName.lastIndexOf(".")); const fileName = window.random_string(16) + folderName.slice(folderName.lastIndexOf('.'))
const self = this; const self = this
this.setState( this.setState(
{ {
visible: true, visible: true
}, },
() => { () => {
setTimeout(() => { setTimeout(() => {
const okBtnDom = document.querySelector("#headPicModal"); const okBtnDom = document.querySelector('#headPicModal')
const options = { const options = {
size: [500, 282], size: [500, 282],
ok: okBtnDom, ok: okBtnDom,
maxZoom: 3, maxZoom: 3,
style: { style: {
jpgFillColor: "transparent", jpgFillColor: 'transparent'
}, },
done: function (dataUrl) { done: function (dataUrl) {
clearTimeout(self.timer); clearTimeout(self.timer)
self.timer = setTimeout(() => { self.timer = setTimeout(() => {
if ((self.state.rotate != this.rotate()) || (self.state.scale != this.scale())) { if (self.state.rotate != this.rotate() || self.state.scale != this.scale()) {
const _dataUrl = this.clip() const _dataUrl = this.clip()
const cutImageBlob = self.convertBase64UrlToBlob(_dataUrl); const cutImageBlob = self.convertBase64UrlToBlob(_dataUrl)
self.setState({ self.setState({
cutImageBlob, cutImageBlob,
dataUrl: _dataUrl, dataUrl: _dataUrl,
...@@ -466,20 +454,19 @@ class AddVideoCourse extends React.Component { ...@@ -466,20 +454,19 @@ class AddVideoCourse extends React.Component {
scale: this.scale() scale: this.scale()
}) })
} }
}, 500) }, 500)
const cutImageBlob = self.convertBase64UrlToBlob(dataUrl); const cutImageBlob = self.convertBase64UrlToBlob(dataUrl)
self.setState({ self.setState({
cutImageBlob, cutImageBlob,
dataUrl dataUrl
}) })
setTimeout(() => { setTimeout(() => {
cutFlag = false; cutFlag = false
}, 2000); }, 2000)
}, },
fail: (failInfo) => { fail: (failInfo) => {
message.error("图片上传失败了,请重新上传"); message.error('图片上传失败了,请重新上传')
}, },
loadComplete: function (img) { loadComplete: function (img) {
setTimeout(() => { setTimeout(() => {
...@@ -489,152 +476,199 @@ class AddVideoCourse extends React.Component { ...@@ -489,152 +476,199 @@ class AddVideoCourse extends React.Component {
hasImgReady: true hasImgReady: true
}) })
}, 100) }, 100)
}
}, }
};
const imgUrl = `${imageFile.ossUrl}?${new Date().getTime()}` const imgUrl = `${imageFile.ossUrl}?${new Date().getTime()}`
if (!this.state.photoclip) { if (!this.state.photoclip) {
const _photoclip = new PhotoClip("#headPicModal", options); const _photoclip = new PhotoClip('#headPicModal', options)
_photoclip.load(imgUrl); _photoclip.load(imgUrl)
this.setState({ this.setState({
photoclip: _photoclip, photoclip: _photoclip
}); })
} else { } else {
this.state.photoclip.clear(); this.state.photoclip.clear()
this.state.photoclip.load(imgUrl); this.state.photoclip.load(imgUrl)
} }
}, 200)
}, 200); }
)
} }
);
};
//获取resourceId //获取resourceId
getSignature = (blob, fileName) => { getSignature = (blob, fileName) => {
Upload.uploadBlobToOSS(blob, 'cover' + (new Date()).valueOf(),null,'signInfo').then((signInfo) => { Upload.uploadBlobToOSS(blob, 'cover' + new Date().valueOf(), null, 'signInfo').then((signInfo) => {
this.setState({ this.setState(
coverClicpPath:signInfo.fileUrl, {
coverId:signInfo.resourceId, coverClicpPath: signInfo.fileUrl,
coverId: signInfo.resourceId,
visible: false visible: false
},()=>this.updateCover()) },
() => this.updateCover()
}); )
}; })
updateCover = () =>{ }
const {coverClicpPath,coverId} = this.state updateCover = () => {
const { coverClicpPath, coverId } = this.state
this.setState({ this.setState({
showSelectCoverModal: false, showSelectCoverModal: false,
coverUrl:coverClicpPath, coverUrl: coverClicpPath,
coverId:coverId coverId: coverId
}) })
} }
// base64转换成blob // base64转换成blob
convertBase64UrlToBlob = (urlData) => { convertBase64UrlToBlob = (urlData) => {
const bytes = window.atob(urlData.split(",")[1]); const bytes = window.atob(urlData.split(',')[1])
const ab = new ArrayBuffer(bytes.length); const ab = new ArrayBuffer(bytes.length)
const ia = new Uint8Array(ab); const ia = new Uint8Array(ab)
for (let i = 0; i < bytes.length; i++) { for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i); ia[i] = bytes.charCodeAt(i)
}
return new Blob([ab], { type: 'image/png' })
} }
return new Blob([ab], { type: "image/png" });
};
render() { render() {
const { const {
pageType,courseName, scheduleVideoId, coverId, pageType,
coverUrl, scheduleVideoUrl, studentList, scheduleMedia, courseName,
showCutModal, showSelectFileModal, diskList, scheduleVideoId,
imageFile, joinType, videoName, videoType,shelfState, coverId,
categoryName,courseCatalogList,whetherVisitorsJoin, coverUrl,
visible,showSelectCoverModal,hasImgReady,cutImageBlob, scheduleVideoUrl,
studentList,
scheduleMedia,
showCutModal,
showSelectFileModal,
diskList,
imageFile,
joinType,
videoName,
videoType,
shelfState,
categoryName,
courseCatalogList,
whetherVisitorsJoin,
visible,
showSelectCoverModal,
hasImgReady,
cutImageBlob,
introduce, introduce,
loadintroduce, loadintroduce,
id, id
} = this.state; } = this.state
// 已选择的上课学员数量 // 已选择的上课学员数量
const hasSelectedStu = studentList.length; const hasSelectedStu = studentList.length
const courseWareIcon = FileVerifyMap[videoType] ? FileTypeIcon[FileVerifyMap[videoType].type] : FileTypeIcon[videoType]; const courseWareIcon = FileVerifyMap[videoType] ? FileTypeIcon[FileVerifyMap[videoType].type] : FileTypeIcon[videoType]
return ( return (
<div className="page add-video-course-page"> <div className='page add-video-course-page'>
<Breadcrumbs <Breadcrumbs navList={pageType === 'add' ? '新建视频课' : '编辑视频课'} goBack={this.handleGoBack} />
navList={pageType === "add" ? "新建视频课" : "编辑视频课"}
goBack={this.handleGoBack}
/>
<div className="box"> <div className='box'>
<div className="show-tips"> <div className='show-tips'>
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利" /> <ShowTips message='请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利' />
</div> </div>
<div className="form"> <div className='form'>
<div className="course-name required"> <div className='course-name required'>
<span className="label">课程名称:</span> <span className='label'>课程名称:</span>
<Input <Input
value={courseName} value={courseName}
placeholder="请输入视频课的名称(40字以内)" placeholder='请输入视频课的名称(40字以内)'
maxLength={40} maxLength={40}
style={{ width: 240 }} style={{ width: 240 }}
onChange={(e) => { this.handleChangeForm('courseName', e.target.value)}} onChange={(e) => {
this.handleChangeForm('courseName', e.target.value)
}}
/> />
</div> </div>
<div className="upload-video mt16"> <div className='upload-video mt16'>
<div className="content flex"> <div className='content flex'>
<span className="label required">视频上传:</span> <span className='label required'>视频上传:</span>
<div className="value"> <div className='value'>
{ {scheduleVideoId ? (
scheduleVideoId ? <div className='course-ware'>
<div className="course-ware"> <img className='course-ware__img' src={courseWareIcon} />
<img className="course-ware__img" src={courseWareIcon} /> <span className='course-ware__name'>{videoName}</span>
<span className="course-ware__name">{videoName}</span> </div>
</div> : ) : (
<div className="course-ware--empty">从资料云盘中选择视频</div> <div className='course-ware--empty'>从资料云盘中选择视频</div>
} )}
</div> </div>
</div> </div>
<div className="sub-content"> <div className='sub-content'>
<Button <Button
onClick={() => { onClick={() => {
this.setState({ this.setState({
showSelectFileModal: true showSelectFileModal: true
}) })
}} }}>{`${pageType === 'add' && !scheduleVideoId ? '选择' : '更换'}视频`}</Button>
>{`${(pageType === 'add' && !scheduleVideoId) ? '选择' : '更换'}视频`}</Button>
<span className="tips">视频数量限制1个,大小不超过2G</span> <span className='tips'>视频数量限制1个,大小不超过2G</span>
</div> </div>
</div> </div>
<div className="cover-url flex mt16"> <div className='cover-url flex mt16'>
<div className="label">视频封面:</div> <div className='label'>视频封面:</div>
<div className="cover-url__wrap"> <div className='cover-url__wrap'>
<div className="img-content"> <div className='img-content'>
{/* 如果视频和封面都没有上传的话, 那么就显示缺省, 如果上传了视频, 那么封面图就默认显示视频的第一帧, 如果上传了封面图, 那么就显示上传的封面图 */} {/* 如果视频和封面都没有上传的话, 那么就显示缺省, 如果上传了视频, 那么封面图就默认显示视频的第一帧, 如果上传了封面图, 那么就显示上传的封面图 */}
{ {scheduleVideoUrl || coverUrl ? (
(scheduleVideoUrl || coverUrl )? <img src={coverUrl || `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`} />
<img src={coverUrl || `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`} /> : ) : (
<div className="empty-img">若不上传<br />系统默认将视频首帧作为封面图</div> <div className='empty-img'>
} 若不上传
<br />
系统默认将视频首帧作为封面图
</div>
)}
</div> </div>
<div className="opt-btns"> <div className='opt-btns'>
<Button onClick={() => {this.setState({ showSelectCoverModal:true })}}>{`${(pageType === 'add' && (!scheduleVideoId && !coverUrl)) ? '上传' : '修改'}封面`}</Button> <Button
<div className="tips">建议尺寸1280*720px或16:9。封面图最大5M,支持jpg、jpeg和png。</div> onClick={() => {
this.setState({ showSelectCoverModal: true })
}}>{`${pageType === 'add' && !scheduleVideoId && !coverUrl ? '上传' : '修改'}封面`}</Button>
<div className='tips'>建议尺寸1280*720px或16:9。封面图最大5M,支持jpg、jpeg和png。</div>
</div> </div>
</div> </div>
</div> </div>
<div className="course-catalog required"> <div className='course-catalog required'>
<span className="label">课程分类:</span> <span className='label'>课程分类:</span>
{ (pageType === 'add') && {pageType === 'add' && (
<Cascader defaultValue={[categoryName]} options={courseCatalogList} displayRender={ label => label.join('-')} fieldNames={fieldNames} onChange={this.catalogChange} style={{ width: 240 }} placeholder="请选择课程分类" suffixIcon={<span className="icon iconfont" style={{fontSize:'12px',color:'#BFBFBF'}}>&#xe835;</span>}/> <Cascader
defaultValue={[categoryName]}
options={courseCatalogList}
displayRender={(label) => label.join('-')}
fieldNames={fieldNames}
onChange={this.catalogChange}
style={{ width: 240 }}
placeholder='请选择课程分类'
suffixIcon={
<span className='icon iconfont' style={{ fontSize: '12px', color: '#BFBFBF' }}>
&#xe835;
</span>
} }
{ (pageType === 'edit' && categoryName ) && />
<Cascader defaultValue={[categoryName]} options={courseCatalogList} displayRender={ label => label.join('-')} fieldNames={fieldNames} onChange={this.catalogChange} style={{ width: 240 }} placeholder="请选择课程分类" suffixIcon={<span className="icon iconfont" style={{fontSize:'12px',color:'#BFBFBF'}}>&#xe835;</span>}/> )}
{pageType === 'edit' && categoryName && (
<Cascader
defaultValue={[categoryName]}
options={courseCatalogList}
displayRender={(label) => label.join('-')}
fieldNames={fieldNames}
onChange={this.catalogChange}
style={{ width: 240 }}
placeholder='请选择课程分类'
suffixIcon={
<span className='icon iconfont' style={{ fontSize: '12px', color: '#BFBFBF' }}>
&#xe835;
</span>
} }
/>
)}
</div> </div>
<div className="intro-info mt16"> <div className='intro-info mt16'>
<AddVideoIntro <AddVideoIntro
data={{ data={{
id, id,
...@@ -642,7 +676,7 @@ class AddVideoCourse extends React.Component { ...@@ -642,7 +676,7 @@ class AddVideoCourse extends React.Component {
shelfState, shelfState,
whetherVisitorsJoin, whetherVisitorsJoin,
introduce, introduce,
loadintroduce, loadintroduce
}} }}
onChange={this.handleChangeForm} onChange={this.handleChangeForm}
/> />
...@@ -650,21 +684,23 @@ class AddVideoCourse extends React.Component { ...@@ -650,21 +684,23 @@ class AddVideoCourse extends React.Component {
</div> </div>
</div> </div>
<div className="footer"> <div className='footer'>
<Button onClick={this.handleGoBack}>取消</Button> <Button onClick={this.handleGoBack}>取消</Button>
<Button onClick={this.handleShowPreviewModal}>预览</Button> <Button onClick={this.handleShowPreviewModal}>预览</Button>
<Button type="primary" onClick={_.debounce(() => this.handleSubmit(), 3000, true)}>保存</Button> <Button type='primary' onClick={_.debounce(() => this.handleSubmit(), 3000, true)}>
保存
</Button>
</div> </div>
{/* 选择备课文件弹窗 */} {/* 选择备课文件弹窗 */}
{ showSelectFileModal && {showSelectFileModal && (
<SelectPrepareFileModal <SelectPrepareFileModal
operateType="select" operateType='select'
selectTypeList={['MP4']} selectTypeList={['MP4']}
accept="video/mp4" accept='video/mp4'
confirm={{ confirm={{
title: '文件过大,无法上传', title: '文件过大,无法上传',
content: '为保障学员的观看体验,上传的视频大小不能超过2G', content: '为保障学员的观看体验,上传的视频大小不能超过2G'
}} }}
tooltip={'格式支持mp4,大小不超过2G'} tooltip={'格式支持mp4,大小不超过2G'}
isOpen={showSelectFileModal} isOpen={showSelectFileModal}
...@@ -675,13 +711,13 @@ class AddVideoCourse extends React.Component { ...@@ -675,13 +711,13 @@ class AddVideoCourse extends React.Component {
}} }}
onSelect={this.handleSelectVideo} onSelect={this.handleSelectVideo}
/> />
} )}
{showSelectCoverModal && {showSelectCoverModal && (
<SelectPrepareFileModal <SelectPrepareFileModal
key="basic" key='basic'
operateType="select" operateType='select'
multiple={false} multiple={false}
accept="image/jpeg,image/png,image/jpg" accept='image/jpeg,image/png,image/jpg'
selectTypeList={['JPG', 'JPEG', 'PNG']} selectTypeList={['JPG', 'JPEG', 'PNG']}
tooltip='支持文件类型:jpg、jpeg、png' tooltip='支持文件类型:jpg、jpeg、png'
isOpen={showSelectCoverModal} isOpen={showSelectCoverModal}
...@@ -690,70 +726,66 @@ class AddVideoCourse extends React.Component { ...@@ -690,70 +726,66 @@ class AddVideoCourse extends React.Component {
}} }}
onSelect={this.handleSelectCover} onSelect={this.handleSelectCover}
/> />
} )}
<Modal <Modal
title="设置图片" title='设置图片'
width={1080} width={1080}
visible={visible} visible={visible}
maskClosable={false} maskClosable={false}
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>} closeIcon={<span className='icon iconfont modal-close-icon'>&#xe6ef;</span>}
onCancel={() => { onCancel={() => {
this.setState({ visible: false }); this.setState({ visible: false })
}} }}
zIndex={10001} zIndex={10001}
footer={[ footer={[
<Button <Button
key="back" key='back'
onClick={() => { onClick={() => {
this.setState({ visible: false }); this.setState({ visible: false })
}} }}>
>
重新上传 重新上传
</Button>, </Button>,
<Button <Button
key="submit" key='submit'
type="primary" type='primary'
disabled={!hasImgReady} disabled={!hasImgReady}
onClick={() => { onClick={() => {
if (!cutFlag) { if (!cutFlag) {
cutFlag = true; cutFlag = true
this.refs.hiddenBtn.click(); this.refs.hiddenBtn.click()
} }
this.getSignature(cutImageBlob); this.getSignature(cutImageBlob)
}} }}>
>
确定 确定
</Button>, </Button>
]} ]}>
> <div className='clip-box'>
<div className="clip-box">
<div <div
id="headPicModal" id='headPicModal'
ref="headPicModal" ref='headPicModal'
style={{ style={{
width: "500px", width: '500px',
height: "430px", height: '430px',
marginBottom: 0, marginBottom: 0
}} }}></div>
></div> <div id='clipBtn' style={{ display: 'none' }} ref='hiddenBtn'></div>
<div id="clipBtn" style={{ display: "none" }} ref="hiddenBtn"></div> <div className='preview-img'>
<div className="preview-img"> <div className='title'>效果预览</div>
<div className="title">效果预览</div> <div id='preview-url-box' style={{ width: 500, height: 282 }}>
<div id="preview-url-box" style={{width:500,height:282}}> <img src={this.state.dataUrl} style={{ width: '100%' }} alt='' />
<img src={this.state.dataUrl} style={{ width: '100%' }} alt="" />
</div> </div>
<div className="tip-box"> <div className='tip-box'>
<div className="tip">温馨提示</div> <div className='tip'>温馨提示</div>
<div className="tip">①预览效果图时可能存在延迟,单击左侧图片刷新即可</div> <div className='tip'>①预览效果图时可能存在延迟,单击左侧图片刷新即可</div>
<div className="tip">②设置图片时双击可旋转图片,滚动可放大或缩小图片</div> <div className='tip'>②设置图片时双击可旋转图片,滚动可放大或缩小图片</div>
</div> </div>
</div> </div>
</div> </div>
</Modal> </Modal>
{ this.state.previewCourseModal } {this.state.previewCourseModal}
</div> </div>
) )
} }
} }
export default AddVideoCourse; export default AddVideoCourse
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-05 10:11:57 * @Date: 2020-08-05 10:11:57
* @LastEditors: zhangleyuan * @LastEditors: fusanqiasng
* @LastEditTime: 2021-02-23 16:35:37 * @LastEditTime: 2021-05-25 10:53:11
* @Description: 视频课-搜索模块 * @Description: 视频课-搜索模块
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
import React from 'react'; import React from 'react'
import { Row, Input, Select,Tooltip } from 'antd'; import { Row, Input, Select, Tooltip, TreeSelect } from 'antd'
import RangePicker from "@/modules/common/DateRangePicker"; import RangePicker from '@/modules/common/DateRangePicker'
import _ from 'underscore'
import './VideoCourseFilter.less'
import moment from 'moment'
import StoreService from '@/domains/store-domain/storeService'
import User from '@/common/js/user'
import AidToolService from '@/domains/aid-tool-domain/AidToolService'
import './VideoCourseFilter.less'; const { Search } = Input
import moment from 'moment'; const { Option } = Select
import StoreService from "@/domains/store-domain/storeService";
const { Search } = Input;
const { Option } = Select;
const DEFAULT_QUERY = { const DEFAULT_QUERY = {
courseName: null, // 课程名称 courseName: null, // 课程名称
operatorId: null, // 创建人 operatorId: null, // 创建人
beginTime: null, // 开始日期 beginTime: null, // 开始日期
endTime: null, // 结束日期 endTime: null, // 结束日期
shelfState:null, shelfState: null,
categoryId: null
} }
const defaultTeacherQuery = { const defaultTeacherQuery = {
size: 10, size: 10,
current: 1, current: 1,
nickName:null nickName: null
} }
class VideoCourseFilter extends React.Component { class VideoCourseFilter extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props)
this.state = { this.state = {
query: { ...DEFAULT_QUERY }, // 使用扩展运算符,避免浅拷贝 query: { ...DEFAULT_QUERY }, // 使用扩展运算符,避免浅拷贝
teacherQuery: defaultTeacherQuery, teacherQuery: defaultTeacherQuery,
teacherList:[], teacherList: [],
expandFilter:false expandFilter: false,
categoryList: []
}
} }
shouldComponentUpdate(nextProps) {
if (nextProps.currentTabKey !== this.props.currentTabKey) {
this.handleReset()
return false
}
return true
} }
componentDidMount() { componentDidMount() {
this.getTeacherList(); this.getTeacherList()
this.queryCategoryTree()
}
// 查询分类树
queryCategoryTree = (categoryName) => {
let query = {
bizType: 'QUESTION',
source: 2,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
count: false
}
AidToolService.queryExternalCategoryTree(query).then((res) => {
const { categoryList = [] } = res.result
this.setState({
categoryList: this.renderTreeNodes(categoryList)
})
})
} }
getTeacherList(current = 1, selectList){
const { teacherQuery,teacherList} = this.state; renderTreeNodes = (data) => {
let newTreeData = data.map((item) => {
item.title = (
<span>
<span className='icon iconfont' style={{ color: '#FBD140' }}>
&#xe7f1;&nbsp;
</span>
{item.categoryName}
</span>
)
item.key = item.id
if (item.sonCategoryList) {
item.children = this.renderTreeNodes(item.sonCategoryList)
}
return item
})
return newTreeData
}
getTeacherList(current = 1, selectList) {
const { teacherQuery, teacherList } = this.state
const _query = { const _query = {
...teacherQuery, ...teacherQuery,
current, current,
size:10 size: 10
}; }
StoreService.getStoreUserBasicPage( _query).then((res) => { StoreService.getStoreUserBasicPage(_query).then((res) => {
const { result = {} } = res; const { result = {} } = res
const { records = [], total = 0, hasNext } = result; const { records = [], hasNext } = result
const list = current > 1 ? teacherList.concat(records) : records; const list = current > 1 ? teacherList.concat(records) : records
this.setState({ this.setState({
hasNext, hasNext,
teacherList: list, teacherList: list
})
}) })
});
} }
// 滑动加载更多讲师列表 // 滑动加载更多讲师列表
handleScrollTeacherList = (e) => { handleScrollTeacherList = (e) => {
const { hasNext } = this.state; const { hasNext } = this.state
const container = e.target; const container = e.target
const scrollToBottom = container && container.scrollHeight <= container.clientHeight + container.scrollTop; const scrollToBottom = container && container.scrollHeight <= container.clientHeight + container.scrollTop
if (scrollToBottom && hasNext) { if (scrollToBottom && hasNext) {
const { teacherQuery } = this.state; const { teacherQuery } = this.state
let _teacherQuery = teacherQuery; let _teacherQuery = teacherQuery
_teacherQuery.current = _teacherQuery.current + 1 _teacherQuery.current = _teacherQuery.current + 1
this.setState({ this.setState(
teacherQuery:{..._teacherQuery} {
},()=>{this.getTeacherList(_teacherQuery.current)}) teacherQuery: { ..._teacherQuery }
},
() => {
this.getTeacherList(_teacherQuery.current)
}
)
} }
} }
// 改变搜索条件 // 改变搜索条件
handleChangeQuery = (field, value) => { handleChangeQuery = (field, value) => {
this.setState({ this.setState(
{
query: { query: {
...this.state.query, ...this.state.query,
[field]: value, [field]: value,
current: 1,
current: 1
} }
}, () => { },
if (field === 'courseName') return; () => {
if (field === 'courseName') return
this.props.onChange(this.state.query) this.props.onChange(this.state.query)
}); }
)
} }
handleChangeDates = (dates) => { handleChangeDates = (dates) => {
const query = _.clone(this.state.query); const query = _.clone(this.state.query)
if (_.isEmpty(dates)) { if (_.isEmpty(dates)) {
delete query.beginTime; delete query.beginTime
delete query.endTime; delete query.endTime
} else { } else {
query.beginTime = dates[0].valueOf(); query.beginTime = dates[0].valueOf()
query.endTime = dates[1].valueOf(); query.endTime = dates[1].valueOf()
} }
this.setState({ this.setState(
query:{ {
query: {
...query, ...query,
current: 1, current: 1
} }
}, () => { },
this.props.onChange(this.state.query); () => {
}) this.props.onChange(this.state.query)
}
)
} }
// 重置搜索条件 // 重置搜索条件
handleReset = () => { handleReset = () => {
this.setState({ this.setState(
query: DEFAULT_QUERY, {
}, () => { query: DEFAULT_QUERY
this.props.onChange(this.state.query); },
}) () => {
this.props.onChange(this.state.query)
}
)
} }
render() { render() {
const { currentTabKey } = this.props
const { const {
query: { query: { courseName, beginTime, endTime, operatorId, shelfState },
courseName,
operator,
beginTime,
endTime,
operatorId,
shelfState
},
expandFilter, expandFilter,
teacherList, teacherList,
teacherQuery teacherQuery,
} = this.state; categoryList
} = this.state
return ( return (
<div className="video-course-filter"> <div className='video-course-filter'>
<Row type="flex" justify="space-between" align="top"> <Row type='flex' justify='space-between' align='top'>
<div className="search-condition"> <div className='search-condition'>
<div className="search-condition__item"> <div className='search-condition__item'>
<span className="search-name">视频课名称:</span> <span className='search-name'>视频课名称:</span>
<Search <Search
value={courseName} value={courseName}
placeholder="搜索视频课名称" placeholder='搜索视频课名称'
onChange={(e) => { this.handleChangeQuery('courseName', e.target.value)}} onChange={(e) => {
onSearch={ () => { this.props.onChange(this.state.query) } } this.handleChangeQuery('courseName', e.target.value)
style={{ width: "calc(100% - 84px)" }} }}
enterButton={<span className="icon iconfont">&#xe832;</span>} onSearch={() => {
this.props.onChange(this.state.query)
}}
style={{ width: 'calc(100% - 84px)' }}
enterButton={<span className='icon iconfont'>&#xe832;</span>}
/> />
</div> </div>
<Choose>
<div className="search-condition__item"> <When condition={currentTabKey === 'internal'}>
<div className='search-condition__item'>
<span>创建人:</span> <span>创建人:</span>
<Select <Select
placeholder="请选择创建人" placeholder='请选择创建人'
style={{width:"calc(100% - 70px)"}} style={{ width: 'calc(100% - 70px)' }}
showSearch showSearch
allowClear allowClear
filterOption={(input, option) => option} filterOption={(input, option) => option}
onPopupScroll={this.handleScrollTeacherList} onPopupScroll={this.handleScrollTeacherList}
suffixIcon={<span className="icon iconfont" style={{fontSize:'12px',color:'#BFBFBF'}}>&#xe835;</span>} suffixIcon={
<span className='icon iconfont' style={{ fontSize: '12px', color: '#BFBFBF' }}>
&#xe835;
</span>
}
value={operatorId} value={operatorId}
onChange={(value) => { onChange={(value) => {
this.handleChangeQuery('operatorId', value) this.handleChangeQuery('operatorId', value)
}} }}
onSearch={(value) => { onSearch={(value) => {
teacherQuery.nickName = value teacherQuery.nickName = value
this.setState({ this.setState(
{
teacherQuery teacherQuery
}, () => { },
() => {
this.getTeacherList() this.getTeacherList()
}) }
)
}} }}
onClear ={(value)=>{ onClear={(value) => {
this.setState({ this.setState(
teacherQuery:{ {
teacherQuery: {
size: 10, size: 10,
current: 1, current: 1,
nickName:null nickName: null
} }
}, () => { },
() => {
this.getTeacherList() this.getTeacherList()
})
}
} }
> )
}}>
{_.map(teacherList, (item, index) => { {_.map(teacherList, (item, index) => {
return ( return (
<Select.Option value={item.id} key={item.id}>{item.nickName}</Select.Option> <Select.Option value={item.id} key={item.id}>
); {item.nickName}
</Select.Option>
)
})} })}
</Select> </Select>
</div> </div>
</When>
<Otherwise>
<div className='search-condition__item'>
<span className='shelf-status'>课程分类:</span>
<TreeSelect
// value={}
style={{ width: 'calc(100% - 75px)' }}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
treeData={categoryList}
placeholder='请选择课程类型'
allowClear
onChange={(value) => {
this.handleChangeQuery('categoryId', value)
}}
/>
</div>
</Otherwise>
</Choose>
<div className="search-condition__item"> <div className='search-condition__item'>
<span className="search-date">创建日期:</span> <span className='search-date'>创建日期:</span>
<RangePicker <RangePicker
id="course_date_picker" id='course_date_picker'
allowClear={false} allowClear={false}
value={ beginTime ? [moment(beginTime), moment(endTime)] : null } value={beginTime ? [moment(beginTime), moment(endTime)] : null}
format={"YYYY-MM-DD"} format={'YYYY-MM-DD'}
onChange={(dates) => { this.handleChangeDates(dates) }} onChange={(dates) => {
style={{ width: "calc(100% - 70px)" }} this.handleChangeDates(dates)
}}
style={{ width: 'calc(100% - 70px)' }}
/> />
</div> </div>
{ expandFilter &&
<div className="search-condition__item"> <If condition={expandFilter}>
<span className="shelf-status">学院展示:</span> <div className='search-condition__item'>
<span className='shelf-status'>学院展示:</span>
<Select <Select
style={{ width: "calc(100% - 84px)" }} style={{ width: 'calc(100% - 84px)' }}
placeholder="请选择" placeholder='请选择'
allowClear={true} allowClear={true}
value={shelfState} value={shelfState}
onChange={(value) => { this.handleChangeQuery('shelfState', value) }} onChange={(value) => {
suffixIcon={<span className="icon iconfont" style={{fontSize:'12px',color:'#BFBFBF'}}>&#xe835;</span>} this.handleChangeQuery('shelfState', value)
> }}
<Option value="YES">开启</Option> suffixIcon={
<Option value="NO">关闭</Option> <span className='icon iconfont' style={{ fontSize: '12px', color: '#BFBFBF' }}>
&#xe835;
</span>
}>
<Option value='YES'>开启</Option>
<Option value='NO'>关闭</Option>
</Select> </Select>
</div> </div>
} </If>
</div> </div>
<div className="reset-fold-area"> <div className='reset-fold-area'>
<Tooltip title="清空筛选"><span className="resetBtn iconfont icon" onClick={this.handleReset}>&#xe61b; </span></Tooltip> <Tooltip title='清空筛选'>
<span style={{ cursor: 'pointer' }} className="fold-btn" onClick={() => { <span className='resetBtn iconfont icon' onClick={this.handleReset}>
this.setState({expandFilter:!expandFilter}); &#xe61b;{' '}
}}>{this.state.expandFilter ? <span><span>收起</span><span className="iconfont icon fold-icon" >&#xe82d; </span> </span> : <span>展开<span className="iconfont icon fold-icon" >&#xe835; </span></span>}</span> </span>
</Tooltip>
<span
style={{ cursor: 'pointer' }}
className='fold-btn'
onClick={() => {
this.setState({ expandFilter: !expandFilter })
}}>
<Choose>
<When condition={this.state.expandFilter}>
<span>
<span>收起</span>
<span className='iconfont icon fold-icon'>&#xe82d; </span>{' '}
</span>
</When>
<Otherwise>
<span>
展开<span className='iconfont icon fold-icon'>&#xe835; </span>
</span>
</Otherwise>
</Choose>
</span>
</div> </div>
</Row> </Row>
</div> </div>
...@@ -232,4 +351,4 @@ class VideoCourseFilter extends React.Component { ...@@ -232,4 +351,4 @@ class VideoCourseFilter extends React.Component {
} }
} }
export default VideoCourseFilter; export default VideoCourseFilter
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-05 10:12:45 * @Date: 2020-08-05 10:12:45
<<<<<<< HEAD
* @LastEditors: wufan * @LastEditors: wufan
* @LastEditTime: 2021-05-13 16:34:11 * @LastEditTime: 2021-05-13 16:34:11
=======
* @LastEditors: fusanqiasng
* @LastEditTime: 2021-05-23 02:14:30
>>>>>>> 4ed93ca (feat:新增视频课外部视频模块相关功能,准备开始冒烟测试)
* @Description: 视频课-列表模块 * @Description: 视频课-列表模块
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
import React from 'react'; import React from 'react'
import { Table, Modal, message , Tooltip,Switch,Dropdown} from 'antd'; import { Table, Modal, message, Tooltip, Switch, Dropdown } from 'antd'
import { PageControl } from "@/components"; import { PageControl } from '@/components'
import { LIVE_SHARE_MAP } from '@/common/constants/academic/cloudClass'; import { LIVE_SHARE } from '@/domains/course-domain/constants'
import { appId, shareUrl, LIVE_SHARE } from '@/domains/course-domain/constants';
import ShareLiveModal from '@/modules/course-manage/modal/ShareLiveModal'
import ShareLiveModal from '@/modules/course-manage/modal/ShareLiveModal';
import WatchDataModal from '../modal/WatchDataModal' import WatchDataModal from '../modal/WatchDataModal'
import CourseService from "@/domains/course-domain/CourseService"; import CourseService from '@/domains/course-domain/CourseService'
import RelatedPlanModal from '../../modal/RelatedPlanModal'; import RelatedPlanModal from '../../modal/RelatedPlanModal'
import User from '@/common/js/user' import User from '@/common/js/user'
import './VideoCourseList.less'
import './VideoCourseList.less';
const ENV = process.env.DEPLOY_ENV || 'dev';
const userRole = User.getUserRole();
class VideoCourseList extends React.Component { class VideoCourseList extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props)
this.state = { this.state = {
id: '', // 视频课ID id: '', // 视频课ID
studentIds:[], studentIds: [],
RelatedPlanModalVisible:false, RelatedPlanModalVisible: false,
selectPlanList:{} selectPlanList: {}
} }
} }
componentDidMount() { componentDidMount() {
const videoCourseItem = localStorage.getItem('videoCourseItem'); const videoCourseItem = localStorage.getItem('videoCourseItem')
if (videoCourseItem) { if (videoCourseItem) {
const _videoCourseItem = JSON.parse(videoCourseItem); const _videoCourseItem = JSON.parse(videoCourseItem)
this.handleShowShareModal(_videoCourseItem, true); this.handleShowShareModal(_videoCourseItem, true)
} }
} }
// 观看数据弹窗 // 观看数据弹窗
handleShowWatchDataModal = (record) => { handleShowWatchDataModal = (record) => {
console.log('111'); console.log('111')
console.log("record",record); console.log('record', record)
const watchDataModal = ( const watchDataModal = (
<WatchDataModal <WatchDataModal
type='videoCourseList' type='videoCourseList'
...@@ -56,35 +55,39 @@ class VideoCourseList extends React.Component { ...@@ -56,35 +55,39 @@ class VideoCourseList extends React.Component {
close={() => { close={() => {
this.setState({ this.setState({
watchDataModal: null watchDataModal: null
}); })
}} }}
/> />
); )
this.setState({ watchDataModal }); this.setState({ watchDataModal })
} }
// 请求表头 // 请求表头
parseColumns = () => { parseColumns = () => {
const { type } = this.props
const columns = [ const columns = [
{ {
title: '视频课', title: '视频课',
key: 'scheduleName', key: 'scheduleName',
dataIndex: 'scheduleName', dataIndex: 'scheduleName',
width:321, width: 321,
fixed: 'left', fixed: 'left',
render: (val, record) => { render: (val, record) => {
const { coverUrl, scheduleVideoUrl } = record; const { coverUrl, scheduleVideoUrl } = record
return ( return (
<div className="record__item"> <div className='record__item'>
{/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */} {/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */}
<img className="course-cover" src={coverUrl || `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`} /> <img className='course-cover' src={coverUrl || `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`} alt='' />
{ record.courseName.length > 25? <Choose>
<When condition={record.courseName.length > 25}>
<Tooltip title={record.courseName}> <Tooltip title={record.courseName}>
<div className="course-name">{record.courseName}</div> <div className='course-name'>{record.courseName}</div>
</Tooltip> </Tooltip>
: </When>
<div className="course-name">{record.courseName}</div> <Otherwise>
} <div className='course-name'>{record.courseName}</div>
</Otherwise>
</Choose>
</div> </div>
) )
} }
...@@ -96,9 +99,17 @@ class VideoCourseList extends React.Component { ...@@ -96,9 +99,17 @@ class VideoCourseList extends React.Component {
width: 200, width: 200,
render: (val, record) => { render: (val, record) => {
return ( return (
<div className="record__item"> <Choose>
{record.categoryOneName}{ record.categoryTwoName?`-${record.categoryTwoName}`:''} <When condition={type === 'internal'}>
<div className='record__item'>
{record.categoryOneName}
{record.categoryTwoName ? `-${record.categoryTwoName}` : ''}
</div> </div>
</When>
<Otherwise>
<div className='record__item'>{record.categoryName}</div>
</Otherwise>
</Choose>
) )
} }
}, },
...@@ -110,42 +121,58 @@ class VideoCourseList extends React.Component { ...@@ -110,42 +121,58 @@ class VideoCourseList extends React.Component {
render: (val) => { render: (val) => {
return ( return (
<div> <div>
{ val && {val && (
<Tooltip title={val}> <Tooltip title={val}>
<div> <div>{val.length > 4 ? `${val.slice(0, 4)}...` : val}</div>
{val.length > 4 ? `${val.slice(0,4)}...` : val}
</div>
</Tooltip> </Tooltip>
} )}
</div> </div>
) )
} }
}, },
{ {
<<<<<<< HEAD
title: <span> title: <span>
<span>学院展示</span> <span>学院展示</span>
<Tooltip title={<div>开启后,学员可在学院内查看到此课程。<br/>关闭后,学院内不再展示此课程,但学员仍可通过分享的海报/链接查看此课程。</div>}><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip> <Tooltip title={<div>开启后,学员可在学院内查看到此课程。<br/>关闭后,学院内不再展示此课程,但学员仍可通过分享的海报/链接查看此课程。</div>}><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip>
</span>, </span>,
=======
title: (
<span>
<span>学院展示</span>
<Tooltip
title={
<div>
开启后,用户可在学院内查看到此课程。若课程“未成功开课”,则系统会自动“关闭”学院展示。
<br />
关闭后,学院内不再展示此课程,但用户仍可通过分享的海报/链接查看此课程。
</div>
}>
<i className='icon iconfont' style={{ marginLeft: '5px', cursor: 'pointer', color: '#bfbfbf', fontSize: '14px' }}>
&#xe61d;
</i>
</Tooltip>
</span>
),
>>>>>>> 4ed93ca (feat:新增视频课外部视频模块相关功能,准备开始冒烟测试)
width: 120, width: 120,
dataIndex: "courseware", dataIndex: 'courseware',
render: (val, item, index) => { render: (val, item, index) => {
return ( return <Switch defaultChecked={item.shelfState === 'YES' ? true : false} onChange={() => this.changeShelfState(item)} />
<Switch defaultChecked={item.shelfState==="YES"?true:false} onChange={()=>this.changeShelfState(item)}/> }
)
},
}, },
{ {
<<<<<<< HEAD
title: "观看学员数", title: "观看学员数",
=======
title: '观看用户数',
>>>>>>> 4ed93ca (feat:新增视频课外部视频模块相关功能,准备开始冒烟测试)
width: 110, width: 110,
key: "watchUserCount", key: 'watchUserCount',
dataIndex: "watchUserCount", dataIndex: 'watchUserCount',
render: (val, item) => { render: (val, item) => {
return ( return <div className='watchUserCount'>{val}</div>
<div className="watchUserCount">{val}</div> }
)
},
}, },
{ {
title: '创建时间', title: '创建时间',
...@@ -170,21 +197,27 @@ class VideoCourseList extends React.Component { ...@@ -170,21 +197,27 @@ class VideoCourseList extends React.Component {
{ {
title: '关联项', title: '关联项',
width: 200, width: 200,
key: "planList", key: 'planList',
dataIndex: "planList", dataIndex: 'planList',
render: (val, record) => { render: (val, record) => {
return ( return (
<div className="related-task"> <div className='related-task'>
{ record.relatedPlanList ? <Choose>
<Tooltip title={this.handlePlanName(record.relatedPlanList)} placement="top" arrowPointAtCenter> <When condition={record.relatedPlanList}>
{ record.relatedPlanList.map((item,index)=>{ <Tooltip title={this.handlePlanName(record.relatedPlanList)} placement='top' arrowPointAtCenter>
return <span>{item.planName} { (index < record.relatedPlanList.length-1)&&(<span></span>)} </span> {record.relatedPlanList.map((item, index) => {
}) return (
} <span>
{item.planName} {index < record.relatedPlanList.length - 1 && <span></span>}
</span>
)
})}
</Tooltip> </Tooltip>
: </When>
<Otherwise>
<span></span> <span></span>
} </Otherwise>
</Choose>
</div> </div>
) )
} }
...@@ -197,18 +230,19 @@ class VideoCourseList extends React.Component { ...@@ -197,18 +230,19 @@ class VideoCourseList extends React.Component {
fixed: 'right', fixed: 'right',
render: (val, record) => { render: (val, record) => {
return ( return (
<div className="operate"> <div className='operate'>
<div className="operate__item" onClick={()=>this.handleShowWatchDataModal(record)}>观看数据</div> <div className='operate__item' onClick={() => this.handleShowWatchDataModal(record)}>
<span className="operate__item split"> | </span> 观看数据
<div className="operate__item" onClick={() => this.handleShowShareModal(record)}>分享</div> </div>
<span className="operate__item split"> | </span> <span className='operate__item split'> | </span>
<div className='operate__item' onClick={() => this.handleShowShareModal(record)}>
分享
</div>
<span className='operate__item split'> | </span>
<Dropdown overlay={this.renderMoreOperate(record)}> <Dropdown overlay={this.renderMoreOperate(record)}>
<span className="more-operate"> <span className='more-operate'>
<span className="operate-text">更多</span> <span className='operate-text'>更多</span>
<span <span className='iconfont icon' style={{ color: '#5289FA' }}>
className="iconfont icon"
style={{ color: "#5289FA" }}
>
&#xe824; &#xe824;
</span> </span>
</span> </span>
...@@ -217,64 +251,68 @@ class VideoCourseList extends React.Component { ...@@ -217,64 +251,68 @@ class VideoCourseList extends React.Component {
) )
} }
} }
]; ]
return columns;
type !== 'internal' && columns.splice(2, 1)
return columns
} }
renderMoreOperate = (item) => { renderMoreOperate = (item) => {
const { type } = this.props
return ( return (
<div className="live-course-more-menu"> <div className='live-course-more-menu'>
{ (User.getUserRole() === "CloudManager" || User.getUserRole() === "StoreManager") && {(User.getUserRole() === 'CloudManager' || User.getUserRole() === 'StoreManager') && (
<div <div className='operate__item' onClick={() => this.handleRelatedModalShow(item)}>
className="operate__item" 关联培训计划
onClick={()=>this.handleRelatedModalShow(item)} </div>
>关联培训计划</div> )}
} <If condition={type === 'internal'}>
<div <div
className="operate__item" className='operate__item'
onClick={() => { onClick={() => {
RCHistory.push(`/create-video-course?type=edit&id=${item.id}`); Window.RCHistory.push(`/create-video-course?type=edit&id=${item.id}`)
}} }}>
>编辑</div> 编辑
<div </div>
className="operate__item" <div className='operate__item' onClick={() => this.handleDeleteVideoCourse(item.id)}>
onClick={() => this.handleDeleteVideoCourse(item.id)} 删除
>删除</div> </div>
</If>
</div> </div>
) )
} }
handlePlanName = (planArray)=>{ handlePlanName = (planArray) => {
let planStr = ""; let planStr = ''
planArray.map((item,index)=>{ planArray.map((item, index) => {
if(index < planArray.length-1){ if (index < planArray.length - 1) {
planStr = planStr + item.planName + '、'; planStr = planStr + item.planName + '、'
}else{ } else {
planStr = planStr + item.planName planStr = planStr + item.planName
} }
}) })
return planStr return planStr
} }
//改变上架状态 //改变上架状态
changeShelfState = (item) =>{ changeShelfState = (item) => {
let _shelfState = item.shelfState let _shelfState = item.shelfState
if(_shelfState==='NO'){ if (_shelfState === 'NO') {
_shelfState = "YES"; _shelfState = 'YES'
item.shelfState = "YES" item.shelfState = 'YES'
}else{ } else {
_shelfState = "NO" _shelfState = 'NO'
item.shelfState = "NO" item.shelfState = 'NO'
} }
const params={ const params = {
courseId: item.id, courseId: item.id,
shelfState:_shelfState shelfState: _shelfState
} }
CourseService.changeVideoShelfState(params).then((res)=>{ CourseService.changeVideoShelfState(params).then((res) => {
if(res.success){ if (res.success) {
if(_shelfState === "YES"){ if (_shelfState === 'YES') {
message.success("已开启展示"); message.success('已开启展示')
}else{ } else {
message.success("已取消展示"); message.success('已取消展示')
} }
} }
}) })
...@@ -285,140 +323,146 @@ class VideoCourseList extends React.Component { ...@@ -285,140 +323,146 @@ class VideoCourseList extends React.Component {
Modal.confirm({ Modal.confirm({
title: '你确定要删除此视频课吗?', title: '你确定要删除此视频课吗?',
content: '删除后,学员将不能进行观看。', content: '删除后,学员将不能进行观看。',
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>, icon: <span className='icon iconfont default-confirm-icon'>&#xe6f4;</span>,
okText: '确定', okText: '确定',
okType: 'danger', okType: 'danger',
cancelText: '取消', cancelText: '取消',
onOk: () => { onOk: () => {
const param ={ const param = {
courseId:scheduleId, courseId: scheduleId,
storeId:User.getStoreId() storeId: User.getStoreId()
} }
CourseService.delVideoSchedule( CourseService.delVideoSchedule(param).then(() => {
param message.success('删除成功')
).then(() => { this.props.onChange()
message.success('删除成功');
this.props.onChange();
}) })
} }
}); })
} }
// 显示分享弹窗 // 显示分享弹窗
handleShowShareModal = (record, needStr = false) => { handleShowShareModal = (record, needStr = false) => {
const { id, scheduleVideoUrl } = record; const { id, scheduleVideoUrl } = record
const htmlUrl = `${LIVE_SHARE}video_detail/${id}?id=${User.getStoreId()}`
const _appId = appId; const longUrl = htmlUrl
const htmlUrl = `${LIVE_SHARE}video_detail/${id}?id=${User.getStoreId()}`; const { coverUrl, courseName } = record
const longUrl = htmlUrl;
const { coverUrl, courseName } = record;
const shareData = { const shareData = {
longUrl, longUrl,
coverUrl, coverUrl,
scheduleVideoUrl, scheduleVideoUrl,
courseName, courseName
}; }
const shareLiveModal = ( const shareLiveModal = (
<ShareLiveModal <ShareLiveModal
needStr={needStr} needStr={needStr}
data={shareData} data={shareData}
type="videoClass" type='videoClass'
title="视频课" title='视频课'
close={() => { close={() => {
this.setState({ this.setState({
shareLiveModal: null shareLiveModal: null
}); })
localStorage.setItem('videoCourseItem', ''); localStorage.setItem('videoCourseItem', '')
}} }}
/> />
); )
this.setState({ shareLiveModal }); this.setState({ shareLiveModal })
} }
handleChangeTable = (pagination, filters, sorter) => { handleChangeTable = (pagination, filters, sorter) => {
const { columnKey, order } = sorter; const { columnKey, order } = sorter
const { query } = this.props; const { query } = this.props
let { order: _order } =query; let { order: _order } = query
// 按创建时间升序排序 // 按创建时间升序排序
if (columnKey === 'created' && order === 'ascend') { _order = 'CREATED_ASC'; } if (columnKey === 'created' && order === 'ascend') {
_order = 'CREATED_ASC'
}
// 按创建时间降序排序 // 按创建时间降序排序
if (columnKey === 'created' && order === 'descend') { _order = 'CREATED_DESC'; } if (columnKey === 'created' && order === 'descend') {
_order = 'CREATED_DESC'
}
// 按更新时间升序排序 // 按更新时间升序排序
if (columnKey === 'updated' && order === 'ascend') { _order = 'UPDATED_ASC'; } if (columnKey === 'updated' && order === 'ascend') {
_order = 'UPDATED_ASC'
}
// 按更新时间降序排序 // 按更新时间降序排序
if (columnKey === 'updated' && order === 'descend') { _order = 'UPDATED_DESC'; } if (columnKey === 'updated' && order === 'descend') {
_order = 'UPDATED_DESC'
}
const _query = { const _query = {
...query, ...query,
orderEnum: _order orderEnum: _order
};
this.props.onChange(_query);
} }
handleRelatedModalShow = (item)=>{ this.props.onChange(_query)
const selectPlanList = {}; }
if(item.relatedPlanList){ handleRelatedModalShow = (item) => {
item.relatedPlanList.map((item,index)=>{ const selectPlanList = {}
if (item.relatedPlanList) {
item.relatedPlanList.map((item, index) => {
selectPlanList[item.planId] = {} selectPlanList[item.planId] = {}
selectPlanList[item.planId].planId = item.planId; selectPlanList[item.planId].planId = item.planId
selectPlanList[item.planId].taskBaseVOList = [{taskId:item.taskId}]; selectPlanList[item.planId].taskBaseVOList = [{ taskId: item.taskId }]
return item return item
}) })
} }
this.setState({ this.setState({
RelatedPlanModalVisible:true, RelatedPlanModalVisible: true,
selectCourseId:item.id, selectCourseId: item.id,
selectPlanList:selectPlanList selectPlanList: selectPlanList
}) })
} }
closeRelatedPlanModalVisible = ()=>{ closeRelatedPlanModalVisible = () => {
this.setState({ this.setState({
RelatedPlanModalVisible:false RelatedPlanModalVisible: false
}) })
} }
onChangeSelectPlanList = (selectPlanList)=>{ onChangeSelectPlanList = (selectPlanList) => {
this.setState({ this.setState({
selectPlanList:selectPlanList selectPlanList: selectPlanList
}) })
} }
onConfirmSelectPlanList = ()=>{ onConfirmSelectPlanList = () => {
this.setState({ this.setState(
RelatedPlanModalVisible:false {
},()=>{this.props.onChange();}) RelatedPlanModalVisible: false
},
() => {
this.props.onChange()
}
)
} }
render() { render() {
const { dataSource = [], totalCount, query } = this.props
const { dataSource = [], totalCount, query } = this.props; const { current, size } = query
const { current, size } = query; const { RelatedPlanModalVisible, selectPlanList, selectCourseId } = this.state
const {RelatedPlanModalVisible,selectPlanList,selectCourseId} = this.state;
return ( return (
<div className="video-course-list"> <div className='video-course-list'>
<Table <Table
rowKey={record => record.id} rowKey={(record) => record.id}
dataSource={dataSource} dataSource={dataSource}
columns={this.parseColumns()} columns={this.parseColumns()}
onChange={this.handleChangeTable} onChange={this.handleChangeTable}
pagination={false} pagination={false}
scroll={{ x: 1500}} scroll={{ x: 1500 }}
bordered bordered
className="video-list-table" className='video-list-table'
/> />
<div className="box-footer"> <div className='box-footer'>
<PageControl <PageControl
current={current - 1} current={current - 1}
pageSize={size} pageSize={size}
total={totalCount} total={totalCount}
toPage={(page) => { toPage={(page) => {
const _query = {...query, current: page + 1}; const _query = { ...query, current: page + 1 }
this.props.onChange(_query) this.props.onChange(_query)
}} }}
/> />
</div> </div>
{ RelatedPlanModalVisible && {RelatedPlanModalVisible && (
<RelatedPlanModal <RelatedPlanModal
onClose={this.closeRelatedPlanModalVisible} onClose={this.closeRelatedPlanModalVisible}
visible={RelatedPlanModalVisible} visible={RelatedPlanModalVisible}
...@@ -427,12 +471,12 @@ class VideoCourseList extends React.Component { ...@@ -427,12 +471,12 @@ class VideoCourseList extends React.Component {
onChange={this.onChangeSelectPlanList} onChange={this.onChangeSelectPlanList}
onConfirm={this.onConfirmSelectPlanList} onConfirm={this.onConfirmSelectPlanList}
/> />
} )}
{ this.state.shareLiveModal } {this.state.shareLiveModal}
{ this.state.watchDataModal } {this.state.watchDataModal}
</div> </div>
) )
} }
} }
export default VideoCourseList; export default VideoCourseList
.video-course-list { .video-course-list {
margin-top: 12px; margin-top: 12px;
.video-list-table{ .video-list-table {
tbody { tbody {
tr{ tr {
&:nth-child(even){ &:nth-child(even) {
background: transparent !important; background: transparent !important;
td{ td {
background:#FFF !important; background: #fff !important;
} }
} }
&:nth-child(odd){ &:nth-child(odd) {
background: #FAFAFA !important; background: #fafafa !important;
td{ td {
background: #FAFAFA !important; background: #fafafa !important;
} }
} }
&:hover{ &:hover {
td{ td {
background:#F3f6fa !important; background: #f3f6fa !important;
} }
} }
} }
} }
} }
.watchUserCount{ .watchUserCount {
text-align:right; text-align: right;
padding:16px; padding: 16px;
} }
.operate-text { .operate-text {
color: #5289FA; color: #5289fa;
cursor: pointer; cursor: pointer;
} }
.operate { .operate {
display: flex; display: flex;
&__item { &__item {
color: #5289FA; color: #5289fa;
cursor: pointer; cursor: pointer;
&.split { &.split {
margin: 0 8px; margin: 0 8px;
color: #BFBFBF; color: #bfbfbf;
} }
} }
} }
.more-operate{ .more-operate {
line-height:20px; line-height: 20px;
} }
.record__item { .record__item {
display: flex; display: flex;
...@@ -61,16 +61,16 @@ ...@@ -61,16 +61,16 @@
.course-name { .course-name {
color: #666; color: #666;
width:188px; width: 188px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
height:48px; height: 48px;
} }
} }
.related-task{ .related-task {
text-overflow: -o-ellipsis-lastline; text-overflow: -o-ellipsis-lastline;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
......
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-05 10:08:06 * @Date: 2020-08-05 10:08:06
* @LastEditors: zhangleyuan * @LastEditors: fusanqiasng
* @LastEditTime: 2020-12-26 15:56:49 * @LastEditTime: 2021-05-25 12:00:56
* @Description: 云课堂-视频课入口页面 * @Description: 云课堂-视频课入口页面
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
import React from 'react'; import React from 'react'
import { Tabs } from 'antd'
import VideoCourseFilter from './components/VideoCourseFilter'; import VideoCourseFilter from './components/VideoCourseFilter'
import VideoCourseOpt from './components/VieoCourseOpt'; import VideoCourseOpt from './components/VieoCourseOpt'
import VideoCourseList from './components/VideoCourseList'; import VideoCourseList from './components/VideoCourseList'
import CourseService from "@/domains/course-domain/CourseService"; import CourseService from '@/domains/course-domain/CourseService'
import User from '@/common/js/user' import User from '@/common/js/user'
const { TabPane } = Tabs
class VideoCourse extends React.Component { class VideoCourse extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props)
this.state = { this.state = {
query: { query: {
size: 10, size: 10,
current: 1, current: 1,
storeId:User.getStoreId() storeId: User.getStoreId()
}, },
dataSource: [], // 视频课列表 dataSource: [], // 视频课列表
totalCount: 0, // 视频课数据总条数 totalCount: 0, // 视频课数据总条数
currentTabKey: 'internal'
} }
} }
componentWillMount() { componentWillMount() {
// 获取视频课列表 // 获取视频课列表
this.handleFetchScheduleList(); this.handleFetchScheduleList()
} }
// 获取视频课列表 // 获取视频课列表
handleFetchScheduleList = (_query = {}) => { handleFetchScheduleList = (_query = {}) => {
const { currentTabKey } = this.state
const query = { const query = {
...this.state.query, ...this.state.query,
..._query ..._query,
};
courseDivision: currentTabKey === 'external' ? 1 : null
}
// 更新请求参数 // 更新请求参数
this.setState({ query }); this.setState({ query })
CourseService.videoSchedulePage(query).then((res) => { CourseService.videoSchedulePage(query).then((res) => {
const { result = {} } = res || {}; const { result = {} } = res || {}
const { records = [], total = 0 } = result; const { records = [], total = 0 } = result
this.setState({ this.setState({
dataSource: records, dataSource: records,
totalCount: Number(total) totalCount: Number(total)
}); })
}); })
}
currenTabChange = (currentTabKey) => {
this.setState(
{
currentTabKey
},
() => {
this.handleFetchScheduleList()
}
)
} }
render() { render() {
const { dataSource, totalCount, query } = this.state; const { dataSource, totalCount, query, currentTabKey } = this.state
return ( return (
<div className="page video-course-page"> <div className='page video-course-page'>
<div className="content-header">视频课</div> <div className='content-header'>视频课</div>
<div className="box"> <div className='box'>
{/* 搜索模块 */} <Tabs onChange={this.currenTabChange} activeKey={currentTabKey}>
<VideoCourseFilter <TabPane key='internal' tab='内部课程'></TabPane>
onChange={this.handleFetchScheduleList}
/>
<TabPane key='external' tab='外部课程'></TabPane>
</Tabs>
{/* 搜索模块 */}
<VideoCourseFilter currentTabKey={currentTabKey} onChange={this.handleFetchScheduleList} />
{/* 操作模块 */} {/* 操作模块 */}
<If condition={currentTabKey === 'internal'}>
<VideoCourseOpt /> <VideoCourseOpt />
</If>
{/* 视频课列表模块 */} {/* 视频课列表模块 */}
<VideoCourseList <VideoCourseList type={currentTabKey} query={query} dataSource={dataSource} totalCount={totalCount} onChange={this.handleFetchScheduleList} />
query={query}
dataSource={dataSource}
totalCount={totalCount}
onChange={this.handleFetchScheduleList}
/>
</div> </div>
</div> </div>
) )
} }
} }
export default VideoCourse; export default VideoCourse
...@@ -2,243 +2,293 @@ ...@@ -2,243 +2,293 @@
* @Description: * @Description:
* @Author: zangsuyun * @Author: zangsuyun
* @Date: 2021-03-13 09:54:26 * @Date: 2021-03-13 09:54:26
* @LastEditors: zangsuyun * @LastEditors: fusanqiasng
* @LastEditTime: 2021-04-07 11:56:10 * @LastEditTime: 2021-05-25 11:49:22
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import React from "react"; import React from 'react'
import { import { Row, Modal, Button, message, Radio, Table, Input, Tabs, Tooltip, TreeSelect } from 'antd'
Row, import { PageControl } from '@/components'
Modal, import TableSelectedData from '@/components/TableSelectedData'
Button, import KnowledgeAPI from '@/data-source/knowledge/request-api'
message, import AidToolService from '@/domains/aid-tool-domain/AidToolService'
Table, import User from '@/common/js/user'
Select, import './LiveList.less'
Radio,
Input, import _ from 'underscore'
Tabs, import dealTimeDuration from '../../course-manage/utils/dealTimeDuration'
Tooltip,
TreeSelect, const { Search } = Input
} from "antd"; const { TabPane } = Tabs
import { PageControl } from "@/components";
import TableSelectedData from "@/components/TableSelectedData";
import CourseService from "@/domains/course-domain/CourseService";
import KnowledgeAPI from "@/data-source/knowledge/request-api";
import User from "@/common/js/user";
import "./LiveList.less";
import _ from "underscore";
import dealTimeDuration from "../../course-manage/utils/dealTimeDuration";
const { Search } = Input;
const { TabPane } = Tabs;
const courseStateShow = { const courseStateShow = {
UN_START: { UN_START: {
code: 1, code: 1,
title: "待开课", title: '待开课',
color: "#FFB714", color: '#FFB714'
}, },
STARTING: { STARTING: {
code: 2, code: 2,
title: "上课中", title: '上课中',
color: "#238FFF", color: '#238FFF'
}, },
FINISH: { FINISH: {
code: 3, code: 3,
title: "已完成", title: '已完成',
color: "#3BBDAA", color: '#3BBDAA'
}, },
EXPIRED: { EXPIRED: {
code: 4, code: 4,
title: "未成功开课", title: '未成功开课',
color: "#999", color: '#999'
}, }
}; }
class AddCourse extends React.Component { class AddCourse extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props)
this.state = { this.state = {
liveDataSource: [], liveDataSource: [],
liveSize: 10, liveSize: 10,
liveQuery: { liveQuery: {
current: 1, current: 1,
excludeUsed: true, excludeUsed: true,
courseType: "LIVE", courseType: 'LIVE',
storeId: User.getStoreId(), storeId: User.getStoreId(),
toRefKnowledgeCategoryId: this.props.categoryId, toRefKnowledgeCategoryId: this.props.categoryId
}, },
liveTotalCount: 0, liveTotalCount: 0,
selectLive: [], //弹窗内已选择的直播课程 selectLive: [], //弹窗内已选择的直播课程
videoDataSource: [], videoCourseDivision: 'internal',
videoSize: 10, videoDataSource: {
external: [],
internal: []
},
videoSize: {
external: 10,
internal: 10
},
videoSearchDefalt: {
external: {
categoryId: '',
courseName: ''
},
internal: {
categoryId: '',
courseName: ''
}
},
videoQuery: { videoQuery: {
external: {
categoryId: '',
courseName: '',
current: 1, current: 1,
courseType: "VOICE", courseType: 'VOICE',
excludeUsed: true, excludeUsed: true,
storeId: User.getStoreId(), storeId: User.getStoreId(),
toRefKnowledgeCategoryId: this.props.categoryId, toRefKnowledgeCategoryId: this.props.categoryId
}, },
videoTotalCount: 0, internal: {
selectVideo: [], //弹窗内已选择的视频课程 categoryId: '',
courseName: '',
current: 1,
courseType: 'VOICE',
excludeUsed: true,
storeId: User.getStoreId(),
toRefKnowledgeCategoryId: this.props.categoryId
}
},
videoTotalCount: {
external: 0,
internal: 0
},
selectVideo: {
external: [],
internal: []
}, //弹窗内已选择的视频课程
currentVideoCourseListData: {
external: [],
internal: []
}, //页面中已关联的视频课程
pictureDataSource: [], pictureDataSource: [],
pictureSize: 10, pictureSize: 10,
pictureQuery: { pictureQuery: {
current: 1, current: 1,
excludeUsed: true, excludeUsed: true,
courseType: "PICTURE", courseType: 'PICTURE',
storeId: User.getStoreId(), storeId: User.getStoreId(),
toRefKnowledgeCategoryId: this.props.categoryId, toRefKnowledgeCategoryId: this.props.categoryId
}, },
pictureTotalCount: 0, pictureTotalCount: 0,
selectPicture: [], //弹窗内已选择的图文课程 selectPicture: [], //弹窗内已选择的图文课程
categoryList: [], categoryList: [], //内部分类列表
}; categoryListExternal: [] //外部分类列表
}
} }
componentDidMount() { componentDidMount() {
this.handleFetchLiveList(); this.handleFetchLiveList()
this.handleFetchVideoList(); this.handleFetchVideoList()
this.handleFetchPictureList(); this.handleFetchPictureList()
this.queryCategoryTree(); this.queryCategoryTree()
} }
// 查询分类树 // 查询分类树
queryCategoryTree = (categoryName) => { queryCategoryTree = (categoryName) => {
let query = { let query = {
storeId: User.getStoreId(), storeId: User.getStoreId(),
withCount: false, withCount: false
}; }
let queryInternal = {
bizType: 'QUESTION',
source: 2,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
count: false
}
AidToolService.queryExternalCategoryTree(queryInternal).then((res) => {
const { categoryList = [] } = res.result
this.setState({
categoryListExternal: this.renderTreeNodes(categoryList)
})
})
KnowledgeAPI.getCategoryTree(query).then((res) => { KnowledgeAPI.getCategoryTree(query).then((res) => {
const { categoryList = [] } = res.result; const { categoryList = [] } = res.result
this.setState({ this.setState({
categoryList: this.renderTreeNodes(categoryList), categoryList: this.renderTreeNodes(categoryList)
}); })
}); })
}; }
renderTreeNodes = (data) => { renderTreeNodes = (data) => {
let newTreeData = data.map((item) => { let newTreeData = data.map((item) => {
item.title = ( item.title = (
<span> <span>
<span className="icon iconfont" style={{ color: "#FBD140" }}> <span className='icon iconfont' style={{ color: '#FBD140' }}>
&#xe7f1;&nbsp; &#xe7f1;&nbsp;
</span> </span>
{item.categoryName} {item.categoryName}
</span> </span>
); )
item.key = item.id; item.key = item.id
if (item.sonCategoryList) { if (item.sonCategoryList) {
item.children = this.renderTreeNodes(item.sonCategoryList); item.children = this.renderTreeNodes(item.sonCategoryList)
}
return item
})
return newTreeData
} }
return item;
});
return newTreeData;
};
// 获取直播课列表 // 获取直播课列表
handleFetchLiveList = () => { handleFetchLiveList = () => {
const { liveQuery, liveSize } = this.state; const { liveQuery, liveSize } = this.state
const params = { const params = {
...liveQuery, ...liveQuery,
size: liveSize, size: liveSize
}; }
// CourseService.getLiveCloudCoursePage(params).then((res) => { // CourseService.getLiveCloudCoursePage(params).then((res) => {
KnowledgeAPI.knowledgeLiveCoursePage(params).then((res) => { KnowledgeAPI.knowledgeLiveCoursePage(params).then((res) => {
const { result = {} } = res; const { result = {} } = res
const { records = [], total = 0 } = result; const { records = [], total = 0 } = result
this.setState({ this.setState({
liveDataSource: records, liveDataSource: records,
liveTotalCount: Number(total), liveTotalCount: Number(total)
}); })
}); })
}; }
// 获取视频课列表 // 获取视频课列表
handleFetchVideoList = () => { handleFetchVideoList = () => {
const { videoQuery, videoSize } = this.state; const { videoQuery, videoSize, videoCourseDivision, videoDataSource, videoTotalCount } = this.state
const params = { const params = {
...videoQuery, ...videoQuery[videoCourseDivision],
size: videoSize, size: videoSize[videoCourseDivision],
}; courseDivision: videoCourseDivision === 'internal' ? 'INTERNAL' : 'EXTERNAL'
}
// CourseService.videoSchedulePage(query).then((res) => { // CourseService.videoSchedulePage(query).then((res) => {
KnowledgeAPI.knowledgeMediaCoursePage(params).then((res) => { KnowledgeAPI.knowledgeMediaCoursePage(params).then((res) => {
const { result = {} } = res || {}; const { result = {} } = res || {}
const { records = [], total = 0 } = result; const { records = [], total = 0 } = result
this.setState({ this.setState({
videoDataSource: records, videoDataSource: {
videoTotalCount: Number(total), ...videoDataSource,
}); [videoCourseDivision]: records
}); },
}; videoTotalCount: {
...videoTotalCount,
[videoCourseDivision]: Number(total)
}
})
})
}
// 获取图文课列表 // 获取图文课列表
handleFetchPictureList = () => { handleFetchPictureList = () => {
const { pictureQuery, pictureSize } = this.state; const { pictureQuery, pictureSize } = this.state
const params = { const params = {
...pictureQuery, ...pictureQuery,
size: pictureSize, size: pictureSize
}; }
// CourseService.pictureSchedulePage(query).then((res) => { // CourseService.pictureSchedulePage(query).then((res) => {
KnowledgeAPI.knowledgeMediaCoursePage(params).then((res) => { KnowledgeAPI.knowledgeMediaCoursePage(params).then((res) => {
const { result = {} } = res || {}; const { result = {} } = res || {}
const { records = [], total = 0 } = result; const { records = [], total = 0 } = result
this.setState({ this.setState({
pictureDataSource: records, pictureDataSource: records,
pictureTotalCount: Number(total), pictureTotalCount: Number(total)
}); })
}); })
}; }
onShowLiveSizeChange = (current, size) => { onShowLiveSizeChange = (current, size) => {
if (current == size) { if (current === size) {
return; return
} }
this.setState( this.setState(
{ {
liveSize: size, liveSize: size
}, },
() => { () => {
this.handleFetchLiveList(); this.handleFetchLiveList()
}
)
} }
);
};
onShowVideoSizeChange = (current, size) => { onShowVideoSizeChange = (current, size) => {
if (current == size) { if (current === size) {
return; return
} }
this.setState( this.setState(
{ {
videoSize: size, videoSize: size
}, },
() => { () => {
this.handleFetchVideoList(); this.handleFetchVideoList()
}
)
} }
);
};
onShowPictureSizeChange = (current, size) => { onShowPictureSizeChange = (current, size) => {
if (current == size) { if (current === size) {
return; return
} }
this.setState( this.setState(
{ {
pictureSize: size, pictureSize: size
}, },
() => { () => {
this.handleFetchPictureList(); this.handleFetchPictureList()
}
)
} }
);
};
liveColumns = () => { liveColumns = () => {
const columns = [ const columns = [
...@@ -246,102 +296,93 @@ class AddCourse extends React.Component { ...@@ -246,102 +296,93 @@ class AddCourse extends React.Component {
title: ( title: (
<span> <span>
<span>课程信息</span> <span>课程信息</span>
<Tooltip <Tooltip title={<div>已加入该分类的课程不支持重复选择,因此不显示。</div>}>
title={<div>已加入该分类的课程不支持重复选择,因此不显示。</div>}
>
<i <i
className="icon iconfont" className='icon iconfont'
style={{ style={{
marginLeft: "5px", marginLeft: '5px',
cursor: "pointer", cursor: 'pointer',
color: "#bfbfbf", color: '#bfbfbf',
fontSize: "14px", fontSize: '14px'
}} }}>
>
&#xe61d; &#xe61d;
</i> </i>
</Tooltip> </Tooltip>
</span> </span>
), ),
width: 371, width: 371,
key: "course", key: 'course',
dataIndex: "courseName", dataIndex: 'courseName',
render: (val, record) => { render: (val, record) => {
let hasCover = false; let hasCover = false
return ( return (
<div className="record__item"> <div className='record__item'>
{record.courseMediaVOS.map((item, index) => { {record.courseMediaVOS.map((item) => {
if (item.contentType === "COVER") { if (item.contentType === 'COVER') {
hasCover = true; hasCover = true
return <img className="course-cover" src={item.mediaUrl} />; return <img className='course-cover' src={item.mediaUrl} alt='' />
} }
})} })}
{!hasCover && ( {!hasCover && <img className='course-cover' src={'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png'} alt='' />}
<img
className="course-cover"
src={"https://image.xiaomaiketang.com/xm/YNfi45JwFA.png"}
/>
)}
<div> <div>
{record.courseName.length > 17 ? ( <Choose>
<When condition={record.courseName.length > 17}>
<Tooltip title={record.courseName}> <Tooltip title={record.courseName}>
<div className="course-name">{record.courseName}</div> <div className='course-name'>{record.courseName}</div>
</Tooltip> </Tooltip>
) : ( </When>
<div className="course-name">{record.courseName}</div> <Otherwise>
)} <div className='course-name'>{record.courseName}</div>
</Otherwise>
</Choose>
<div> <div>
<span <span
className="course-status" className='course-status'
style={{ style={{
color: courseStateShow[record.courseState].color, color: courseStateShow[record.courseState].color,
border: `1px solid ${ border: `1px solid ${courseStateShow[record.courseState].color}`
courseStateShow[record.courseState].color }}>
}`,
}}
>
{courseStateShow[record.courseState].title} {courseStateShow[record.courseState].title}
</span> </span>
</div> </div>
</div> </div>
</div> </div>
); )
}, }
}, },
{ {
title: "上课时间", title: '上课时间',
width: 110, width: 110,
key: "couseCatalog", key: 'couseCatalog',
dataIndex: "couseCatalog", dataIndex: 'couseCatalog',
render: (val, item) => { render: (val, item) => {
return ( return (
<span className="course-time"> <span className='course-time'>
{formatDate("YYYY-MM-DD", parseInt(item.startTime))} <br></br> {formatDate('YYYY-MM-DD', parseInt(item.startTime))} <br></br>
{formatDate("H:i", parseInt(item.startTime))}~ {formatDate('H:i', parseInt(item.startTime))}~{formatDate('H:i', parseInt(item.endTime))}
{formatDate("H:i", parseInt(item.endTime))}
</span> </span>
); )
}, }
}, },
{ {
title: "课程分类", title: '课程分类',
// width: "10%", // width: "10%",
key: "couseCatalog", key: 'couseCatalog',
dataIndex: "couseCatalog", dataIndex: 'couseCatalog',
render: (val, record) => { render: (val, record) => {
return ( return (
<div className="categoryName"> <div className='categoryName'>
{record.categoryOneName} {record.categoryOneName}
{record.categoryTwoName ? `-${record.categoryTwoName}` : ""} {record.categoryTwoName ? `-${record.categoryTwoName}` : ''}
</div> </div>
); )
}, }
}, }
]; ]
return columns; return columns
}; }
videoColumns = () => { videoColumns = () => {
const columns = [ const columns = [
...@@ -349,74 +390,69 @@ class AddCourse extends React.Component { ...@@ -349,74 +390,69 @@ class AddCourse extends React.Component {
title: ( title: (
<span> <span>
<span>课程信息</span> <span>课程信息</span>
<Tooltip <Tooltip title={<div>已加入该分类的课程不支持重复选择,因此不显示。</div>}>
title={<div>已加入该分类的课程不支持重复选择,因此不显示。</div>}
>
<i <i
className="icon iconfont" className='icon iconfont'
style={{ style={{
marginLeft: "5px", marginLeft: '5px',
cursor: "pointer", cursor: 'pointer',
color: "#bfbfbf", color: '#bfbfbf',
fontSize: "14px", fontSize: '14px'
}} }}>
>
&#xe61d; &#xe61d;
</i> </i>
</Tooltip> </Tooltip>
</span> </span>
), ),
key: "scheduleName", key: 'scheduleName',
dataIndex: "scheduleName", dataIndex: 'scheduleName',
width: 371, width: 300,
render: (val, record) => { render: (val, record) => {
const { coverUrl, mediaCourseUrl } = record; const { coverUrl, mediaCourseUrl } = record
return ( return (
<div className="record__item"> <div className='record__item'>
{/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */} {/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */}
<img <img className='course-cover' src={coverUrl || `${mediaCourseUrl}?x-oss-process=video/snapshot,t_0,m_fast`} alt='' />
className="course-cover" <Choose>
src={ <When condition={record.courseName.length > 25}>
coverUrl ||
`${mediaCourseUrl}?x-oss-process=video/snapshot,t_0,m_fast`
}
/>
{record.courseName.length > 25 ? (
<Tooltip title={record.courseName}> <Tooltip title={record.courseName}>
<div className="course-name">{record.courseName}</div> <div className='course-name'>{record.courseName}</div>
</Tooltip> </Tooltip>
) : ( </When>
<div className="course-name">{record.courseName}</div> <Otherwise>
)} <div className='course-name'>{record.courseName}</div>
</Otherwise>
</Choose>
</div> </div>
); )
}, }
}, },
{ {
title: "课程时长", title: '课程时长',
key: "videoDuration", key: 'videoDuration',
width: 80, width: 80,
dataIndex: "videoDuration", dataIndex: 'videoDuration',
render: (text, item) => { render: (text, item) => {
return <span>{text ? dealTimeDuration(text) : "-"}</span>; return <span>{text ? dealTimeDuration(text) : '-'}</span>
}, }
}, },
{ {
title: "课程分类", title: '课程分类',
key: "categoryName", key: 'categoryName',
dataIndex: "categoryName", dataIndex: 'categoryName',
render: (val, record) => { render: (val, record) => {
return ( return (
<div className="record__item"> <div className='record__item'>
{record.categoryOneName} {record.categoryOneName}
{record.categoryTwoName ? `-${record.categoryTwoName}` : ""} {record.categoryTwoName ? `-${record.categoryTwoName}` : ''}
</div> </div>
); )
}, }
}, }
]; ]
return columns; return columns
}; }
pictureColumns = () => { pictureColumns = () => {
const columns = [ const columns = [
...@@ -424,208 +460,228 @@ class AddCourse extends React.Component { ...@@ -424,208 +460,228 @@ class AddCourse extends React.Component {
title: ( title: (
<span> <span>
<span>课程信息</span> <span>课程信息</span>
<Tooltip <Tooltip title={<div>已加入该分类的课程不支持重复选择,因此不显示。</div>}>
title={<div>已加入该分类的课程不支持重复选择,因此不显示。</div>}
>
<i <i
className="icon iconfont" className='icon iconfont'
style={{ style={{
marginLeft: "5px", marginLeft: '5px',
cursor: "pointer", cursor: 'pointer',
color: "#bfbfbf", color: '#bfbfbf',
fontSize: "14px", fontSize: '14px'
}} }}>
>
&#xe61d; &#xe61d;
</i> </i>
</Tooltip> </Tooltip>
</span> </span>
), ),
key: "scheduleName", key: 'scheduleName',
dataIndex: "scheduleName", dataIndex: 'scheduleName',
width: 371, width: 371,
render: (val, record) => { render: (val, record) => {
const { coverUrl } = record; const { coverUrl } = record
return ( return (
<div className="record__item"> <div className='record__item'>
{/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */} {/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */}
<img <img className='course-cover' src={coverUrl || 'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png'} alt='' />
className="course-cover" <Choose>
src={ <When condition={record.courseName.length > 25}>
coverUrl ||
"https://image.xiaomaiketang.com/xm/YNfi45JwFA.png"
}
/>
{record.courseName.length > 25 ? (
<Tooltip title={record.courseName}> <Tooltip title={record.courseName}>
<div className="course-name">{record.courseName}</div> <div className='course-name'>{record.courseName}</div>
</Tooltip> </Tooltip>
) : ( </When>
<div className="course-name">{record.courseName}</div> <Otherwise>
)} <div className='course-name'>{record.courseName}</div>
</Otherwise>
</Choose>
</div> </div>
); )
}, }
}, },
{ {
title: "课程分类", title: '课程分类',
key: "categoryName", key: 'categoryName',
dataIndex: "categoryName", dataIndex: 'categoryName',
render: (val, record) => { render: (val, record) => {
return ( return (
<div className="record__item"> <div className='record__item'>
{record.categoryOneName} {record.categoryOneName}
{record.categoryTwoName ? `-${record.categoryTwoName}` : ""} {record.categoryTwoName ? `-${record.categoryTwoName}` : ''}
</div> </div>
); )
}, }
}, }
]; ]
return columns; return columns
}; }
selectLiveList = (record, selected) => { selectLiveList = (record, selected) => {
let { selectLive } = this.state; let { selectLive } = this.state
let _list = []; let _list = []
if ( if (selected || !_.find(selectLive, (item) => item.liveCourseId === record.liveCourseId)) {
selected || _list = _.uniq(selectLive.concat([record]), false, (item) => item.liveCourseId)
!_.find(selectLive, (item) => item.liveCourseId == record.liveCourseId)
) {
_list = _.uniq(
selectLive.concat([record]),
false,
(item) => item.liveCourseId
);
} else { } else {
_list = _.reject( _list = _.reject(selectLive, (item) => item.liveCourseId === record.liveCourseId)
selectLive, }
(item) => item.liveCourseId === record.liveCourseId this.setState({ selectLive: _list })
);
} }
this.setState({ selectLive: _list });
};
selectVideoList = (record, selected) => { selectVideoList = (record, selected) => {
console.log(record); const { selectVideo, videoCourseDivision } = this.state
let { selectVideo } = this.state;
let _list = []; let { [videoCourseDivision]: selectList } = selectVideo
if (selected || !_.find(selectVideo, (item) => item.id == record.id)) {
_list = _.uniq(selectVideo.concat([record]), false, (item) => item.id); let _list = []
if (selected || !_.find(selectList, (item) => item.id === record.id)) {
_list = _.uniq(selectList.concat([record]), false, (item) => item.id)
} else { } else {
_list = _.reject(selectVideo, (item) => item.id === record.id); _list = _.reject(selectList, (item) => item.id === record.id)
}
this.setState({
selectVideo: {
...selectVideo,
[videoCourseDivision]: _list
}
})
} }
this.setState({ selectVideo: _list });
};
selectPictureList = (record, selected) => { selectPictureList = (record, selected) => {
console.log(record); console.log(record)
let { selectPicture } = this.state; let { selectPicture } = this.state
let _list = []; let _list = []
if (selected || !_.find(selectPicture, (item) => item.id == record.id)) { if (selected || !_.find(selectPicture, (item) => item.id == record.id)) {
_list = _.uniq(selectPicture.concat([record]), false, (item) => item.id); _list = _.uniq(selectPicture.concat([record]), false, (item) => item.id)
} else { } else {
_list = _.reject(selectPicture, (item) => item.id === record.id); _list = _.reject(selectPicture, (item) => item.id === record.id)
}
this.setState({ selectPicture: _list })
} }
this.setState({ selectPicture: _list });
};
callback(key) { callback(key) {
console.log(key); console.log(key)
} }
handleChangVideoFilter = (key, value) => { handleChangVideoFilter = (key, value) => {
const { videoQuery } = this.state; const { videoQuery, videoCourseDivision, videoSearchDefalt } = this.state
videoQuery[key] = value; videoQuery[videoCourseDivision][key] = value
videoQuery.current = 1; videoSearchDefalt[videoCourseDivision][key] = value
videoQuery[videoCourseDivision].current = 1
this.setState( this.setState(
{ {
videoQuery, videoQuery,
videoSearchDefalt
}, },
() => { () => {
this.handleFetchVideoList(); this.handleFetchVideoList()
}
)
}
handleChangVideoCourseName = (e) => {
const { videoSearchDefalt, videoCourseDivision } = this.state
videoSearchDefalt[videoCourseDivision].courseName = e.target.value
this.setState({
videoSearchDefalt
})
} }
);
};
handleChangLiveFilter = (key, value) => { handleChangLiveFilter = (key, value) => {
const { liveQuery } = this.state; const { liveQuery } = this.state
liveQuery[key] = value; liveQuery[key] = value
liveQuery.current = 1; liveQuery.current = 1
this.setState( this.setState(
{ {
liveQuery, liveQuery
}, },
() => { () => {
this.handleFetchLiveList(); this.handleFetchLiveList()
}
)
} }
);
};
handleChangPictureFilter = (key, value) => { handleChangPictureFilter = (key, value) => {
const { pictureQuery } = this.state; const { pictureQuery } = this.state
pictureQuery[key] = value; pictureQuery[key] = value
pictureQuery.current = 1; pictureQuery.current = 1
this.setState( this.setState(
{ {
pictureQuery, pictureQuery
}, },
() => { () => {
this.handleFetchPictureList(); this.handleFetchPictureList()
}
)
} }
);
};
handAddCourse = () => { handAddCourse = () => {
const { selectVideo, selectLive, selectPicture } = this.state; const { selectVideo, selectLive, selectPicture } = this.state
const batchAddList = []; const batchAddList = []
if (selectVideo.length) { if (selectVideo.length) {
batchAddList.push({ batchAddList.push({
categoryId: this.props.categoryId, categoryId: this.props.categoryId,
refIds: _.pluck(selectVideo, "id"), refIds: _.pluck(selectVideo, 'id'),
storeId: User.getStoreId(), storeId: User.getStoreId(),
type: "VOICE", type: 'VOICE',
createId: User.getStoreUserId(), createId: User.getStoreUserId()
}); })
} }
if (selectLive.length) { if (selectLive.length) {
batchAddList.push({ batchAddList.push({
categoryId: this.props.categoryId, categoryId: this.props.categoryId,
refIds: _.pluck(selectLive, "liveCourseId"), refIds: _.pluck(selectLive, 'liveCourseId'),
storeId: User.getStoreId(), storeId: User.getStoreId(),
type: "LIVE", type: 'LIVE',
createId: User.getStoreUserId(), createId: User.getStoreUserId()
}); })
} }
if (selectPicture.length) { if (selectPicture.length) {
batchAddList.push({ batchAddList.push({
categoryId: this.props.categoryId, categoryId: this.props.categoryId,
refIds: _.pluck(selectPicture, "id"), refIds: _.pluck(selectPicture, 'id'),
storeId: User.getStoreId(), storeId: User.getStoreId(),
type: "PICTURE", type: 'PICTURE',
createId: User.getStoreUserId(), createId: User.getStoreUserId()
}); })
} }
KnowledgeAPI.addDifTypeKnowledge({ batchAddList }).then(({ success }) => { KnowledgeAPI.addDifTypeKnowledge({ batchAddList }).then(({ success }) => {
if (success) { if (success) {
message.success("新增成功"); message.success('新增成功')
this.props.onClose(); this.props.onClose()
this.props.onChange(); this.props.onChange()
this.props.updateCategoryTree(); this.props.updateCategoryTree()
}
})
}
videoCourseDivisionChange = (e) => {
const { videoQuery, videoSearchDefalt } = this.state
this.setState(
{
videoCourseDivision: e.target.value,
videoSearchDefalt: {
...videoSearchDefalt,
[e.target.value]: {
courseName: videoQuery[e.target.value].courseName,
categoryId: videoQuery[e.target.value].categoryId
}
}
},
() => {
this.handleFetchVideoList()
}
)
} }
});
};
renderFooter = () => { renderFooter = () => {
const {selectVideo,selectPicture,selectLive} =this.state const { selectVideo, selectPicture, selectLive } = this.state
return ( return (
<div> <div>
<Button onClick={this.props.onClose}>取消</Button> <Button onClick={this.props.onClose}>取消</Button>
<Button disabled={!(selectLive.length || selectVideo.length || selectPicture.length)} type="primary" onClick={this.handAddCourse}> <Button disabled={!(selectLive.length || selectVideo.length || selectPicture.length)} type='primary' onClick={this.handAddCourse}>
确定 确定
</Button> </Button>
</div> </div>
); )
}; }
render() { render() {
const { const {
...@@ -638,162 +694,151 @@ class AddCourse extends React.Component { ...@@ -638,162 +694,151 @@ class AddCourse extends React.Component {
videoSize, videoSize,
videoQuery, videoQuery,
videoTotalCount, videoTotalCount,
videoCourseDivision,
selectVideo, selectVideo,
pictureDataSource, pictureDataSource,
pictureSize, pictureSize,
pictureQuery, pictureQuery,
pictureTotalCount, pictureTotalCount,
selectPicture, selectPicture,
videoSearchDefalt,
categoryList, categoryList,
} = this.state; categoryListExternal
} = this.state
const LiveSelection = { const LiveSelection = {
selectedRowKeys: _.pluck(selectLive, "liveCourseId"), selectedRowKeys: _.pluck(selectLive, 'liveCourseId'),
onSelect: this.selectLiveList, onSelect: this.selectLiveList,
onSelectAll: (selected, _selectedRows, changeRows) => { onSelectAll: (selected, _selectedRows, changeRows) => {
let _list = []; let _list = []
if (selected) { if (selected) {
_list = _.uniq( _list = _.uniq(selectLive.concat(changeRows), false, (item) => item.liveCourseId)
selectLive.concat(changeRows),
false,
(item) => item.liveCourseId
);
} else { } else {
_list = _.reject(selectLive, (item) => _list = _.reject(selectLive, (item) => _.find(changeRows, (data) => data.liveCourseId === item.liveCourseId))
_.find( }
changeRows, this.setState({ selectLive: _list })
(data) => data.liveCourseId === item.liveCourseId }
)
);
} }
this.setState({ selectLive: _list });
},
};
const VideoSelection = { const VideoSelection = {
selectedRowKeys: _.pluck(selectVideo, "id"), selectedRowKeys: _.pluck(selectVideo[videoCourseDivision], 'id'),
onSelect: this.selectVideoList, onSelect: this.selectVideoList,
onSelectAll: (selected, _selectedRows, changeRows) => { onSelectAll: (selected, _selectedRows, changeRows) => {
let _list = []; let _list = []
if (selected) { if (selected) {
_list = _.uniq( _list = _.uniq(selectVideo[videoCourseDivision].concat(changeRows), false, (item) => item.id)
selectVideo.concat(changeRows),
false,
(item) => item.id
);
} else { } else {
_list = _.reject(selectVideo, (item) => _list = _.reject(selectVideo[videoCourseDivision], (item) => _.find(changeRows, (data) => data.id === item.id))
_.find(changeRows, (data) => data.id === item.id) }
); this.setState({
selectVideo: {
...selectVideo,
[videoCourseDivision]: _list
}
})
}
} }
this.setState({ selectVideo: _list });
},
};
const PictureSelection = { const PictureSelection = {
selectedRowKeys: _.pluck(selectPicture, "id"), selectedRowKeys: _.pluck(selectPicture, 'id'),
onSelect: this.selectPictureList, onSelect: this.selectPictureList,
onSelectAll: (selected, _selectedRows, changeRows) => { onSelectAll: (selected, _selectedRows, changeRows) => {
console.log(changeRows); console.log(changeRows)
let _list = []; let _list = []
if (selected) { if (selected) {
_list = _.uniq( _list = _.uniq(selectPicture.concat(changeRows), false, (item) => item.id)
selectPicture.concat(changeRows),
false,
(item) => item.id
);
} else { } else {
_list = _.reject(selectPicture, (item) => _list = _.reject(selectPicture, (item) => _.find(changeRows, (data) => data.id === item.id))
_.find(changeRows, (data) => data.id === item.id) }
); this.setState({ selectPicture: _list })
}
} }
this.setState({ selectPicture: _list });
},
};
return ( return (
<Modal <Modal visible={true} width={800} title='新增课程' footer={this.renderFooter()} onCancel={this.props.onClose} className='add-course-modal'>
visible={true} <Tabs defaultActiveKey='VIDEO'>
width={720} <TabPane tab='视频课' key='VIDEO'>
title="新增课程" <Radio.Group value={videoCourseDivision} onChange={this.videoCourseDivisionChange} style={{ marginBottom: 8 }}>
footer={this.renderFooter()} <Radio.Button value='internal'>内部课程</Radio.Button>
onCancel={this.props.onClose} <Radio.Button value='external'>外部课程</Radio.Button>
className="add-course-modal" </Radio.Group>
> <div className='live-list'>
<Tabs defaultActiveKey="VIDEO" onChange={this.callback} centered>
<TabPane tab="视频课" key="VIDEO">
<div className="live-list">
<div> <div>
<Row type="flex" justify="space-between" align="top"> <Row type='flex' justify='space-between' align='top'>
<div> <div>
<span style={{ lineHeight: "32px" }}>课程名称:</span> <span style={{ lineHeight: '32px' }}>课程名称:</span>
<Search <Search
// value={courseName} value={videoSearchDefalt[videoCourseDivision].courseName}
style={{ width: "calc(100% - 75px)" }} style={{ width: 'calc(100% - 75px)' }}
placeholder="搜索课程名称" placeholder='搜索课程名称'
onChange={this.handleChangVideoCourseName}
onSearch={(value) => { onSearch={(value) => {
this.handleChangVideoFilter("courseName", value); this.handleChangVideoFilter('courseName', value)
}} }}
enterButton={ enterButton={<span className='icon iconfont'>&#xe832;</span>}
<span className="icon iconfont">&#xe832;</span>
}
/> />
</div> </div>
<div style={{ width: "50%" }}> <div style={{ width: '50%' }}>
<span className="shelf-status">课程分类:</span> <span className='shelf-status'>课程分类:</span>
<TreeSelect <TreeSelect
style={{ width: "calc(100% - 75px)" }} value={videoSearchDefalt[videoCourseDivision].categoryId}
dropdownStyle={{ maxHeight: 400, overflow: "auto" }} style={{ width: 'calc(100% - 75px)' }}
treeData={categoryList} dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
placeholder="请选择课程类型" treeData={videoCourseDivision === 'internal' ? categoryList : categoryListExternal}
placeholder='请选择课程类型'
allowClear allowClear
onChange={(value) => { onChange={(value) => {
this.handleChangVideoFilter("categoryId", value); this.handleChangVideoFilter('categoryId', value)
}} }}
/> />
</div> </div>
</Row> </Row>
</div> </div>
<TableSelectedData <TableSelectedData
selectedNum={ selectedNum={selectVideo.internal.length + selectVideo.external.length + selectLive.length + selectPicture.length}
selectVideo.length + selectLive.length + selectPicture.length
}
clearSelectedData={() => { clearSelectedData={() => {
this.setState({ this.setState({
selectVideo: [], selectVideo: {
internal: [],
external: []
},
selectLive: [], selectLive: [],
selectPicture: [], selectPicture: []
}); })
}} }}
/> />
<Table <Table
rowKey={(record) => record.id} rowKey={(record) => record.id}
dataSource={videoDataSource} dataSource={videoDataSource[videoCourseDivision]}
columns={this.videoColumns()} columns={this.videoColumns()}
size="middle" size='middle'
rowSelection={VideoSelection} rowSelection={VideoSelection}
pagination={false} pagination={false}
bordered bordered
className="video-list-table" className='video-list-table'
style={{ maxHeight: 359, overflow: "scroll" }} style={{ maxHeight: 359, overflow: 'scroll' }}
/> />
<div className="box-footer"> <div className='box-footer'>
{videoTotalCount > 0 && ( {videoDataSource[videoCourseDivision].length > 0 && (
<PageControl <PageControl
current={videoQuery.current - 1} current={videoQuery[videoCourseDivision].current - 1}
pageSize={videoSize} pageSize={videoSize[videoCourseDivision]}
total={videoTotalCount} total={videoTotalCount[videoCourseDivision]}
toPage={(page) => { toPage={(page) => {
const _query = { ...videoQuery, current: page + 1 }; const _query = { ...videoQuery[videoCourseDivision], current: page + 1 }
console.log('_query', _query)
this.setState( this.setState(
{ {
videoQuery: _query, videoQuery: {
...videoQuery,
[videoCourseDivision]: _query
}
}, },
() => { () => {
this.handleFetchVideoList(); this.handleFetchVideoList()
} }
); )
}} }}
onShowSizeChange={this.onShowVideoSizeChange} onShowSizeChange={this.onShowVideoSizeChange}
/> />
...@@ -801,84 +846,76 @@ class AddCourse extends React.Component { ...@@ -801,84 +846,76 @@ class AddCourse extends React.Component {
</div> </div>
</div> </div>
</TabPane> </TabPane>
<TabPane tab="直播课" key="LIVE"> <TabPane tab='直播课' key='LIVE'>
<div className="live-list"> <div className='live-list'>
<div> <div>
<Row type="flex" justify="space-between" align="top"> <Row type='flex' justify='space-between' align='top'>
<div> <div>
<span style={{ lineHeight: "32px" }}>课程名称:</span> <span style={{ lineHeight: '32px' }}>课程名称:</span>
<Search <Search
// value={courseName} style={{ width: 'calc(100% - 75px)' }}
style={{ width: "calc(100% - 75px)" }} placeholder='搜索课程名称'
placeholder="搜索课程名称"
// onChange={(e) => {
// this.handleChangLiveFilter(
// "courseName",
// e.target.value
// );
// }}
onSearch={(value) => { onSearch={(value) => {
this.handleChangLiveFilter("courseName", value); this.handleChangLiveFilter('courseName', value)
}} }}
enterButton={ enterButton={<span className='icon iconfont'>&#xe832;</span>}
<span className="icon iconfont">&#xe832;</span>
}
/> />
</div> </div>
<div style={{ width: "50%" }}> <div style={{ width: '50%' }}>
<span className="shelf-status">课程分类:</span> <span className='shelf-status'>课程分类:</span>
<TreeSelect <TreeSelect
style={{ width: "calc(100% - 75px)" }} style={{ width: 'calc(100% - 75px)' }}
dropdownStyle={{ maxHeight: 400, overflow: "auto" }} dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
treeData={categoryList} treeData={categoryList}
placeholder="请选择课程类型" placeholder='请选择课程类型'
allowClear allowClear
onChange={(value) => { onChange={(value) => {
this.handleChangLiveFilter("categoryId", value); this.handleChangLiveFilter('categoryId', value)
}} }}
/> />
</div> </div>
</Row> </Row>
</div> </div>
<TableSelectedData <TableSelectedData
selectedNum={ selectedNum={selectVideo.internal.length + selectVideo.external.length + selectLive.length + selectPicture.length}
selectVideo.length + selectLive.length + selectPicture.length
}
clearSelectedData={() => { clearSelectedData={() => {
this.setState({ this.setState({
selectVideo: [], selectVideo: {
internal: [],
external: []
},
selectLive: [], selectLive: [],
selectPicture: [], selectPicture: []
}); })
}} }}
/> />
<Table <Table
bordered bordered
size="middle" size='middle'
pagination={false} pagination={false}
columns={this.liveColumns()} columns={this.liveColumns()}
rowSelection={LiveSelection} rowSelection={LiveSelection}
// loading={loading} // loading={loading}
dataSource={liveDataSource} dataSource={liveDataSource}
style={{ maxHeight: 359, overflow: "scroll" }} style={{ maxHeight: 359, overflow: 'scroll' }}
rowKey={(row) => row.liveCourseId} rowKey={(row) => row.liveCourseId}
/> />
{liveTotalCount > 0 && ( {liveTotalCount > 0 && (
<div className="box-footer"> <div className='box-footer'>
<PageControl <PageControl
current={liveQuery.current - 1} current={liveQuery.current - 1}
pageSize={liveSize} pageSize={liveSize}
total={parseInt(liveTotalCount)} total={parseInt(liveTotalCount)}
toPage={(page) => { toPage={(page) => {
const _query = { ...liveQuery, current: page + 1 }; const _query = { ...liveQuery, current: page + 1 }
this.setState( this.setState(
{ {
liveQuery: _query, liveQuery: _query
}, },
() => { () => {
this.handleFetchLiveList(); this.handleFetchLiveList()
} }
); )
}} }}
onShowSizeChange={this.onShowLiveSizeChange} onShowSizeChange={this.onShowLiveSizeChange}
/> />
...@@ -886,77 +923,76 @@ class AddCourse extends React.Component { ...@@ -886,77 +923,76 @@ class AddCourse extends React.Component {
)} )}
</div> </div>
</TabPane> </TabPane>
<TabPane tab="图文课" key="PICTURE"> <TabPane tab='图文课' key='PICTURE'>
<div className="live-list"> <div className='live-list'>
<div> <div>
<Row type="flex" justify="space-between" align="top"> <Row type='flex' justify='space-between' align='top'>
<div> <div>
<span style={{ lineHeight: "32px" }}>课程名称:</span> <span style={{ lineHeight: '32px' }}>课程名称:</span>
<Search <Search
style={{ width: "calc(100% - 75px)" }} style={{ width: 'calc(100% - 75px)' }}
placeholder="搜索课程名称" placeholder='搜索课程名称'
onSearch={(value) => { onSearch={(value) => {
this.handleChangPictureFilter("courseName", value); this.handleChangPictureFilter('courseName', value)
}} }}
enterButton={ enterButton={<span className='icon iconfont'>&#xe832;</span>}
<span className="icon iconfont">&#xe832;</span>
}
/> />
</div> </div>
<div style={{ width: "50%" }}> <div style={{ width: '50%' }}>
<span className="shelf-status">课程分类:</span> <span className='shelf-status'>课程分类:</span>
<TreeSelect <TreeSelect
style={{ width: "calc(100% - 75px)" }} style={{ width: 'calc(100% - 75px)' }}
dropdownStyle={{ maxHeight: 400, overflow: "auto" }} dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
treeData={categoryList} treeData={categoryList}
placeholder="请选择课程类型" placeholder='请选择课程类型'
allowClear allowClear
onChange={(value) => { onChange={(value) => {
this.handleChangPictureFilter("categoryId", value); this.handleChangPictureFilter('categoryId', value)
}} }}
/> />
</div> </div>
</Row> </Row>
</div> </div>
<TableSelectedData <TableSelectedData
selectedNum={ selectedNum={selectVideo.internal.length + selectVideo.external.length + selectLive.length + selectPicture.length}
selectVideo.length + selectLive.length + selectPicture.length
}
clearSelectedData={() => { clearSelectedData={() => {
this.setState({ this.setState({
selectVideo: [], selectVideo: {
internal: [],
external: []
},
selectLive: [], selectLive: [],
selectPicture: [], selectPicture: []
}); })
}} }}
/> />
<Table <Table
bordered bordered
size="middle" size='middle'
pagination={false} pagination={false}
columns={this.pictureColumns()} columns={this.pictureColumns()}
rowSelection={PictureSelection} rowSelection={PictureSelection}
// loading={loading} // loading={loading}
dataSource={pictureDataSource} dataSource={pictureDataSource}
style={{ maxHeight: 359, overflow: "scroll" }} style={{ maxHeight: 359, overflow: 'scroll' }}
rowKey={(row) => row.id} rowKey={(row) => row.id}
/> />
{pictureTotalCount > 0 && ( {pictureTotalCount > 0 && (
<div className="box-footer"> <div className='box-footer'>
<PageControl <PageControl
current={pictureQuery.current - 1} current={pictureQuery.current - 1}
pageSize={pictureSize} pageSize={pictureSize}
total={parseInt(pictureTotalCount)} total={parseInt(pictureTotalCount)}
toPage={(page) => { toPage={(page) => {
const _query = { ...pictureQuery, current: page + 1 }; const _query = { ...pictureQuery, current: page + 1 }
this.setState( this.setState(
{ {
pictureQuery: _query, pictureQuery: _query
}, },
() => { () => {
this.handleFetchPictureList(); this.handleFetchPictureList()
} }
); )
}} }}
onShowSizeChange={this.onShowPictureSizeChange} onShowSizeChange={this.onShowPictureSizeChange}
/> />
...@@ -966,7 +1002,7 @@ class AddCourse extends React.Component { ...@@ -966,7 +1002,7 @@ class AddCourse extends React.Component {
</TabPane> </TabPane>
</Tabs> </Tabs>
</Modal> </Modal>
); )
} }
} }
export default AddCourse; export default AddCourse
...@@ -125,42 +125,10 @@ ...@@ -125,42 +125,10 @@
} }
} }
.add-course-modal { .add-course-modal {
.ant-tabs-top > .ant-tabs-nav::before {
border-bottom: 0px;
}
.ant-tabs-nav-list {
margin: 0 auto;
flex:none !important
}
.ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn {
font-weight: normal;
border-bottom: 0px;
}
.ant-tabs-nav .ant-tabs-tab {
padding: 6px 12px !important;
margin: 0;
border: 0.5px solid #e8e8e8;
font-size: 14px !important;
color: #999;
&:nth-child(1) {
border-radius: 4px 0px 0px 4px;
}
&:nth-child(3) {
border-radius: 0px 4px 4px 0px;
}
}
.ant-tabs-nav .ant-tabs-tab-active { .ant-tabs-nav .ant-tabs-tab-active {
border: 1px solid #ffb714;
color: #ffb714; color: #ffb714;
} }
.ant-modal-content tr > td {
.ant-tabs-top .ant-tabs-ink-bar-animated:after { padding: 12px 8px !important;
height: 0;
}
.ant-modal-content tr > td{
padding:12px 8px !important;
} }
} }
/* /*
* @Author: zhangleyuan * @Author: zhangleyuan
* @Date: 2021-02-20 16:13:39 * @Date: 2021-02-20 16:13:39
* @LastEditors: zhangleyuan * @LastEditors: fusanqiasng
* @LastEditTime: 2021-05-10 10:15:58 * @LastEditTime: 2021-05-24 00:00:31
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from 'react'
import { Button, message, Modal} from 'antd'; import { Button, message, Modal } from 'antd'
import ShowTips from "@/components/ShowTips"; import ShowTips from '@/components/ShowTips'
import Breadcrumbs from "@/components/Breadcrumbs"; import Breadcrumbs from '@/components/Breadcrumbs'
import BasicInfo from './components/BasicInfo'; import BasicInfo from './components/BasicInfo'
import TrainingTask from './components/TrainingTask'; import TrainingTask from './components/TrainingTask'
import ExpiredCourseList from './components/ExpiredCourseList'; import ExpiredCourseList from './components/ExpiredCourseList'
import PlanService from '@/domains/plan-domain/planService' import PlanService from '@/domains/plan-domain/planService'
import User from '@/common/js/user'; import User from '@/common/js/user'
import _ from "underscore"; import _ from 'underscore'
import './AddPlan.less' import './AddPlan.less'
const defaultCover = 'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png'; const defaultCover = 'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png'
const defaultBasicData = { const defaultBasicData = {
planName:"", planName: '',
coverUrl: defaultCover, coverUrl: defaultCover,
coverId:null, coverId: null,
enableState:"YES", enableState: 'YES',
selectOperatorList:[], selectOperatorList: [],
instro:'', instro: '',
operateType:'All_Operate', operateType: 'All_Operate',
percentCompleteLive:80, percentCompleteLive: 80,
percentCompleteVideo:80, percentCompleteVideo: 80,
percentCompletePicture:100 percentCompletePicture: 100
} }
const defaultTaskList = []; const defaultTaskList = []
function AddPlan() { function AddPlan() {
const id = getParameterByName("id"); const id = getParameterByName('id')
const type = getParameterByName("type"); const type = getParameterByName('type')
const [basicData,setBasicData] = useState(defaultBasicData); const [basicData, setBasicData] = useState(defaultBasicData)
const [taskList,setTaskList] = useState(defaultTaskList); const [taskList, setTaskList] = useState(defaultTaskList)
const [expiredCourseList,setExpiredCourseList] = useState([]); const [expiredCourseList, setExpiredCourseList] = useState([])
const [hasGetDetail,setHasGetDetail]= useState(false); const [hasGetDetail, setHasGetDetail] = useState(false)
const [submitDisabled,setSubmitDisabled] = useState(false); const [submitDisabled, setSubmitDisabled] = useState(false)
useEffect(()=>{ useEffect(() => {
if(type==='edit'){ if (type === 'edit') {
getPlanDetail(); getPlanDetail()
getPlanCustomerState(); getPlanCustomerState()
} }
},id) }, id)
function getPlanCustomerState(){ function getPlanCustomerState() {
PlanService.getTrainingCourseAutoCancel({ PlanService.getTrainingCourseAutoCancel({
planId: id planId: id
}).then((res) => { }).then((res) => {
const expiredCourseList = res.result; const expiredCourseList = res.result
setExpiredCourseList(expiredCourseList) setExpiredCourseList(expiredCourseList)
}) })
} }
function getPlanDetail (){ function getPlanDetail() {
PlanService.getTrainingPlanDetail({ PlanService.getTrainingPlanDetail({
planId: id planId: id
}).then((res) => { }).then((res) => {
...@@ -68,231 +68,231 @@ function AddPlan() { ...@@ -68,231 +68,231 @@ function AddPlan() {
percentCompletePicture, percentCompletePicture,
courseMediaVOS, courseMediaVOS,
trainingTaskList trainingTaskList
} = res.result; } = res.result
let coverId; let coverId
let coverUrl; let coverUrl
let instro; let instro
courseMediaVOS.map((item) => { courseMediaVOS.map((item) => {
switch (item.contentType){ switch (item.contentType) {
case "COVER": case 'COVER':
coverId = item.mediaContent; coverId = item.mediaContent
coverUrl = item.mediaUrl; coverUrl = item.mediaUrl
break; break
case "INTRO": case 'INTRO':
instro = item.mediaContent; instro = item.mediaContent
break; break
default: default:
break; break
} }
return item; return item
}) })
let _selectOperatorList = []; let _selectOperatorList = []
if(operateIds){ if (operateIds) {
_selectOperatorList = operateIds.map((item,index)=>{ _selectOperatorList = operateIds.map((item, index) => {
let _item = {}; let _item = {}
_item.id = item; _item.id = item
return _item return _item
}) })
} }
setTaskList(trainingTaskList); setTaskList(trainingTaskList)
setBasicData({ setBasicData({
planName, planName,
coverUrl:coverUrl || defaultCover, coverUrl: coverUrl || defaultCover,
coverId, coverId,
enableState, enableState,
selectOperatorList:_selectOperatorList, selectOperatorList: _selectOperatorList,
instro, instro,
operateType, operateType,
percentCompleteLive, percentCompleteLive,
percentCompleteVideo, percentCompleteVideo,
percentCompletePicture percentCompletePicture
}) })
setHasGetDetail(true); setHasGetDetail(true)
}) })
} }
function handleChangeBasicInfo(field, value,option){ function handleChangeBasicInfo(field, value, option) {
setBasicData( { setBasicData({
...basicData, ...basicData,
[field]: value, [field]: value
}) })
} }
function handleChangeTaskInfo(value){ function handleChangeTaskInfo(value) {
setTaskList(value) setTaskList(value)
} }
function submitInfo(){ function submitInfo() {
const {planName,enableState,selectOperatorList,instro,operateType,percentCompleteLive,percentCompleteVideo,percentCompletePicture,coverId,coverUrl} = basicData; const {
let input = /^[\s]*$/; planName,
if(!planName || input.test(planName)){ enableState,
message.warning('请输入的培训计划名称'); selectOperatorList,
return; instro,
} operateType,
if(operateType==='Assign_Operate' && selectOperatorList.length===0){ percentCompleteLive,
message.warning('请选择指定运营师'); percentCompleteVideo,
return; percentCompletePicture,
} coverId,
if(!percentCompleteLive && percentCompleteLive !==0 ){ coverUrl
message.warning('请输入完成标准'); } = basicData
return; let input = /^[\s]*$/
} if (!planName || input.test(planName)) {
if(!percentCompleteVideo && percentCompleteVideo !==0 ){ message.warning('请输入的培训计划名称')
message.warning('请输入完成标准'); return
return; }
} if (operateType === 'Assign_Operate' && selectOperatorList.length === 0) {
if(!percentCompletePicture && percentCompletePicture !==0 ){ message.warning('请选择指定运营师')
message.warning('请输入完成标准'); return
return; }
} if (!percentCompleteLive && percentCompleteLive !== 0) {
if(taskList.length === 0){ message.warning('请输入完成标准')
message.warning('请输入培训计划内容'); return
return; }
} if (!percentCompleteVideo && percentCompleteVideo !== 0) {
for(let i=0;i<taskList.length;i++){ message.warning('请输入完成标准')
if(input.test(taskList[i].taskName)){ return
message.warning('培训任务名称不能为空'); }
return false; if (!percentCompletePicture && percentCompletePicture !== 0) {
} message.warning('请输入完成标准')
if(taskList[i].courseList.length === 0){ return
}
if (taskList.length === 0) {
message.warning('请输入培训计划内容')
return
}
for (let i = 0; i < taskList.length; i++) {
if (input.test(taskList[i].taskName)) {
message.warning('培训任务名称不能为空')
return false
}
if (taskList[i].courseList.length === 0) {
Modal.confirm({ Modal.confirm({
title: '保存失败', title: '保存失败',
content: '每个任务下至少关联一个课程', content: '每个任务下至少关联一个课程',
okText: '确定', okText: '确定',
cancelText: '取消', cancelText: '取消',
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>, icon: <span className='icon iconfont default-confirm-icon'>&#xe6f4;</span>
}) })
return false; return false
} }
} }
let scheduleMediaRequests = []; let scheduleMediaRequests = []
let coverObj ={ let coverObj = {
contentType:'COVER', contentType: 'COVER',
mediaContent:coverId, mediaContent: coverId,
mediaType:'PICTURE', mediaType: 'PICTURE',
mediaUrl: coverUrl, mediaUrl: coverUrl
} }
if(coverId){ if (coverId) {
scheduleMediaRequests = [...scheduleMediaRequests,coverObj]; scheduleMediaRequests = [...scheduleMediaRequests, coverObj]
} }
let instroObj = { let instroObj = {
contentType:"INTRO", contentType: 'INTRO',
mediaType: 'TEXT', mediaType: 'TEXT',
mediaContent:instro, mediaContent: instro
} }
if(instro){ if (instro) {
scheduleMediaRequests = [...scheduleMediaRequests,instroObj]; scheduleMediaRequests = [...scheduleMediaRequests, instroObj]
} }
const params = { const params = {
createId:User.getStoreUserId(), createId: User.getStoreUserId(),
enableState, enableState,
operateIds:_.pluck(selectOperatorList,'id'), operateIds: _.pluck(selectOperatorList, 'id'),
operateType, operateType,
percentCompleteLive, percentCompleteLive,
percentCompleteVideo, percentCompleteVideo,
percentCompletePicture, percentCompletePicture,
planName, planName,
scheduleMediaRequests, scheduleMediaRequests,
storeId:User.getStoreId(), storeId: User.getStoreId(),
trainingTaskList:handleSubmitTaskData(taskList) trainingTaskList: handleSubmitTaskData(taskList)
} }
if (type === 'add') { if (type === 'add') {
PlanService.createTrainingPlan(params).then((res) => { PlanService.createTrainingPlan(params).then((res) => {
if (res.success){ if (res.success) {
message.success("新建成功"); message.success('新建成功')
setSubmitDisabled(true); setSubmitDisabled(true)
window.RCHistory.goBack(); window.RCHistory.goBack()
} }
}); })
}else{ } else {
const _params = { const _params = {
...params, ...params,
id id
} }
PlanService.updateTrainingPlan(_params).then((res) => { PlanService.updateTrainingPlan(_params).then((res) => {
if (res.success){ if (res.success) {
message.success("更新成功"); message.success('更新成功')
window.RCHistory.goBack(); window.RCHistory.goBack()
} }
}); })
} }
} }
function handleSubmitTaskData(taskData){ function handleSubmitTaskData(taskData) {
return taskData.map((item,index)=>{ return taskData.map((item, index) => {
let _item = {}; let _item = {}
_item.taskId = item.taskId; _item.taskId = item.taskId
_item.taskName =item.taskName; _item.taskName = item.taskName
_item.courseList = item.courseList.map((childItem,index)=>{ _item.courseList = item.courseList.map((childItem, index) => {
let _childItem = {} let _childItem = {}
_childItem.courseId = childItem.courseId; _childItem.courseId = childItem.courseId
_childItem.courseName = childItem.courseName; _childItem.courseName = childItem.courseName
_childItem.courseType = childItem.courseType; _childItem.courseType = childItem.courseType
return _childItem; return _childItem
}); })
return _item; return _item
}) })
} }
// 取消编辑并返回上一级路由 // 取消编辑并返回上一级路由
function handleGoBack (){ function handleGoBack() {
if (!_.isEqual(basicData, defaultBasicData) || !_.isEqual(taskList, defaultTaskList) if (!_.isEqual(basicData, defaultBasicData) || !_.isEqual(taskList, defaultTaskList)) {
) {
Modal.confirm({ Modal.confirm({
title: '确定要返回吗?', title: '确定要返回吗?',
content: '返回后,本次编辑的内容将不被保存', content: '返回后,本次编辑的内容将不被保存',
okText: '确认返回', okText: '确认返回',
cancelText: '留在本页', cancelText: '留在本页',
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>, icon: <span className='icon iconfont default-confirm-icon'>&#xe6f4;</span>,
onOk: () => { onOk: () => {
window.RCHistory.goBack(); window.RCHistory.goBack()
} }
}) })
} else { } else {
window.RCHistory.goBack(); window.RCHistory.goBack()
} }
} }
return ( return (
<div className="page add-plan-page"> <div className='page add-plan-page'>
<Breadcrumbs <Breadcrumbs navList={type == 'add' ? '新建培训计划' : '编辑培训计划'} goBack={handleGoBack} />
navList={type == "add" ? "新建培训计划" : "编辑培训计划"} <div className='box'>
goBack={handleGoBack} <div className='show-tips'>
/> <ShowTips message='请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利' />
<div className="box">
<div className="show-tips">
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利" />
</div> </div>
<div className="add-plan-page__form"> <div className='add-plan-page__form'>
<div className="basic-info__wrap"> <div className='basic-info__wrap'>
<div className="title">基本信息</div> <div className='title'>基本信息</div>
<BasicInfo <BasicInfo data={basicData} onChange={handleChangeBasicInfo} />
data={basicData}
onChange={handleChangeBasicInfo}
/>
</div> </div>
<div className="basic-info__wrap"> <div className='basic-info__wrap'>
<div className="title">培训任务</div> <div className='title'>培训任务</div>
{ (type==='edit' && hasGetDetail) && {type === 'edit' && hasGetDetail && <TrainingTask data={taskList} onChange={handleChangeTaskInfo} />}
<TrainingTask data={taskList} onChange={handleChangeTaskInfo} /> {type === 'add' && <TrainingTask data={taskList} onChange={handleChangeTaskInfo} />}
}
{ type==='add' &&
<TrainingTask data={taskList} onChange={handleChangeTaskInfo} />
}
</div> </div>
{ (type==='edit' && expiredCourseList.length > 0) && {type === 'edit' && expiredCourseList.length > 0 && (
<div className="expired-info__wrap"> <div className='expired-info__wrap'>
<div className="title">失效课程</div> <div className='title'>失效课程</div>
<ExpiredCourseList expiredCourseList={expiredCourseList}/> <ExpiredCourseList expiredCourseList={expiredCourseList} />
</div> </div>
} )}
</div> </div>
</div> </div>
<div className="footer"> <div className='footer'>
<Button onClick={handleGoBack}>取消</Button> <Button onClick={handleGoBack}>取消</Button>
<Button type="primary" onClick={submitInfo} disabled={submitDisabled}>保存</Button> <Button type='primary' onClick={submitInfo} disabled={submitDisabled}>
保存
</Button>
</div> </div>
</div> </div>
) )
} }
export default AddPlan; export default AddPlan
\ No newline at end of file
/* /*
* @Author: zhangleyuan * @Author: zhangleyuan
* @Date: 2021-02-20 16:13:39 * @Date: 2021-02-20 16:13:39
* @LastEditors: zhangleyuan * @LastEditors: fusanqiasng
* @LastEditTime: 2021-03-10 18:38:50 * @LastEditTime: 2021-05-23 23:59:43
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from 'react'
import PlanFilter from './components/PlanFilter'; import PlanFilter from './components/PlanFilter'
import PlanOpt from './components/PlanOpt'; import PlanOpt from './components/PlanOpt'
import PlanList from './components/PlanList'; import PlanList from './components/PlanList'
import PlanService from "@/domains/plan-domain/planService"; import PlanService from '@/domains/plan-domain/planService'
import User from '@/common/js/user'; import User from '@/common/js/user'
function PlanPage() { function PlanPage() {
const [planListData, setPlanListData] = useState([])
const [planListData, setPlanListData] = useState([]); const [query, setQuery] = useState({
const [query,setQuery] = useState({ current: 1,
current:1, size: 10
size:10, })
});
useEffect(() => { useEffect(() => {
handleFetchPlanList(); function handleFetchPlanList(_query) {
}, [query]);
const [totalCount,setTotalCount] = useState(0);
function queryChange(_query){
const params = { const params = {
...query, ...query,
..._query, ..._query,
}; storeUserId: User.getStoreUserId()
setQuery(params);
} }
function handleFetchPlanList(_query){
const params = {
...query,
..._query,
storeUserId:User.getStoreUserId()
};
//动态获取计划列表 //动态获取计划列表
PlanService.getTrainingPlanPage(params).then((res) => { PlanService.getTrainingPlanPage(params).then((res) => {
const { result: { records = [], total } } = res; const {
setPlanListData(records); result: { records = [], total }
setTotalCount(total); } = res
setPlanListData(records)
setTotalCount(total)
}) })
} }
handleFetchPlanList()
}, [query])
const [totalCount, setTotalCount] = useState(0)
function queryChange(_query) {
const params = {
...query,
..._query
}
setQuery(params)
}
return ( return (
<div className="page"> <div className='page'>
<div className="content-header">培训计划</div> <div className='content-header'>培训计划</div>
<div className="box"> <div className='box'>
<PlanFilter onChange={queryChange}/> <PlanFilter onChange={queryChange} />
<PlanOpt/> <PlanOpt />
<PlanList <PlanList planListData={planListData} query={query} totalCount={totalCount} onChange={queryChange} />
planListData={planListData}
query={query}
totalCount={totalCount}
onChange={queryChange}
/>
</div> </div>
</div> </div>
) )
} }
export default PlanPage; export default PlanPage
\ No newline at end of file
/* /*
* @Author: zhangleyuan * @Author: zhangleyuan
* @Date: 2021-02-20 16:45:51 * @Date: 2021-02-20 16:45:51
* @LastEditors: zhangleyuan * @LastEditors: fusanqiasng
* @LastEditTime: 2021-03-27 14:43:17 * @LastEditTime: 2021-05-24 15:15:06
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import React from 'react'; import React from 'react'
import { Table ,Button,Input,Form,Collapse,Modal } from 'antd'; import { Input, Form, Modal } from 'antd'
import { sortableContainer, sortableElement, sortableHandle} from 'react-sortable-hoc'; import { sortableContainer, sortableElement, sortableHandle } from 'react-sortable-hoc'
import { MenuOutlined } from '@ant-design/icons';
import arrayMove from 'array-move'; import arrayMove from 'array-move'
import RelatedCourseModal from '../modal/relatedCourseModal' import RelatedCourseModal from '../modal/relatedCourseModal'
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom'
import './TrainingTask.less'; import './TrainingTask.less'
const { Panel } = Collapse;
const { confirm } = Modal; const { confirm } = Modal
const CourseType = { const CourseType = {
LIVE: { LIVE: {
text: "直播课" text: '直播课'
}, },
VOICE : { VOICE: {
text:"视频课" text: '视频课'
}, },
RECORD : { RECORD: {
text:'录播课' text: '录播课'
}, },
PICTURE:{ PICTURE: {
text:'图文课' text: '图文课'
} }
}; }
const courseStateShow = { const courseStateShow = {
UN_START: { UN_START: {
title: "待开播", title: '待开播'
}, },
STARTING: { STARTING: {
title: "直播中", title: '直播中'
}, },
FINISH: { FINISH: {
title: "回放", title: '回放'
}, },
EXPIRED: { EXPIRED: {
title: "未成功开课", title: '未成功开课'
}, }
}; }
const DragHandle = sortableHandle(() => ( const DragHandle = sortableHandle(() => (
<span className="operate__item" > <span className='operate__item'>
<span className="icon iconfont">&#xe7cd;</span> <span className='icon iconfont'>&#xe7cd;</span>
<span className="text">移动</span> <span className='text'>移动</span>
</span> </span>
)); ))
const SortableTaskItem = sortableElement((props) => <div {...props}>{props.taskitem}</div>)
const SortableTaskContainer = sortableContainer((props) => <div {...props}></div>)
const SortableTaskItem = sortableElement(props => <div {...props}>{props.taskItem}</div>) const SortableCourseItem = sortableElement((props) => <div {...props}>{props.courseitem}</div>)
const SortableTaskContainer = sortableContainer(props => <div {...props}></div>); const SortableCourseContainer = sortableContainer((props) => <div {...props}></div>)
const SortableCourseItem = sortableElement(props => <div {...props}>{props.courseItem}</div>)
const SortableCourseContainer = sortableContainer(props => <div {...props}></div>);
class TrainingTask extends React.Component { class TrainingTask extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props)
this.state = { this.state = {
dataSource:this.props.data, dataSource: this.props.data,
selectedTaskIndex:0, selectedTaskIndex: 0,
relatedCourseModalVisible:false relatedCourseModalVisible: false
};
} }
componentWillMount(){
} }
componentWillMount() {}
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {}
}
onTaskSortEnd = ({ oldIndex, newIndex }) => { onTaskSortEnd = ({ oldIndex, newIndex }) => {
const { dataSource } = this.state; const { dataSource } = this.state
if (oldIndex !== newIndex) { if (oldIndex !== newIndex) {
const newData = arrayMove([].concat(dataSource), oldIndex, newIndex).filter((el) => !!el)
const newData = arrayMove([].concat(dataSource), oldIndex, newIndex).filter(el => !!el); this.setState(
this.setState({ {
dataSource:newData, dataSource: newData
},()=>{this.props.onChange(newData);}) },
() => {
this.props.onChange(newData)
} }
}; )
onCourseSortEnd = ({ oldIndex, newIndex },parentIndex) => { }
}
const { dataSource } = this.state; onCourseSortEnd = ({ oldIndex, newIndex }, parentIndex) => {
const { dataSource } = this.state
const _dataSource = [...dataSource]; const _dataSource = [...dataSource]
if (oldIndex !== newIndex) { if (oldIndex !== newIndex) {
_dataSource[parentIndex].courseList = arrayMove([].concat(dataSource[parentIndex].courseList), oldIndex, newIndex).filter(el => !!el); _dataSource[parentIndex].courseList = arrayMove([].concat(dataSource[parentIndex].courseList), oldIndex, newIndex).filter((el) => !!el)
this.setState({ this.setState(
dataSource:_dataSource, {
},()=>{this.props.onChange(_dataSource);}) dataSource: _dataSource
},
() => {
this.props.onChange(_dataSource)
}
)
}
} }
};
addTask = () => { addTask = () => {
const { dataSource } = this.state; const { dataSource } = this.state
const taskObj={ const taskObj = {
taskName: '', taskName: '',
index:dataSource.length, index: dataSource.length,
type:'input', type: 'input',
open:true, open: true,
courseList:[ courseList: []
]
} }
const newData = [...dataSource,taskObj]; const newData = [...dataSource, taskObj]
this.setState({ this.setState(
dataSource:newData {
},()=>{this.props.onChange(newData);}) dataSource: newData
},
() => {
this.props.onChange(newData)
}
)
} }
handleRenameTaskName = (e,record) => { handleRenameTaskName = (e, record) => {
const { value } = e.target; const { value } = e.target
const { dataSource } = this.state; const { dataSource } = this.state
record.taskName = value; record.taskName = value
this.setState({ this.setState(
dataSource, {
},()=>{this.props.onChange(dataSource);}) dataSource
} },
handleTaskNameBlur = (e,record)=>{ () => {
const { value } = e.target; this.props.onChange(dataSource)
const { dataSource }= this.state;
let input = /^[\s]*$/;
if(value && !input.test(value)){
record.type="text";
this.setState({
dataSource,
},()=>{this.props.onChange(dataSource);})
} }
)
}
handleTaskNameBlur = (e, record) => {
const { value } = e.target
const { dataSource } = this.state
let input = /^[\s]*$/
if (value && !input.test(value)) {
record.type = 'text'
this.setState(
{
dataSource
},
() => {
this.props.onChange(dataSource)
}
)
} }
handleRenameCourseName = (e,record) => {
const { value } = e.target;
const { dataSource } = this.state;
record.courseName = value;
this.setState({
dataSource,
},()=>{this.props.onChange(dataSource);})
} }
handleCourseNameBlur = (e,record)=>{ handleRenameCourseName = (e, record) => {
const { value } = e.target; const { value } = e.target
const { dataSource }= this.state; const { dataSource } = this.state
let input = /^[\s]*$/; record.courseName = value
if(value && !input.test(value)){ this.setState(
record.type="text"; {
this.setState({ dataSource
dataSource, },
},()=>{this.props.onChange(dataSource);}) () => {
this.props.onChange(dataSource)
}
)
} }
handleCourseNameBlur = (e, record) => {
const { value } = e.target
const { dataSource } = this.state
let input = /^[\s]*$/
if (value && !input.test(value)) {
record.type = 'text'
this.setState(
{
dataSource
},
() => {
this.props.onChange(dataSource)
}
)
} }
handleDeleteTask = (index)=>{ }
handleDeleteTask = (index) => {
return confirm({ return confirm({
title: "删除任务", title: '删除任务',
content: "删除该任务会同步删除任务下的课程,是否仍要删除?", content: '删除该任务会同步删除任务下的课程,是否仍要删除?',
icon: ( icon: <span className='icon iconfont default-confirm-icon'>&#xe839; </span>,
<span className="icon iconfont default-confirm-icon">&#xe839; </span> okText: '删除',
), okType: 'danger',
okText: "删除", cancelText: '取消',
okType: "danger",
cancelText: "取消",
onOk: () => { onOk: () => {
this.handleConfirmDeleteTask(index); this.handleConfirmDeleteTask(index)
}
})
}
handleConfirmDeleteTask = (index) => {
const { dataSource } = this.state
const newData = [...dataSource]
newData.splice(index, 1)
this.setState(
{
dataSource: newData
}, },
}); () => {
this.props.onChange(newData)
} }
handleConfirmDeleteTask = (index)=>{ )
const {dataSource}= this.state;
const newData=[...dataSource];
newData.splice(index,1);
this.setState({
dataSource:newData,
},()=>{this.props.onChange(newData);})
} }
handleDeleteCourse = (parentIndex,index)=>{ handleDeleteCourse = (parentIndex, index) => {
return confirm({ return confirm({
title: "删除课程", title: '删除课程',
content: "确定删除该课程吗?", content: '确定删除该课程吗?',
icon: ( icon: <span className='icon iconfont default-confirm-icon'>&#xe839; </span>,
<span className="icon iconfont default-confirm-icon">&#xe839; </span> okText: '删除',
), okType: 'danger',
okText: "删除", cancelText: '取消',
okType: "danger",
cancelText: "取消",
onOk: () => { onOk: () => {
this.handleConfirmDeleteCourse(parentIndex,index); this.handleConfirmDeleteCourse(parentIndex, index)
}, }
}); })
} }
handleConfirmDeleteCourse = (parentIndex,index)=>{ handleConfirmDeleteCourse = (parentIndex, index) => {
const {dataSource}= this.state; const { dataSource } = this.state
const newData=[...dataSource]; const newData = [...dataSource]
const selectData = [...newData[parentIndex].courseList] const selectData = [...newData[parentIndex].courseList]
selectData.splice(index,1) selectData.splice(index, 1)
newData[parentIndex].courseList= selectData; newData[parentIndex].courseList = selectData
this.setState({ this.setState(
dataSource:newData, {
},()=>{this.props.onChange(newData);}) dataSource: newData
},
() => {
this.props.onChange(newData)
}
)
} }
showRelatedCourseModal = (index)=>{ showRelatedCourseModal = (index) => {
this.setState({ this.setState({
selectedTaskIndex:index, selectedTaskIndex: index,
relatedCourseModalVisible:true relatedCourseModalVisible: true
}) })
} }
closeRelatedCourseModal = (index)=>{ closeRelatedCourseModal = (index) => {
this.setState({ this.setState({
relatedCourseModalVisible:false relatedCourseModalVisible: false
}) })
} }
confirmSelectCourse = (selectList) =>{ confirmSelectCourse = (selectList) => {
console.log("selectList",selectList); console.log('selectList', selectList)
const {selectedTaskIndex}= this.state; const { selectedTaskIndex } = this.state
const { dataSource } = this.state const { dataSource } = this.state
const newData=[...dataSource]; const newData = [...dataSource]
const selectData = [...newData[selectedTaskIndex].courseList] const selectData = [...newData[selectedTaskIndex].courseList]
const _selectData =[...selectData,...selectList]; const _selectData = [...selectData, ...selectList]
newData[selectedTaskIndex].courseList= _selectData; newData[selectedTaskIndex].courseList = _selectData
this.setState({ this.setState(
relatedCourseModalVisible:false, {
dataSource:newData, relatedCourseModalVisible: false,
},()=>{ dataSource: newData
this.props.onChange(newData); },
}) () => {
this.props.onChange(newData)
} }
openOrCloseTask = (index)=>{ )
const {dataSource}= this.state;
const newData=[...dataSource];
newData[index].open = !newData[index].open;
this.setState({
dataSource:newData,
},()=>{this.props.onChange(newData);})
} }
handleValidatorTaskName = (rule,value)=>{ openOrCloseTask = (index) => {
let input = /^[\s]*$/; const { dataSource } = this.state
if (input.test(value) || !value){ const newData = [...dataSource]
newData[index].open = !newData[index].open
this.setState(
{
dataSource: newData
},
() => {
this.props.onChange(newData)
}
)
}
handleValidatorTaskName = (rule, value) => {
let input = /^[\s]*$/
if (input.test(value) || !value) {
return Promise.reject(new Error('请输入任务名称')) return Promise.reject(new Error('请输入任务名称'))
} }
return Promise.resolve() return Promise.resolve()
} }
handleValidatorCourseName = (rule,value)=>{ handleValidatorCourseName = (rule, value) => {
let input = /^[\s]*$/; let input = /^[\s]*$/
if (input.test(value) || !value){ if (input.test(value) || !value) {
return Promise.reject(new Error('请输入课程名称')) return Promise.reject(new Error('请输入课程名称'))
} }
return Promise.resolve() return Promise.resolve()
} }
renderTaskItem = (record,index)=>{ renderTaskItem = (record, index) => {
return <div className="plan-sort-task-item"> return (
<div className="task-con"> <div className='plan-sort-task-item'>
<div className="task-instro"> <div className='task-con'>
<span onClick={()=>this.openOrCloseTask(index)}> <div className='task-instro'>
{record.open? <span onClick={() => this.openOrCloseTask(index)}>
<span className="icon iconfont open-icon">&#xe82d;</span>: {record.open ? <span className='icon iconfont open-icon'>&#xe82d;</span> : <span className='icon iconfont open-icon'>&#xe835;</span>}
<span className="icon iconfont open-icon">&#xe835;</span>
}
</span> </span>
{record.type==='input'? <Choose>
<div className="task-name-con"> <When condition={record.type === 'input'}>
<span className="number">{index + 1}.</span> <div className='task-name-con'>
<span className='number'>{index + 1}.</span>
<Form> <Form>
<Form.Item <Form.Item
initialValue={record.taskName}
validateTrigger={['onChange', 'onBlur']} validateTrigger={['onChange', 'onBlur']}
name={['taskName']} name={['taskName']}
rules={[ rules={[
{ {
validator:(rule,value)=>this.handleValidatorTaskName(rule,value) validator: (rule, value) => this.handleValidatorTaskName(rule, value)
} }
]}> ]}>
<Input className="task-name-input" defaultValue={record.taskName} style={{ width: 300 }} placeholder="请输入任务名称(20字以内)" maxLength={20} onChange={(e) => { this.handleRenameTaskName(e,record)}} onBlur={(e)=>{this.handleTaskNameBlur(e,record)}}/> <Input
className='task-name-input'
style={{ width: 300 }}
placeholder='请输入任务名称(20字以内)'
maxLength={20}
onChange={(e) => {
this.handleRenameTaskName(e, record)
}}
onBlur={(e) => {
this.handleTaskNameBlur(e, record)
}}
/>
</Form.Item> </Form.Item>
</Form> </Form>
</div> </div>
: </When>
<div className="task-name-con"> <Otherwise>
<span className="number">{index + 1}.</span> <div className='task-name-con'>
<span className="task-name">{record.taskName}</span> <span className='number'>{index + 1}.</span>
<span className='task-name'>{record.taskName}</span>
</div> </div>
} </Otherwise>
</Choose>
</div> </div>
<div className="operate"> <div className='operate'>
<DragHandle /> <DragHandle />
<span className="operate__item" onClick={()=>{const { dataSource }= this.state; record.type="input";this.setState({dataSource})}}> <span
<span className="icon iconfont">&#xe6f5;</span> className='operate__item'
<span className="text">重命名</span> onClick={() => {
const { dataSource } = this.state
record.type = 'input'
this.setState({ dataSource })
}}>
<span className='icon iconfont'>&#xe6f5;</span>
<span className='text'>重命名</span>
</span> </span>
<span className="operate__item" onClick={()=>{this.handleDeleteTask(index)}} > <span
<span className="icon iconfont">&#xe6f6;</span> className='operate__item'
<span className="text">删除</span> onClick={() => {
this.handleDeleteTask(index)
}}>
<span className='icon iconfont'>&#xe6f6;</span>
<span className='text'>删除</span>
</span> </span>
</div> </div>
</div> </div>
{record.open && {record.open && (
<div className="course-box"> <div className='course-box'>
<SortableCourseContainer <SortableCourseContainer useDragHandle disableAutoscroll helperClass='row-dragging' onSortEnd={(record) => this.onCourseSortEnd(record, index)}>
useDragHandle {record.courseList.map((item, courseIndex) => (
disableAutoscroll <SortableCourseItem courseitem={this.renderCourseItem(item, courseIndex, index)} index={courseIndex} key={courseIndex}></SortableCourseItem>
helperClass="row-dragging" ))}
onSortEnd={(record)=>this.onCourseSortEnd(record,index)} >
{record.courseList.map((courseItem, courseIndex) =>
<SortableCourseItem courseItem={this.renderCourseItem(courseItem,courseIndex,index)} index={courseIndex}>
</SortableCourseItem>
)}
</SortableCourseContainer> </SortableCourseContainer>
<div className="add-course-con"> <div className='add-course-con'>
{record.courseList.length>19? <Choose>
<span className="add-course-btn-disabled" onClick={()=>{this.showRelatedCourseModal(index)}}><span>+</span><span>关联课程</span></span> <When condition={record.courseList.length > 19}>
: <span
<span className="add-course-btn" onClick={()=>{this.showRelatedCourseModal(index)}}><span>+</span><span>关联课程</span></span> className='add-course-btn-disabled'
} onClick={() => {
this.showRelatedCourseModal(index)
}}>
<span>+</span>
<span>关联课程</span>
</span>
</When>
<Otherwise>
<span
className='add-course-btn'
onClick={() => {
this.showRelatedCourseModal(index)
}}>
<span>+</span>
<span>关联课程</span>
</span>
</Otherwise>
</Choose>
</div> </div>
</div> </div>
} )}
</div> </div>
)
} }
renderCourseItem = (record,index,parentIndex)=>{ renderCourseItem = (record, index, parentIndex) => {
return <div className="plan-course-sort-item"> return (
<div className="course-info"> <div className='plan-course-sort-item'>
<span className="course-type">{CourseType[record.courseType].text}</span> <div className='course-info'>
{record.type==='input'? <span className='course-type'>{CourseType[record.courseType].text}</span>
<Choose>
<When condition={record.type === 'input'}>
<Form> <Form>
<Form.Item <Form.Item
initialValue={record.courseName}
validateTrigger={['onChange', 'onBlur']} validateTrigger={['onChange', 'onBlur']}
name={['courseName']} name={['courseName']}
rules={[ rules={[
{ {
validator:(rule,value)=>this.handleValidatorCourseName(rule,value) validator: (rule, value) => this.handleValidatorCourseName(rule, value)
} }
]}> ]}>
<Input className="course-name-input" defaultValue={record.courseName} style={{ width: 300 }} placeholder="请输入课程名称(40字以内)" maxLength={40} onChange={(e) => { this.handleRenameCourseName(e,record)}} onBlur={(e)=>{this.handleCourseNameBlur(e,record)}}/></Form.Item> <Input
className='course-name-input'
style={{ width: 300 }}
placeholder='请输入课程名称(40字以内)'
maxLength={40}
onChange={(e) => {
this.handleRenameCourseName(e, record)
}}
onBlur={(e) => {
this.handleCourseNameBlur(e, record)
}}
/>
</Form.Item>
</Form> </Form>
: </When>
<span className="course-name">{parentIndex + 1}.{index + 1} {record.courseName}</span> <Otherwise>
} <span className='course-name'>
{record.courseState === "EXPIRED" && {parentIndex + 1}.{index + 1} {record.courseName}
<span className="icon iconfont tip">&#xe834;</span> </span>
} </Otherwise>
{ record.courseType==="LIVE" && </Choose>
<span className="course-state">{courseStateShow[record.courseState].title}</span>
}
{record.courseState === 'EXPIRED' && <span className='icon iconfont tip'>&#xe834;</span>}
{record.courseType === 'LIVE' && <span className='course-state'>{courseStateShow[record.courseState].title}</span>}
</div> </div>
<div className="course-operate"> <div className='course-operate'>
<DragHandle /> <DragHandle />
{/* <span className="operate__item">
<span className="icon iconfont">&#xe6f5;</span> <span
<span className="text" onClick={(e)=>{const { dataSource } = this.state; record.type="input";this.setState({dataSource})}}>重命名</span> className='operate__item'
</span> */} onClick={() => {
<span className="operate__item" onClick={()=>{this.handleDeleteCourse(parentIndex,index)}}> this.handleDeleteCourse(parentIndex, index)
<span className="icon iconfont">&#xe6f6;</span> }}>
<span className="text">删除</span> <span className='icon iconfont'>&#xe6f6;</span>
<span className='text'>删除</span>
</span> </span>
</div> </div>
</div> </div>
)
} }
render() { render() {
const { dataSource,selectedTaskIndex,relatedCourseModalVisible} = this.state; const { dataSource, selectedTaskIndex, relatedCourseModalVisible } = this.state
console.log('dataSource', dataSource)
const { data } = this.props;
return ( return (
<div className="training-task"> <div className='training-task'>
<SortableTaskContainer <SortableTaskContainer useDragHandle disableAutoscroll helperClass='row-dragging' onSortEnd={this.onTaskSortEnd} className='plan-task-sort-container'>
useDragHandle {dataSource.map((item, index) => (
disableAutoscroll <SortableTaskItem taskitem={this.renderTaskItem(item, index)} index={index} key={index}></SortableTaskItem>
helperClass="row-dragging" ))}
onSortEnd={this.onTaskSortEnd}
className="plan-task-sort-container"
>
{dataSource.map((item, index) =>
<SortableTaskItem taskItem={this.renderTaskItem(item,index)} index={index}>
</SortableTaskItem>
)}
</SortableTaskContainer> </SortableTaskContainer>
<div className="add-task-con"> <div className='add-task-con'>
{dataSource.length > 9 ? <Choose>
<span className="add-task-btn-disabled"><span>+</span><span>添加任务</span></span> <When condition={dataSource.length > 9}>
: <span className='add-task-btn-disabled'>
<span className="add-task-btn" onClick={()=>this.addTask()}><span>+</span><span>添加任务</span></span> <span>+</span>
} <span>添加任务</span>
</span>
</When>
<Otherwise>
<span className='add-task-btn' onClick={() => this.addTask()}>
<span>+</span>
<span>添加任务</span>
</span>
</Otherwise>
</Choose>
</div> </div>
{ relatedCourseModalVisible && {relatedCourseModalVisible && (
<RelatedCourseModal <RelatedCourseModal
selectedTaskIndex={selectedTaskIndex} selectedTaskIndex={selectedTaskIndex}
data={dataSource} data={dataSource}
...@@ -403,9 +492,9 @@ class TrainingTask extends React.Component { ...@@ -403,9 +492,9 @@ class TrainingTask extends React.Component {
onClose={this.closeRelatedCourseModal} onClose={this.closeRelatedCourseModal}
onSelect={this.confirmSelectCourse} onSelect={this.confirmSelectCourse}
/> />
} )}
</div> </div>
); )
} }
} }
......
import React from 'react'; import React from 'react'
import {Table, Modal,Input,message,Button,Tooltip} from 'antd'; import _ from 'underscore'
import { PageControl } from "@/components"; import { Table, Radio, Tabs, Modal, Input, message, Button, Tooltip } from 'antd'
import CourseService from "@/domains/course-domain/CourseService";
import User from '@/common/js/user'; import { PageControl } from '@/components'
import Service from '@/common/js/service';
import { Tabs } from 'antd'; import CourseService from '@/domains/course-domain/CourseService'
import './relatedCourseModal.less'; import User from '@/common/js/user'
import _ from "underscore"; import Service from '@/common/js/service'
import dealTimeDuration from "../../course-manage/utils/dealTimeDuration"; import dealTimeDuration from '../../course-manage/utils/dealTimeDuration'
const { Search } = Input; import './relatedCourseModal.less'
const { TabPane } = Tabs;
const { Search } = Input
const { TabPane } = Tabs
const courseStateShow = { const courseStateShow = {
UN_START: { UN_START: {
code: 1, code: 1,
title: "待开课", title: '待开课',
color: "#FFB714", color: '#FFB714'
}, },
STARTING: { STARTING: {
code: 2, code: 2,
title: "上课中", title: '上课中',
color: "#238FFF", color: '#238FFF'
}, },
FINISH: { FINISH: {
code: 3, code: 3,
title: "已完成", title: '已完成',
color: "#3BBDAA", color: '#3BBDAA'
}, },
EXPIRED: { EXPIRED: {
code: 4, code: 4,
title: "未成功开课", title: '未成功开课',
color: "#999", color: '#999'
}, }
}; }
class SelectOperatorModal extends React.Component { class SelectOperatorModal extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props)
this.state = { this.state = {
liveDataSource:[], liveDataSource: [],
liveSize:10, liveSize: 10,
liveQuery: { liveQuery: {
current: 1, current: 1
}, },
liveTotalCount:0, liveTotalCount: 0,
selectLive:[],//弹窗内已选择的直播课程 selectLive: [], //弹窗内已选择的直播课程
currentCourseListData:[], currentCourseListData: [],
currentLiveCourseListData:[], //页面中已关联的直播课程 currentLiveCourseListData: [], //页面中已关联的直播课程
videoDataSource:[], videoCourseDivision: 'internal',
videoSize:10, videoDataSource: {
external: [],
internal: []
},
videoSize: {
external: 10,
internal: 10
},
videoSearchName: {
external: '',
internal: ''
},
videoSearchDefalt: '',
videoQuery: { videoQuery: {
current: 1, external: {
current: 1
}, },
videoTotalCount:0, internal: {
selectVideo:[], //弹窗内已选择的视频课程 current: 1
currentVideoCourseListData:[], //页面中已关联的视频课程 }
},
pictureDataSource:[], videoTotalCount: {
pictureSize:10, external: 0,
internal: 0
},
selectVideo: {
external: [],
internal: []
}, //弹窗内已选择的视频课程
currentVideoCourseListData: {
external: [],
internal: []
}, //页面中已关联的视频课程
pictureDataSource: [],
pictureSize: 10,
pictureQuery: { pictureQuery: {
current: 1, current: 1
}, },
pictureTotalCount:0, pictureTotalCount: 0,
selectPicture:[], //弹窗内已选择的视频课程 selectPicture: [], //弹窗内已选择的视频课程
currentPictureCourseListData:[], //页面中已关联的视频课程 currentPictureCourseListData: [], //页面中已关联的视频课程
activeKey:'video', activeKey: 'video',
currentTaskCourseData:this.props.data[this.props.selectedTaskIndex].courseList || [] currentTaskCourseData: this.props.data[this.props.selectedTaskIndex].courseList || []
} }
} }
componentDidMount() { componentDidMount() {
this.handleFetchLiveDataList(); this.handleFetchLiveDataList()
this.handleFetchVideoDataList(); this.handleFetchVideoDataList()
this.handleFetchPictureDataList(); this.handleFetchPictureDataList()
} }
// 获取直播课列表 // 获取直播课列表
handleFetchLiveDataList = () => { handleFetchLiveDataList = () => {
const {liveQuery,liveSize} = this.state; const { liveQuery, liveSize } = this.state
const { selectedTaskIndex } =this.props; const _data = [...this.props.data]
const _data = [...this.props.data]; let currentLiveCourseListData = []
let currentLiveCourseListData = []; _data.map((item) => {
_data.map((item,index) => { item.courseList.map((childItem, childIndex) => {
item.courseList.map((childItem,childIndex)=>{ if (childItem.courseType === 'LIVE') {
if(childItem.courseType ==="LIVE"){
currentLiveCourseListData.push(childItem.courseId) currentLiveCourseListData.push(childItem.courseId)
} }
return childItem return childItem
}) })
return item return item
}); })
const params ={ const params = {
...liveQuery, ...liveQuery,
size:liveSize, size: liveSize,
excludeCourseIdList:currentLiveCourseListData excludeCourseIdList: currentLiveCourseListData
} }
CourseService.getLiveCloudCourseBasePage(params).then((res) => { CourseService.getLiveCloudCourseBasePage(params).then((res) => {
const { result = {} } = res ; const { result = {} } = res
const { records = [], total = 0 } = result; const { records = [], total = 0 } = result
this.setState({ this.setState({
liveDataSource: records, liveDataSource: records,
liveTotalCount: Number(total), liveTotalCount: Number(total),
currentLiveCourseListData currentLiveCourseListData
}); })
}); })
} }
// 获取视频课列表 // 获取视频课列表
handleFetchVideoDataList = () => { handleFetchVideoDataList = () => {
const {videoQuery,videoSize,videoTotalCount} = this.state; const { videoQuery, videoSize, videoDataSource, videoTotalCount, videoCourseDivision } = this.state
const { selectedTaskIndex } =this.props;
const _data = [...this.props.data]; const _data = [...this.props.data]
let currentVideoCourseListData = []; let currentVideoCourseListData = []
_data.map((item,index) => { _data.map((item, index) => {
item.courseList.map((childItem,childIndex)=>{ item.courseList.map((childItem, childIndex) => {
if(childItem.courseType ==="VOICE"){ if (childItem.courseType === 'VOICE') {
currentVideoCourseListData.push(childItem.courseId) currentVideoCourseListData.push(childItem.courseId)
} }
return childItem return childItem
}) })
return item return item
}); })
const params ={ const params = {
...videoQuery, ...videoQuery[videoCourseDivision],
size:videoSize, size: videoSize[videoCourseDivision],
excludeCourseIdList:currentVideoCourseListData courseDivision: videoCourseDivision === 'internal' ? 'INTERNAL' : 'EXTERNAL',
excludeCourseIdList: currentVideoCourseListData
} }
CourseService.videoScheduleBasePage(params).then((res) => { CourseService.videoScheduleBasePage(params).then((res) => {
const { result = {} } = res ; const { result = {} } = res
const { records = [], total = 0 } = result; console.log('result', result)
const { records = [], total = 0 } = result
this.setState({ this.setState({
videoDataSource: records, videoDataSource: {
videoTotalCount: Number(total), ...videoDataSource,
[videoCourseDivision]: records
},
videoTotalCount: {
...videoTotalCount,
[videoCourseDivision]: Number(total)
},
currentVideoCourseListData currentVideoCourseListData
}); })
}); })
} }
// 获取图文课列表 // 获取图文课列表
handleFetchPictureDataList = () => { handleFetchPictureDataList = () => {
const {pictureQuery,pictureSize} = this.state; const { pictureQuery, pictureSize } = this.state
const { selectedTaskIndex } =this.props; const _data = [...this.props.data]
const _data = [...this.props.data]; let currentPictureCourseListData = []
let currentPictureCourseListData = []; _data.map((item, index) => {
_data.map((item,index) => { item.courseList.map((childItem, childIndex) => {
item.courseList.map((childItem,childIndex)=>{ if (childItem.courseType === 'PICTURE') {
if(childItem.courseType ==="PICTURE"){
currentPictureCourseListData.push(childItem.courseId) currentPictureCourseListData.push(childItem.courseId)
} }
return childItem return childItem
}) })
return item return item
}); })
const params ={ const params = {
...pictureQuery, ...pictureQuery,
size:pictureSize, size: pictureSize,
courseType:"PICTURE", courseType: 'PICTURE',
storeId:User.getStoreId(), storeId: User.getStoreId(),
excludeCourseIdList:currentPictureCourseListData excludeCourseIdList: currentPictureCourseListData
} }
Service.Hades('public/hades/mediaCoursePage', params).then((res) => { Service.Hades('public/hades/mediaCoursePage', params).then((res) => {
const { result = {} } = res ; const { result = {} } = res
const { records = [], total = 0 } = result; const { records = [], total = 0 } = result
this.setState({ this.setState({
pictureDataSource: records, pictureDataSource: records,
pictureTotalCount: Number(total), pictureTotalCount: Number(total),
currentPictureCourseListData currentPictureCourseListData
}); })
}); })
} }
handleChangVideoCourseName = (value)=>{ handleChangVideoCourseName = (value) => {
const { videoQuery } = this.state; const { videoQuery, videoCourseDivision, videoSearchName } = this.state
videoQuery.courseName = value; videoQuery[videoCourseDivision].courseName = value
videoQuery.current = 1; videoQuery[videoCourseDivision].current = 1
this.setState({ this.setState({
videoQuery ...videoQuery,
videoSearchDefalt: value,
videoSearchName: {
...videoSearchName,
[videoCourseDivision]: value
}
}) })
} }
handleChangLiveCourseName = (value)=>{ handleChangLiveCourseName = (value) => {
const { liveQuery } = this.state; const { liveQuery } = this.state
liveQuery.courseName = value; liveQuery.courseName = value
liveQuery.current = 1; liveQuery.current = 1
this.setState({ this.setState({
liveQuery liveQuery
}) })
} }
handleChangPictureCourseName = (value)=>{ handleChangPictureCourseName = (value) => {
const { pictureQuery } = this.state; const { pictureQuery } = this.state
pictureQuery.courseName = value; pictureQuery.courseName = value
pictureQuery.current = 1; pictureQuery.current = 1
this.setState({ this.setState({
pictureQuery pictureQuery
}) })
} }
onShowLiveSizeChange = (current, size) => { onShowLiveSizeChange = (current, size) => {
if (current == size) { if (current === size) {
return return
} }
this.setState({ this.setState(
liveSize:size {
},()=>{this.handleFetchLiveDataList()}) liveSize: size
},
() => {
this.handleFetchLiveDataList()
}
)
} }
onShowVideoSizeChange = (current, size) => { onShowVideoSizeChange = (current, size) => {
if (current == size) { if (current === size) {
return return
} }
this.setState({ this.setState(
videoSize:size {
},()=>{this.handleFetchLiveDataList()}) videoSize: size
},
() => {
this.handleFetchLiveDataList()
}
)
} }
onShowPictureSizeChange = (current, size) => { onShowPictureSizeChange = (current, size) => {
if (current == size) { if (current === size) {
return return
} }
this.setState({ this.setState(
pictureSize:size {
},()=>{this.handleFetchPictureDataList()}) pictureSize: size
},
() => {
this.handleFetchPictureDataList()
}
)
} }
// 请求表头 // 请求表头
parseLiveColumns = () => { parseLiveColumns = () => {
const columns = [ const columns = [
{ {
title: <span><span>课程信息</span><Tooltip title="仅显示未关联课程,已关联课程不支持重复选择"><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip></span>, title: (
<span>
<span>课程信息</span>
<Tooltip title='仅显示未关联课程,已关联课程不支持重复选择'>
<i className='icon iconfont' style={{ marginLeft: '5px', cursor: 'pointer', color: '#bfbfbf', fontSize: '14px' }}>
&#xe61d;
</i>
</Tooltip>
</span>
),
key: 'course', key: 'course',
dataIndex: 'course', dataIndex: 'course',
width:'40%', width: '40%',
render: (val, record) => { render: (val, record) => {
let hasCover = false; let hasCover = false
return ( return (
<div className="course-info"> <div className='course-info'>
{ {record.courseMediaVOS.map((item) => {
record.courseMediaVOS.map((item,index)=>{ if (item.contentType === 'COVER') {
if( item.contentType === "COVER"){ hasCover = true
hasCover = true; return <img className='course-cover' src={item.mediaUrl} alt='' />
return <img className="course-cover" src={item.mediaUrl}/> }
} return null
}) })}
} <If condition={!hasCover}>
{ !hasCover && <img className='course-cover' src={'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png'} alt='' />
<img className="course-cover" src={'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png'} /> </If>
}
<div> <div>
<div className="course-name">{record.courseName}</div> <div className='course-name'>{record.courseName}</div>
<span className="course-status" style={{color:courseStateShow[record.courseState].color,border:`1px solid ${courseStateShow[record.courseState].color}`}}>{courseStateShow[record.courseState].title}</span> <span
className='course-status'
style={{ color: courseStateShow[record.courseState].color, border: `1px solid ${courseStateShow[record.courseState].color}` }}>
{courseStateShow[record.courseState].title}
</span>
</div> </div>
</div> </div>
) )
...@@ -263,12 +331,14 @@ class SelectOperatorModal extends React.Component { ...@@ -263,12 +331,14 @@ class SelectOperatorModal extends React.Component {
title: '上课时间', title: '上课时间',
key: 'courseTime', key: 'courseTime',
dataIndex: 'courseTime', dataIndex: 'courseTime',
width:'40%', width: '40%',
render: (val, record) => { render: (val, record) => {
return ( return (
<div> <div>
<div>{formatDate('YYYY-MM-DD', record.startTime)}</div> <div>{formatDate('YYYY-MM-DD', record.startTime)}</div>
<div>{formatDate('H:i', record.startTime)}~{formatDate('H:i', record.endTime)}</div> <div>
{formatDate('H:i', record.startTime)}~{formatDate('H:i', record.endTime)}
</div>
</div> </div>
) )
} }
...@@ -277,39 +347,50 @@ class SelectOperatorModal extends React.Component { ...@@ -277,39 +347,50 @@ class SelectOperatorModal extends React.Component {
title: '学院展示', title: '学院展示',
key: 'shelfState', key: 'shelfState',
dataIndex: 'shelfState', dataIndex: 'shelfState',
width:'20%', width: '20%',
render: (val, record) => { render: (val, record) => {
return ( return (
<span> <span>
{record.shelfState==="YES"? <Choose>
<When condition={record.shelfState === 'YES'}>
<span>开启</span> <span>开启</span>
: </When>
<Otherwise>
<span>关闭</span> <span>关闭</span>
} </Otherwise>
</Choose>
</span> </span>
) )
} }
}, }
]
]; return columns
return columns;
} }
// 请求表头 // 请求表头
parseVideoColumns = () => { parseVideoColumns = () => {
const columns = [ const columns = [
{ {
title: <span><span>课程信息</span><Tooltip title="仅显示未关联课程,已关联课程不支持重复选择"><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip></span>, title: (
<span>
<span>课程信息</span>
<Tooltip title='仅显示未关联课程,已关联课程不支持重复选择'>
<i className='icon iconfont' style={{ marginLeft: '5px', cursor: 'pointer', color: '#bfbfbf', fontSize: '14px' }}>
&#xe61d;
</i>
</Tooltip>
</span>
),
key: 'course', key: 'course',
dataIndex: 'course', dataIndex: 'course',
width:'60%', width: '40%',
render: (val, record) => { render: (val, record) => {
const { coverUrl, scheduleVideoUrl } = record; const { coverUrl, scheduleVideoUrl } = record
return ( return (
<div className="course-info"> <div className='course-info'>
{/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */} {/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */}
<img className="course-cover" src={coverUrl || `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`}/> <img className='course-cover' src={coverUrl || `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`} alt='' />
<div className="course-name">{record.courseName}</div> <div className='course-name'>{record.courseName}</div>
</div> </div>
) )
} }
...@@ -318,50 +399,57 @@ class SelectOperatorModal extends React.Component { ...@@ -318,50 +399,57 @@ class SelectOperatorModal extends React.Component {
title: '课程时长', title: '课程时长',
key: 'courseTime', key: 'courseTime',
dataIndex: 'courseTime', dataIndex: 'courseTime',
width:'20%', width: '20%',
render: (val, record) => { render: (val, record) => {
return ( return <span className='course-status'>{dealTimeDuration(record.videoDuration)}</span>
<span className="course-status">{dealTimeDuration(record.videoDuration)}</span>
)
} }
}, },
{ {
title: '学院展示', title: '学院展示',
key: 'shelfState', key: 'shelfState',
dataIndex: 'shelfState', dataIndex: 'shelfState',
width:'20%', width: '20%',
render: (val, record) => { render: (val, record) => {
return ( return (
<span> <Choose>
{record.shelfState==="YES"? <When condition={record.shelfState === 'YES'}>
<span>开启</span> <span>开启</span>
: </When>
<Otherwise>
<span>关闭</span> <span>关闭</span>
} </Otherwise>
</span> </Choose>
) )
} }
} }
]
]; return columns
return columns;
} }
// 请求表头 // 请求表头
parsePictureColumns = () => { parsePictureColumns = () => {
const columns = [ const columns = [
{ {
title: <span><span>课程信息</span><Tooltip title="仅显示未关联课程,已关联课程不支持重复选择"><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf',fontSize:'14px'}}>&#xe61d;</i></Tooltip></span>, title: (
<span>
<span>课程信息</span>
<Tooltip title='仅显示未关联课程,已关联课程不支持重复选择'>
<i className='icon iconfont' style={{ marginLeft: '5px', cursor: 'pointer', color: '#bfbfbf', fontSize: '14px' }}>
&#xe61d;
</i>
</Tooltip>
</span>
),
key: 'course', key: 'course',
dataIndex: 'course', dataIndex: 'course',
width:'55%', width: '55%',
render: (val, record) => { render: (val, record) => {
const { coverUrl } = record; const { coverUrl } = record
return ( return (
<div className="course-info"> <div className='course-info'>
{/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */} {/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */}
<img className="course-cover" src={coverUrl || 'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png'}/> <img className='course-cover' src={coverUrl || 'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png'} alt='' />
<div className="course-name">{record.courseName}</div> <div className='course-name'>{record.courseName}</div>
</div> </div>
) )
} }
...@@ -370,136 +458,177 @@ class SelectOperatorModal extends React.Component { ...@@ -370,136 +458,177 @@ class SelectOperatorModal extends React.Component {
title: '更新时间', title: '更新时间',
key: 'updated', key: 'updated',
dataIndex: 'updated', dataIndex: 'updated',
width:'25%', width: '25%',
render: (val, record) => { render: (val, record) => {
return ( return <span className='course-status'>{formatDate('YYYY-MM-DD', record.updated)}</span>
<span className="course-status">{formatDate('YYYY-MM-DD',record.updated)}</span>
)
} }
}, },
{ {
title: '学院展示', title: '学院展示',
key: 'shelfState', key: 'shelfState',
dataIndex: 'shelfState', dataIndex: 'shelfState',
width:'20%', width: '20%',
render: (val, record) => { render: (val, record) => {
return ( return <span>{record.shelfState === 'YES' ? '开启' : '关闭'}</span>
<span>
{record.shelfState==="YES"?
<span>开启</span>
:
<span>关闭</span>
}
</span>
)
} }
} }
]
]; return columns
return columns;
} }
selectLiveList = (record,selected) =>{ selectLiveList = (record, selected) => {
const {selectVideo,currentTaskCourseData,selectLive,selectPicture} = this.state; const { selectVideo, currentTaskCourseData, selectLive, selectPicture } = this.state
let _list = []; let _list = []
if (selected || !_.find(selectLive, (item) => item.liveCourseId == record.liveCourseId)) { if (selected || !_.find(selectLive, (item) => item.liveCourseId === record.liveCourseId)) {
_list = _.uniq(selectLive.concat([record]), false, (item) => item.liveCourseId); _list = _.uniq(selectLive.concat([record]), false, (item) => item.liveCourseId)
} else { } else {
_list = _.reject(selectLive, (item) => item.liveCourseId === record.liveCourseId); _list = _.reject(selectLive, (item) => item.liveCourseId === record.liveCourseId)
} }
if(_list.length + currentTaskCourseData.length + selectVideo.length + selectPicture.length > 20){ if (_list.length + currentTaskCourseData.length + selectVideo.length + selectPicture.length > 20) {
message.warning('无法继续选择,一个任务最多关联20个课程'); message.warning('无法继续选择,一个任务最多关联20个课程')
return; return
} }
this.setState({selectLive:_list}); this.setState({ selectLive: _list })
} }
selectVideoList = (record,selected) =>{ selectVideoList = (record, selected) => {
const {selectVideo,currentTaskCourseData,selectLive,selectPicture} = this.state; const { selectVideo, currentTaskCourseData, selectLive, selectPicture, videoCourseDivision } = this.state
let _list = [];
if (selected || !_.find(selectVideo, (item) => item.id == record.id)) { let { [videoCourseDivision]: selectList } = selectVideo
_list = _.uniq(selectVideo.concat([record]), false, (item) => item.id);
let _list = []
if (selected || !_.find(selectList, (item) => item.id === record.id)) {
_list = _.uniq(selectList.concat([record]), false, (item) => item.id)
} else { } else {
_list = _.reject(selectVideo, (item) => item.id === record.id); _list = _.reject(selectList, (item) => item.id === record.id)
} }
if(_list.length + currentTaskCourseData.length + selectLive.length + selectPicture.length > 20){ if (_list.length + currentTaskCourseData.length + selectLive.length + selectPicture.length > 20) {
message.warning('无法继续选择,一个任务最多关联20个课程'); message.warning('无法继续选择,一个任务最多关联20个课程')
return; return
} }
this.setState({selectVideo:_list}); this.setState({
selectVideo: {
...selectVideo,
[videoCourseDivision]: _list
}
})
} }
selectPictureList = (record,selected) =>{ selectPictureList = (record, selected) => {
const {selectVideo,currentTaskCourseData,selectLive,selectPicture} = this.state; const { selectVideo, currentTaskCourseData, selectLive, selectPicture } = this.state
let _list = []; let _list = []
if (selected || !_.find(selectPicture, (item) => item.id == record.id)) { if (selected || !_.find(selectPicture, (item) => item.id === record.id)) {
_list = _.uniq(selectPicture.concat([record]), false, (item) => item.id); _list = _.uniq(selectPicture.concat([record]), false, (item) => item.id)
} else { } else {
_list = _.reject(selectPicture, (item) => item.id === record.id); _list = _.reject(selectPicture, (item) => item.id === record.id)
} }
if(_list.length + currentTaskCourseData.length + selectLive.length + selectVideo.length > 20){ if (_list.length + currentTaskCourseData.length + selectLive.length + selectVideo.length > 20) {
message.warning('无法继续选择,一个任务最多关联20个课程'); message.warning('无法继续选择,一个任务最多关联20个课程')
return; return
} }
this.setState({selectPicture:_list}); this.setState({ selectPicture: _list })
} }
clearSelectCourse = ()=>{ clearSelectCourse = () => {
this.setState({ this.setState({
selectLive:[], selectLive: [],
selectVideo:[], selectVideo: {
selectPicture:[] internal: [],
external: []
},
selectPicture: []
}) })
} }
handleSelectVideo = (selectVideo)=>{ handleSelectVideo = (selectVideo) => {
return selectVideo.map((item,index)=>{ return selectVideo.map((item) => {
let _item = {}; let _item = {}
_item.courseId = item.id; _item.courseId = item.id
_item.courseType = "VOICE"; _item.courseType = 'VOICE'
_item.courseName = item.courseName; _item.courseName = item.courseName
return _item; return _item
}) })
} }
handleSelectLive = (selectLive)=>{
return selectLive.map((item,index)=>{ handleSelectLive = (selectLive) => {
let _item = {}; return selectLive.map((item, index) => {
_item.courseId = item.liveCourseId; let _item = {}
_item.courseType = "LIVE"; _item.courseId = item.liveCourseId
_item.courseName = item.courseName; _item.courseType = 'LIVE'
_item.courseState = item.courseState; _item.courseName = item.courseName
return _item; _item.courseState = item.courseState
return _item
}) })
} }
videoCourseDivisionChange = (e) => {
const { videoSearchName } = this.state
this.setState(
{
videoCourseDivision: e.target.value,
videoSearchDefalt: videoSearchName[e.target.value]
},
() => {
this.handleFetchVideoDataList()
}
)
}
handleSelectPicture = (selectPicture)=>{ handleSelectPicture = (selectPicture) => {
return selectPicture.map((item, index) => {
return selectPicture.map((item,index)=>{ let _item = {}
let _item = {}; _item.courseId = item.id
_item.courseId = item.id; _item.courseType = 'PICTURE'
_item.courseType = "PICTURE"; _item.courseName = item.courseName
_item.courseName = item.courseName; return _item
return _item;
}) })
} }
renderFooter = ()=>{ renderFooter = () => {
const { activeKey } = this.state; const { activeKey } = this.state
let href = ''; let href = ''
switch (activeKey){ switch (activeKey) {
case 'live': case 'live':
href = <a target='_blank' className="link-create-course" href={window.location.origin + window.location.pathname + '#/create-live-course?type=add'} onClick={this.props.onClose}>没有找到需要的直播课?<span>去创建</span></a> href = (
break; <a
target='_blank'
rel='noopener noreferrer'
className='link-create-course'
href={window.location.origin + window.location.pathname + '#/create-live-course?type=add'}
onClick={this.props.onClose}>
没有找到需要的直播课?<span>去创建</span>
</a>
)
break
case 'video': case 'video':
href = <a target='_blank' className="link-create-course" href={window.location.origin + window.location.pathname + '#/create-video-course?type=add'} onClick={this.props.onClose}>没有找到需要的视频课?<span>去创建</span></a> href = (
break; <a
target='_blank'
rel='noopener noreferrer'
className='link-create-course'
href={window.location.origin + window.location.pathname + '#/create-video-course?type=add'}
onClick={this.props.onClose}>
没有找到需要的视频课?<span>去创建</span>
</a>
)
break
case 'picture': case 'picture':
href = <a target='_blank' className="link-create-course" href={window.location.origin + window.location.pathname + '#/create-graphics-course?type=add'} onClick={this.props.onClose}>没有找到需要的图文课?<span>去创建</span></a> href = (
break; <a
target='_blank'
rel='noopener noreferrer'
className='link-create-course'
href={window.location.origin + window.location.pathname + '#/create-graphics-course?type=add'}
onClick={this.props.onClose}>
没有找到需要的图文课?<span>去创建</span>
</a>
)
break
default:
break
} }
return href; return href
} }
render() { render() {
const { visible } = this.props; const { visible } = this.props
const { const {
liveDataSource, liveDataSource,
liveSize, liveSize,
...@@ -509,130 +638,192 @@ class SelectOperatorModal extends React.Component { ...@@ -509,130 +638,192 @@ class SelectOperatorModal extends React.Component {
videoDataSource, videoDataSource,
videoSize, videoSize,
videoQuery, videoQuery,
videoSearchDefalt,
videoTotalCount, videoTotalCount,
selectVideo, selectVideo,
currentTaskCourseData, currentTaskCourseData,
activeKey,
selectPicture, selectPicture,
pictureDataSource, pictureDataSource,
pictureSize, pictureSize,
pictureQuery, pictureQuery,
pictureTotalCount, pictureTotalCount,
} = this.state;
videoCourseDivision
} = this.state
return ( return (
<Modal <Modal
title="关联课程" title='关联课程'
onCancel={this.props.onClose} onCancel={this.props.onClose}
maskClosable={false} maskClosable={false}
visible={visible} visible={visible}
className="related-course-modal" className='related-course-modal'
closable={true} closable={true}
width={800} width={800}
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>} closeIcon={<span className='icon iconfont modal-close-icon'>&#xe6ef;</span>}
footer={[ footer={[
this.renderFooter() // <If condition={videoCourseDivision === 'internal'}>{}</If>,
, this.renderFooter(),
<Button <Button
onClick={() => { onClick={() => {
this.props.onClose() this.props.onClose()
}} }}>
>
取消 取消
</Button>, </Button>,
<Button type="primary" onClick={() => this.props.onSelect([...this.handleSelectVideo(selectVideo),...this.handleSelectLive(selectLive),...this.handleSelectPicture(selectPicture)]) }> <Button
type='primary'
onClick={() =>
this.props.onSelect([
...this.handleSelectVideo(selectVideo.internal),
...this.handleSelectVideo(selectVideo.external),
...this.handleSelectLive(selectLive),
...this.handleSelectPicture(selectPicture)
])
}>
确定 确定
</Button> </Button>
]} ]}>
>
<div> <div>
<Tabs defaultActiveKey="video" onChange={(activeKey)=>{this.setState({activeKey:activeKey})}}> <Tabs
<TabPane tab="视频课" key="video"> type='line'
<div className="search-container"> defaultActiveKey='video'
<Search enterButton={<span className="icon iconfont">&#xe832;</span>} placeholder="搜索课程名称" style={{ width: 200 }} onChange={(e) => { this.handleChangVideoCourseName(e.target.value)}} onSearch={ () => { this.handleFetchVideoDataList()}}/> onChange={(activeKey) => {
this.setState({ activeKey: activeKey })
}}>
<TabPane tab='视频课' key='video'>
<Radio.Group value={videoCourseDivision} onChange={this.videoCourseDivisionChange} style={{ marginBottom: 8 }}>
<Radio.Button value='internal'>内部课程</Radio.Button>
<Radio.Button value='external'>外部课程</Radio.Button>
</Radio.Group>
<div className='search-container'>
<Search
value={videoSearchDefalt}
enterButton={<span className='icon iconfont'>&#xe832;</span>}
placeholder='搜索课程名称'
style={{ width: 200 }}
onChange={(e) => {
this.handleChangVideoCourseName(e.target.value)
}}
onSearch={() => {
this.handleFetchVideoDataList()
}}
/>
</div> </div>
<div className="select-area"> <div className='select-area'>
<div className="select-box"> <div className='select-box'>
<div> <div>
<span className="icon iconfont tip-icon">&#xe61d;</span> <span className='icon iconfont tip-icon'>&#xe61d;</span>
<span className="select-num">已选择{selectVideo.length + selectLive.length + selectPicture.length }</span> <span className='select-num'>
已选择{selectVideo.internal.length + selectVideo.external.length + selectLive.length + selectPicture.length}
</span>
</div> </div>
<div> <div>
<span className="clear-btn" onClick={this.clearSelectCourse}>清空</span> <span className='clear-btn' onClick={this.clearSelectCourse}>
清空
</span>
</div>
</div> </div>
<div className='related-box'>
该任务已关联{currentTaskCourseData.length}个课程,可继续选择{20 - currentTaskCourseData.length}
</div> </div>
<div className="related-box">该任务已关联{currentTaskCourseData.length}个课程,可继续选择{20- currentTaskCourseData.length }</div>
</div> </div>
<div> <div>
<Table <Table
rowKey={record => record.id} rowKey={(record) => record.id}
dataSource={videoDataSource} dataSource={videoDataSource[videoCourseDivision]}
columns={this.parseVideoColumns()} columns={this.parseVideoColumns()}
pagination={false} pagination={false}
bordered bordered
rowSelection={{ rowSelection={{
type: 'checkbox', type: 'checkbox',
selectedRowKeys: _.pluck(selectVideo, 'id'), selectedRowKeys: _.pluck(selectVideo[videoCourseDivision], 'id'),
onSelect: (record, selected) => { onSelect: (record, selected) => {
this.selectVideoList(record, selected); this.selectVideoList(record, selected)
}, },
onSelectAll: (selected, _selectedRows, changeRows) => { onSelectAll: (selected, _selectedRows, changeRows) => {
let _list = []; let _list = []
if (selected) { if (selected) {
_list = _.uniq(selectVideo.concat(changeRows), false, (item) => item.id); _list = _.uniq(selectVideo[videoCourseDivision].concat(changeRows), false, (item) => item.id)
} else { } else {
_list = _.reject(selectVideo, (item) => _.find(changeRows, (data) => data.id === item.id)); _list = _.reject(selectVideo[videoCourseDivision], (item) => _.find(changeRows, (data) => data.id === item.id))
} }
if(_list.length + currentTaskCourseData.length + selectLive.length + selectPicture.length> 20){ if (_list.length + currentTaskCourseData.length + selectLive.length + selectPicture.length > 20) {
message.warning('无法继续选择,一个任务最多关联20个课程'); message.warning('无法继续选择,一个任务最多关联20个课程')
const extraLength = (_list.length + currentTaskCourseData.length + selectLive.length + selectPicture.length) -20; const extraLength = _list.length + currentTaskCourseData.length + selectLive.length + selectPicture.length - 20
_list.splice(_list.length - extraLength,extraLength); _list.splice(_list.length - extraLength, extraLength)
}
this.setState({
selectVideo: {
...selectVideo,
[videoCourseDivision]: _list
}
})
} }
this.setState({selectVideo:_list});
},
}} }}
/> />
{videoDataSource.length >0 && {videoDataSource[videoCourseDivision].length > 0 && (
<div className="box-footer"> <div className='box-footer'>
<PageControl <PageControl
current={videoQuery.current - 1} current={videoQuery[videoCourseDivision].current - 1}
pageSize={videoSize} pageSize={videoSize[videoCourseDivision]}
size="small" size='small'
total={videoTotalCount} total={videoTotalCount[videoCourseDivision]}
toPage={(page) => { toPage={(page) => {
const _query = {...videoQuery, current: page + 1}; const _query = { ...videoQuery[videoCourseDivision], current: page + 1 }
this.setState({
videoQuery:_query this.setState(
},()=>{ this.handleFetchVideoDataList()}) {
videoQuery: {
...videoQuery,
[videoCourseDivision]: _query
}
},
() => {
this.handleFetchVideoDataList()
}
)
}} }}
onShowSizeChange={this.onShowVideoSizeChange} onShowSizeChange={this.onShowVideoSizeChange}
/> />
</div> </div>
} )}
</div> </div>
</TabPane> </TabPane>
<TabPane tab="直播课" key="live"> <TabPane tab='直播课' key='live'>
<div className="search-container"> <div className='search-container'>
<Search enterButton={<span className="icon iconfont">&#xe832;</span>} placeholder="搜索课程名称" style={{ width: 200 }} onChange={(e) => { this.handleChangLiveCourseName(e.target.value)}} onSearch={ () => { this.handleFetchLiveDataList()}} /> <Search
enterButton={<span className='icon iconfont'>&#xe832;</span>}
placeholder='搜索课程名称'
style={{ width: 200 }}
onChange={(e) => {
this.handleChangLiveCourseName(e.target.value)
}}
onSearch={() => {
this.handleFetchLiveDataList()
}}
/>
</div> </div>
<div className="select-area"> <div className='select-area'>
<div className="select-box"> <div className='select-box'>
<div> <div>
<span className="icon iconfont tip-icon">&#xe61d;</span> <span className='icon iconfont tip-icon'>&#xe61d;</span>
<span className="select-num">已选择{selectVideo.length + selectLive.length + selectPicture.length}</span> <span className='select-num'>
已选择{selectVideo.internal.length + selectVideo.external.length + selectLive.length + selectPicture.length}
</span>
</div> </div>
<div> <div>
<span className="clear-btn" onClick={this.clearSelectCourse}>清空</span> <span className='clear-btn' onClick={this.clearSelectCourse}>
清空
</span>
</div> </div>
</div> </div>
<div className="related-box">该任务已关联{currentTaskCourseData.length}个课程,可继续选择{20- currentTaskCourseData.length }</div> <div className='related-box'>
该任务已关联{currentTaskCourseData.length}个课程,可继续选择{20 - currentTaskCourseData.length}
</div>
</div> </div>
<div> <div>
<Table <Table
rowKey={record => record.liveCourseId} rowKey={(record) => record.liveCourseId}
dataSource={liveDataSource} dataSource={liveDataSource}
columns={this.parseLiveColumns()} columns={this.parseLiveColumns()}
pagination={false} pagination={false}
...@@ -644,61 +835,81 @@ class SelectOperatorModal extends React.Component { ...@@ -644,61 +835,81 @@ class SelectOperatorModal extends React.Component {
this.selectLiveList(record, selected) this.selectLiveList(record, selected)
}, },
onSelectAll: (selected, _selectedRows, changeRows) => { onSelectAll: (selected, _selectedRows, changeRows) => {
let _list = []; let _list = []
if (selected) { if (selected) {
_list = _.uniq(selectLive.concat(changeRows), false, (item) => item.liveCourseId); _list = _.uniq(selectLive.concat(changeRows), false, (item) => item.liveCourseId)
} else { } else {
_list = _.reject(selectLive, (item) => _.find(changeRows, (data) => data.liveCourseId === item.liveCourseId)); _list = _.reject(selectLive, (item) => _.find(changeRows, (data) => data.liveCourseId === item.liveCourseId))
} }
if(_list.length + currentTaskCourseData.length + selectVideo.length + selectPicture.length> 20){ if (_list.length + currentTaskCourseData.length + selectVideo.length + selectPicture.length > 20) {
message.warning('无法继续选择,一个任务最多关联20个课程'); message.warning('无法继续选择,一个任务最多关联20个课程')
const extraLength = (_list.length + currentTaskCourseData.length + selectVideo.length + selectPicture.length) -20; const extraLength = _list.length + currentTaskCourseData.length + selectVideo.length + selectPicture.length - 20
_list.splice(_list.length - extraLength,extraLength); _list.splice(_list.length - extraLength, extraLength)
}
this.setState({ selectLive: _list })
} }
this.setState({selectLive:_list});
},
}} }}
/> />
{liveDataSource.length >0 && {liveDataSource.length > 0 && (
<div className="box-footer"> <div className='box-footer'>
<PageControl <PageControl
current={liveQuery.current - 1} current={liveQuery.current - 1}
pageSize={liveSize} pageSize={liveSize}
size="small" size='small'
total={liveTotalCount} total={liveTotalCount}
toPage={(page) => { toPage={(page) => {
const _query = {...liveQuery, current: page + 1}; const _query = { ...liveQuery, current: page + 1 }
this.setState({ this.setState(
liveQuery:_query {
},()=>{ this.handleFetchLiveDataList()}) liveQuery: _query
},
() => {
this.handleFetchLiveDataList()
}
)
}} }}
onShowSizeChange={this.onShowLiveSizeChange} onShowSizeChange={this.onShowLiveSizeChange}
/> />
</div> </div>
} )}
</div> </div>
</TabPane> </TabPane>
<TabPane tab="图文课" key="picture"> <TabPane tab='图文课' key='picture'>
<div className="search-container"> <div className='search-container'>
<Search enterButton={<span className="icon iconfont">&#xe832;</span>} placeholder="搜索课程名称" style={{ width: 200 }} onChange={(e) => { this.handleChangPictureCourseName(e.target.value)}} onSearch={ () => { this.handleFetchPictureDataList()}} /> <Search
enterButton={<span className='icon iconfont'>&#xe832;</span>}
placeholder='搜索课程名称'
style={{ width: 200 }}
onChange={(e) => {
this.handleChangPictureCourseName(e.target.value)
}}
onSearch={() => {
this.handleFetchPictureDataList()
}}
/>
</div> </div>
<div className="select-area"> <div className='select-area'>
<div className="select-box"> <div className='select-box'>
<div> <div>
<span className="icon iconfont tip-icon">&#xe61d;</span> <span className='icon iconfont tip-icon'>&#xe61d;</span>
<span className="select-num">已选择{selectVideo.length + selectLive.length + selectPicture.length }</span> <span className='select-num'>
已选择{selectVideo.internal.length + selectVideo.external.length + selectLive.length + selectPicture.length}
</span>
</div> </div>
<div> <div>
<span className="clear-btn" onClick={this.clearSelectCourse}>清空</span> <span className='clear-btn' onClick={this.clearSelectCourse}>
清空
</span>
</div>
</div> </div>
<div className='related-box'>
该任务已关联{currentTaskCourseData.length}个课程,可继续选择{20 - currentTaskCourseData.length}
</div> </div>
<div className="related-box">该任务已关联{currentTaskCourseData.length}个课程,可继续选择{20- currentTaskCourseData.length }</div>
</div> </div>
<div> <div>
<Table <Table
rowKey={record => record.id} rowKey={(record) => record.id}
dataSource={pictureDataSource} dataSource={pictureDataSource}
columns={this.parsePictureColumns()} columns={this.parsePictureColumns()}
pagination={false} pagination={false}
...@@ -710,39 +921,43 @@ class SelectOperatorModal extends React.Component { ...@@ -710,39 +921,43 @@ class SelectOperatorModal extends React.Component {
this.selectPictureList(record, selected) this.selectPictureList(record, selected)
}, },
onSelectAll: (selected, _selectedRows, changeRows) => { onSelectAll: (selected, _selectedRows, changeRows) => {
let _list = []; let _list = []
if (selected) { if (selected) {
_list = _.uniq(selectPicture.concat(changeRows), false, (item) => item.id); _list = _.uniq(selectPicture.concat(changeRows), false, (item) => item.id)
} else { } else {
_list = _.reject(selectPicture, (item) => _.find(changeRows, (data) => data.id === item.id)); _list = _.reject(selectPicture, (item) => _.find(changeRows, (data) => data.id === item.id))
} }
if(_list.length + currentTaskCourseData.length + selectVideo.length + selectLive.length> 20){ if (_list.length + currentTaskCourseData.length + selectVideo.length + selectLive.length > 20) {
message.warning('无法继续选择,一个任务最多关联20个课程'); message.warning('无法继续选择,一个任务最多关联20个课程')
const extraLength = (_list.length + currentTaskCourseData.length + selectVideo.length + selectLive.length) -20; const extraLength = _list.length + currentTaskCourseData.length + selectVideo.length + selectLive.length - 20
_list.splice(_list.length - extraLength,extraLength); _list.splice(_list.length - extraLength, extraLength)
}
this.setState({ selectPicture: _list })
} }
this.setState({selectPicture:_list});
},
}} }}
/> />
{pictureDataSource.length >0 && {pictureDataSource.length > 0 && (
<div className="box-footer"> <div className='box-footer'>
<PageControl <PageControl
current={pictureQuery.current - 1} current={pictureQuery.current - 1}
pageSize={pictureSize} pageSize={pictureSize}
size="small" size='small'
total={pictureTotalCount} total={pictureTotalCount}
toPage={(page) => { toPage={(page) => {
const _query = {...pictureQuery, current: page + 1}; const _query = { ...pictureQuery, current: page + 1 }
this.setState({ this.setState(
pictureQuery:_query {
},()=>{ this.handleFetchPictureDataList()}) pictureQuery: _query
},
() => {
this.handleFetchPictureDataList()
}
)
}} }}
onShowSizeChange={this.onShowPictureSizeChange} onShowSizeChange={this.onShowPictureSizeChange}
/> />
</div> </div>
} )}
</div> </div>
</TabPane> </TabPane>
</Tabs> </Tabs>
...@@ -752,4 +967,4 @@ class SelectOperatorModal extends React.Component { ...@@ -752,4 +967,4 @@ class SelectOperatorModal extends React.Component {
} }
} }
export default SelectOperatorModal; export default SelectOperatorModal
\ No newline at end of file
.related-course-modal{ .related-course-modal {
.ant-tabs-top > .ant-tabs-nav::before{ .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn {
border-bottom: 0px; font-weight: normal;
} }
.ant-tabs-nav-list{ // .ant-tabs-nav .ant-tabs-tab {
margin:0 auto; // padding: 6px 12px !important;
} // margin: 0;
.ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn{ // border: 1px solid #e8e8e8;
font-weight:normal; // font-size: 14px !important;
} // color: #999;
.ant-tabs-nav .ant-tabs-tab{
padding:6px 12px !important;
margin:0;
border: 1px solid #E8E8E8;
font-size:14px !important;
color:#999;
&:nth-child(1){ // &:nth-child(1) {
border-radius: 4px 0px 0px 4px; // border-radius: 4px 0px 0px 4px;
} // }
&:nth-child(2){ // &:nth-child(2) {
border-radius: 0px 4px 4px 0px; // border-radius: 0px 4px 4px 0px;
} // }
} // }
.ant-tabs-nav .ant-tabs-tab-active{ // .ant-tabs-nav .ant-tabs-tab-active {
border: 1px solid #FFB714; // // border: 1px solid #ffb714;
color:#FFB714; // color: #ffb714;
} // }
.ant-tabs-top .ant-tabs-ink-bar-animated:after{ // .ant-tabs-top .ant-tabs-ink-bar-animated:after {
height:0; // height: 0;
} // }
.link-create-course{ .link-create-course {
color:#666666; color: #666666;
font-size:14px; font-size: 14px;
width:638px; width: 638px;
text-align:left; text-align: left;
display:inline-block; display: inline-block;
span{ span {
color:#5289FA; color: #5289fa;
} }
} }
.search-container{ .search-container {
margin-bottom:16px; margin-bottom: 16px;
} }
.select-area{ .select-area {
margin-bottom:12px; margin-bottom: 12px;
display:flex; display: flex;
justify-content:space-between; justify-content: space-between;
.select-box{ .select-box {
display:inline-box; display: inline-box;
width: 186px; width: 186px;
background: #FFF4DD; background: #fff4dd;
border-radius: 4px; border-radius: 4px;
padding:6px 16px; padding: 6px 16px;
margin-right:8px; margin-right: 8px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.tip-icon{ .tip-icon {
color:#FF9D14; color: #ff9d14;
font-size:14px; font-size: 14px;
margin-right:4px; margin-right: 4px;
} }
.select-num{ .select-num {
color:#666666; color: #666666;
font-size:14px; font-size: 14px;
} }
.clear-btn{ .clear-btn {
text-align:right; text-align: right;
color:#5289FA; color: #5289fa;
font-size:14px; font-size: 14px;
} }
} }
.related-box{ .related-box {
padding:6px 16px; padding: 6px 16px;
background: #FFF4DD; background: #fff4dd;
border-radius: 4px; border-radius: 4px;
flex:1; flex: 1;
color:#666666; color: #666666;
font-size:14px; font-size: 14px;
} }
} }
.course-info{ .course-info {
display: flex; display: flex;
align-items: center; align-items: center;
.course-cover{ .course-cover {
width: 97px; width: 97px;
height: 55px; height: 55px;
display: inline-block; display: inline-block;
border-radius:4px; border-radius: 4px;
margin-right:8px; margin-right: 8px;
} }
.course-name{ .course-name {
font-size:14px; font-size: 14px;
color:#666; color: #666;
text-overflow: -o-ellipsis-lastline; text-overflow: -o-ellipsis-lastline;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
...@@ -101,15 +95,15 @@ ...@@ -101,15 +95,15 @@
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
line-clamp: 2; line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
width:238px; width: 180px;
} }
.course-status { .course-status {
font-size:12px; font-size: 12px;
line-height:18px; line-height: 18px;
display:inline-block; display: inline-block;
border-radius:2px; border-radius: 2px;
padding:0 8px; padding: 0 8px;
margin-top:8px; margin-top: 8px;
} }
} }
} }
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react'
import { import { withRouter } from 'react-router-dom'
withRouter import './Login.less'
} from 'react-router-dom'; import { Input, Popover, message, Tabs, Button } from 'antd'
import './Login.less'; import CheckBeforeSendCode from '../../components/CheckBeforeSendCode'
import { Input, Popover, message, Tabs, Button } from 'antd'; import User from '@/common/js/user'
import CheckBeforeSendCode from '../../components/CheckBeforeSendCode';
import User from '@/common/js/user';
import WechatLogin from './WechatLogin' import WechatLogin from './WechatLogin'
import BaseService from "@/domains/basic-domain/baseService"; import BaseService from '@/domains/basic-domain/baseService'
import axios from 'axios'; import axios from 'axios'
import _ from 'underscore'; import _ from 'underscore'
import user from '@/common/js/user'; import user from '@/common/js/user'
const { TabPane } = Tabs; const { TabPane } = Tabs
function Login(props) { function Login(props) {
const [phone, setPhone] = useState(''); // 登录手机号 const [phone, setPhone] = useState('') // 登录手机号
const [phoneverify, setPhoneverify] = useState(''); // 密码登录验证码 const [phoneverify, setPhoneverify] = useState('') // 密码登录验证码
const [openCheck1, setOpenCheck1] = useState(false); const [openCheck1, setOpenCheck1] = useState(false)
const [checking1, setChecking1] = useState(false); const [checking1, setChecking1] = useState(false)
const [codeText, setCodeText] = useState('获取验证码'); // 验证码提示语 const [codeText, setCodeText] = useState('获取验证码') // 验证码提示语
const [waitStatus, setWaitStatus] = useState(false); // 验证码是否在倒计时 const [waitStatus, setWaitStatus] = useState(false) // 验证码是否在倒计时
const [errorMessage, setErrorMessage] = useState(''); const [errorMessage, setErrorMessage] = useState('')
const [phoneError, setPhoneError] = useState(false); const [phoneError, setPhoneError] = useState(false)
const [checkObject1, setCheckObject1] = useState({}); const [checkObject1, setCheckObject1] = useState({})
useEffect(() => { useEffect(() => {
const enterpriseId = getParameterByName("enterpriseId"); const enterpriseId = getParameterByName('enterpriseId')
const userId = getParameterByName("userId"); const userId = getParameterByName('userId')
const from = getParameterByName("from"); const from = getParameterByName('from')
const storeId = getParameterByName("storeId"); const storeId = getParameterByName('storeId')
if (storeId) { if (storeId) {
User.setCustomerStoreId(storeId); User.setCustomerStoreId(storeId)
} }
if (from === 'customer' && enterpriseId && userId) { if (from === 'customer' && enterpriseId && userId) {
if (!user.getToken() || enterpriseId !== user.getEnterpriseId() || userId !== User.getUserId()) { if (!user.getToken() || enterpriseId !== user.getEnterpriseId() || userId !== User.getUserId()) {
getWXWorkLoginNoCheck(enterpriseId, userId); getWXWorkLoginNoCheck(enterpriseId, userId)
} else { } else {
window.RCHistory.push({ window.RCHistory.push({
pathname: `/switch-route`, pathname: `/switch-route`
}) })
} }
} else { } else {
User.removeUserId(); User.removeUserId()
User.removeToken(); User.removeToken()
User.removeEnterpriseId(); User.removeEnterpriseId()
} }
}, []) }, [])
function getWXWorkLoginNoCheck(enterpriseId, userId) { function getWXWorkLoginNoCheck(enterpriseId, userId) {
const params = { const params = {
appTermEnum: "XIAOMAI_CLOUD_CLASS_PC_WEB_ADMIN", appTermEnum: 'XIAOMAI_CLOUD_CLASS_PC_WEB_ADMIN',
enterpriseId, enterpriseId,
userId userId
} }
BaseService.getWXWorkLoginNoCheck(params).then((res) => { BaseService.getWXWorkLoginNoCheck(params).then((res) => {
User.setUserId(res.result.loginInfo.userId); User.setUserId(res.result.loginInfo.userId)
User.setToken(res.result.loginInfo.xmToken); User.setToken(res.result.loginInfo.xmToken)
User.setEnterpriseId(res.result.enterpriseId); User.setEnterpriseId(res.result.enterpriseId)
window.RCHistory.push({ window.RCHistory.push({
pathname: `/switch-route`, pathname: `/switch-route`
}) })
}) })
} }
async function checkAccount(code, callback = () => { }) { async function checkAccount(code, callback = () => {}) {
callback(); callback()
} }
function checkSend(code) { function checkSend(code) {
if (!phone) { if (!phone) {
setPhoneError(true); setPhoneError(true)
setErrorMessage("请输入手机号"); setErrorMessage('请输入手机号')
return; return
} }
if (phone.length != 11) { if (phone.length != 11) {
setPhoneError(true); setPhoneError(true)
setErrorMessage("请输入11位手机号") setErrorMessage('请输入11位手机号')
return; return
} }
!_.isEmpty(checkObject1) && checkObject1.reset(); !_.isEmpty(checkObject1) && checkObject1.reset()
setOpenCheck1(true); setOpenCheck1(true)
} }
function handleSendSMSCode(checkData, userType) { function handleSendSMSCode(checkData, userType) {
if (waitStatus) return; if (waitStatus) return
let timer; let timer
const params = { const params = {
phone: phone, phone: phone,
sig: checkData.sig, sig: checkData.sig,
sessionId: checkData.csessionid, sessionId: checkData.csessionid,
token: checkData.token, token: checkData.token,
scene: 'nc_login', scene: 'nc_login',
serverType: "CLOUD_CLASS_LOGIN", serverType: 'CLOUD_CLASS_LOGIN',
appTermEnum: 'XIAOMAI_CLOUD_CLASS_PC_WEB_ADMIN' appTermEnum: 'XIAOMAI_CLOUD_CLASS_PC_WEB_ADMIN'
} }
BaseService.sendLoginAuthCode(params).then((res) => { BaseService.sendLoginAuthCode(params).then((res) => {
if (!res.success) { if (!res.success) {
setErrorMessage(res.message); setErrorMessage(res.message)
} else { } else {
timeSub(60); timeSub(60)
setChecking1(true) setChecking1(true)
} }
}) })
function timeSub(waitTime, unit) { function timeSub(waitTime, unit) {
clearTimeout(timer); clearTimeout(timer)
timer = setTimeout(function () { timer = setTimeout(function () {
if (waitTime === 0) { if (waitTime === 0) {
setCodeText('发送验证码') setCodeText('发送验证码')
setChecking1(false) setChecking1(false)
setWaitStatus(false) setWaitStatus(false)
clearTimeout(timer); clearTimeout(timer)
} else { } else {
setCodeText(`${waitTime}秒后重发`) setCodeText(`${waitTime}秒后重发`)
setWaitStatus(true) setWaitStatus(true)
timeSub(--waitTime, 1000); timeSub(--waitTime, 1000)
} }
}, unit || 0); }, unit || 0)
} }
} }
function handleSubmit() { function handleSubmit() {
if (!phone) { if (!phone) {
setPhoneError(true); setPhoneError(true)
setErrorMessage("请输入手机号"); setErrorMessage('请输入手机号')
return; return
} }
if (phone.length != 11) { if (phone.length != 11) {
setPhoneError(true); setPhoneError(true)
setErrorMessage("请输入11位手机号") setErrorMessage('请输入11位手机号')
return; return
} }
if (!phoneverify) { if (!phoneverify) {
setErrorMessage("请输入验证码"); setErrorMessage('请输入验证码')
return; return
} }
const params = { const params = {
phone, phone,
authCode: phoneverify, authCode: phoneverify,
appTermEnum: "XIAOMAI_CLOUD_CLASS_PC_WEB_ADMIN" appTermEnum: 'XIAOMAI_CLOUD_CLASS_PC_WEB_ADMIN'
} }
BaseService.login(params).then((res) => { BaseService.login(params).then((res) => {
if (!res.success) { if (!res.success) {
setErrorMessage(res.message); setErrorMessage(res.message)
} else { } else {
User.setUserId(res.result.userId); User.setUserId(res.result.userId)
User.setToken(res.result.xmToken); User.setToken(res.result.xmToken)
window.RCHistory.push({ window.RCHistory.push({
pathname: `/switch-route`, pathname: `/switch-route`
}) })
} }
}) })
} }
return ( return (
<div className="login-page" > <div className='login-page'>
<div className="login-main"> <div className='login-main'>
<div className="left-banner"> <div className='left-banner'>
<div><img src="https://image.xiaomaiketang.com/xm/Newk4NrxKC.png" alt="" style={{ width: 60, height: 61 }} /></div> <div>
<div className="name">小麦企学院</div> <img src='https://image.xiaomaiketang.com/xm/Newk4NrxKC.png' alt='' style={{ width: 60, height: 61 }} />
<div className="desc">一键开启直播授课 让知识更有价值</div>
</div> </div>
<div className="login-box"> <div className='name'>小麦企学院</div>
<div className="login"> <div className='desc'>一键开启直播授课 让知识更有价值</div>
<div className="r"> </div>
<Tabs defaultActiveKey="1"> <div className='login-box'>
<TabPane tab="企业微信登录" key="1"> <div className='login'>
<div className='r'>
<Tabs defaultActiveKey='1'>
<TabPane tab='企业微信登录' key='1'>
<WechatLogin></WechatLogin> <WechatLogin></WechatLogin>
</TabPane> </TabPane>
<TabPane tab="手机号登录" key="2"> <TabPane tab='手机号登录' key='2'>
<div className="login-form"> <div className='login-form'>
<div className="form"> <div className='form'>
<div className="username" style={{ marginBottom: 16 }}> <div className='username' style={{ marginBottom: 16 }}>
<Input <Input
type="phone" type='phone'
autoComplete="off" autoComplete='off'
name="account" name='account'
maxLength={11} maxLength={11}
placeholder="手机号" placeholder='手机号'
value={phone} value={phone}
onChange={(e) => { setPhone(e.target.value) }} onChange={(e) => {
setPhone(e.target.value)
}}
/> />
</div> </div>
<div className="error-message"> <div className='error-message'></div>
<div className='phoneverify'>
</div>
<div className="phoneverify">
<Input <Input
type="text" type='text'
id="phoneverify" id='phoneverify'
name="phoneverify" name='phoneverify'
placeholder="验证码" placeholder='验证码'
autoComplete="off" autoComplete='off'
value={phoneverify} value={phoneverify}
maxLength={4} maxLength={4}
onChange={(e) => { setPhoneverify(e.target.value) }} onChange={(e) => {
setPhoneverify(e.target.value)
}}
/> />
<Popover <Popover
visible={openCheck1} visible={openCheck1}
trigger="click" trigger='click'
title="" title=''
content={<div> content={
<div>
<span style={{ fontSize: '12px', color: '#999', marginBottom: 8, display: 'block' }}>请完成安全验证</span> <span style={{ fontSize: '12px', color: '#999', marginBottom: 8, display: 'block' }}>请完成安全验证</span>
<CheckBeforeSendCode <CheckBeforeSendCode
callback={(data, nc) => { callback={(data, nc) => {
setCheckObject1(nc); setCheckObject1(nc)
checkAccount(1, (userType) => { checkAccount(1, (userType) => {
handleSendSMSCode(data, userType); handleSendSMSCode(data, userType)
setTimeout(() => { setTimeout(() => {
setOpenCheck1(false); setOpenCheck1(false)
}, 500) }, 500)
}) })
}} }}
/> />
</div>} </div>
}
onVisibleChange={(value) => { onVisibleChange={(value) => {
if (!value) { if (!value) {
setOpenCheck1(false); setOpenCheck1(false)
} }
}} }}
placement="bottomRight" placement='bottomRight'>
>
<div <div
className="btn" className='btn'
id="sendVerifyCode" id='sendVerifyCode'
onClick={() => { onClick={() => {
if (checking1) return; if (checking1) return
checkSend(1) checkSend(1)
}} }}>
>{codeText}</div> {codeText}
</Popover>
</div> </div>
<div className="error-message"> </Popover>
{errorMessage}
</div> </div>
<div className="submit"> <div className='error-message'>{errorMessage}</div>
<div className="btn"> <div className='submit'>
<span id='loginIn' onClick={() => { handleSubmit() }} >登录</span> <div className='btn'>
<span
id='loginIn'
onClick={() => {
handleSubmit()
}}>
登录
</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</TabPane> </TabPane>
</Tabs> </Tabs>
</div> </div>
</div> </div>
...@@ -249,4 +254,4 @@ function Login(props) { ...@@ -249,4 +254,4 @@ function Login(props) {
) )
} }
export default withRouter(Login); export default withRouter(Login)
...@@ -15,10 +15,11 @@ ...@@ -15,10 +15,11 @@
background-color: #f0f2f5; background-color: #f0f2f5;
overflow-x: scroll; overflow-x: scroll;
z-index: 1; z-index: 1;
&.right-container-vertical{ height: calc(~'100% - 50px');
left:@xm-left-min-width; &.right-container-vertical {
.page{ left: @xm-left-min-width;
.page{ .page {
.page {
left: @xm-left-min-width; left: @xm-left-min-width;
} }
} }
...@@ -41,7 +42,6 @@ ...@@ -41,7 +42,6 @@
} }
} }
.right-container { .right-container {
// min-width: 1186px; // min-width: 1186px;
&:before { &:before {
...@@ -111,7 +111,7 @@ ...@@ -111,7 +111,7 @@
} }
&.multiple { &.multiple {
h1{ h1 {
&.on { &.on {
border-left: 1px solid @border; border-left: 1px solid @border;
} }
......
.wechatLoginBox {
.wechatLoginBox{
height: 320px; height: 320px;
text-align: center; text-align: center;
.text{ .text {
margin-top: 12px; margin-top: 12px;
font-size: 14px; font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC; font-family: PingFangSC-Regular, PingFang SC;
color: #999999; color: #999999;
line-height: 20px; line-height: 20px;
} }
.rwm {
position: relative;
width: 160px;
height: 160px;
text-align: center;
display: inline-block;
margin-top: 24px;
.error {
position: absolute;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.95);
display: flex;
align-items: center;
justify-content: center;
left: 0px;
top: 0px;
div {
margin: 0 10px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 20px;
}
.ope {
cursor: pointer;
color: rgba(82, 137, 250, 1);
}
}
<<<<<<< HEAD
.rwm{ .rwm{
position: relative; position: relative;
width: 160px; width: 160px;
...@@ -42,33 +72,35 @@ ...@@ -42,33 +72,35 @@
} }
} }
} }
=======
}
>>>>>>> 4ed93ca (feat:新增视频课外部视频模块相关功能,准备开始冒烟测试)
.ant-tabs-tab-active{ .ant-tabs-tab-active {
.ant-tabs-tab-btn{ .ant-tabs-tab-btn {
color: #333333; color: #333333;
} }
} }
.ant-tabs-tab-btn{ .ant-tabs-tab-btn {
color: #999999; color: #999999;
font-size: 16px; font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC; font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500; font-weight: 500;
line-height: 25px; line-height: 25px;
} }
.ant-tabs-nav::before{ .ant-tabs-nav::before {
display: none; display: none;
} }
.ant-tabs-tab{ .ant-tabs-tab {
width: 105px; width: 105px;
text-align: center; text-align: center;
} }
.ant-tabs > .ant-tabs-nav .ant-tabs-nav-list{ .ant-tabs > .ant-tabs-nav .ant-tabs-nav-list {
margin: 0 auto; margin: 0 auto;
} }
.ant-tabs-top > .ant-tabs-nav .ant-tabs-ink-bar{ .ant-tabs-top > .ant-tabs-nav .ant-tabs-ink-bar {
width: 24px !important; width: 24px !important;
height: 4px; height: 4px;
margin-left: 30px; margin-left: 30px;
......
/* /*
* @Author: yuananting * @Author: yuananting
* @Date: 2021-02-23 18:28:50 * @Date: 2021-02-23 18:28:50
* @LastEditors: yuananting * @LastEditors: fusanqiasng
* @LastEditTime: 2021-04-15 21:53:13 * @LastEditTime: 2021-05-21 17:57:59
* @Description: 助学工具-课程分类 * @Description: 助学工具-课程分类
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import React, { Component } from "react"; import React, { Component } from 'react'
import Breadcrumbs from "@/components/Breadcrumbs"; import Breadcrumbs from '@/components/Breadcrumbs'
import "./CourseCategoryManage.less"; import './CourseCategoryManage.less'
import OpearteCourseCategoryModal from "../modal/OpearteCourseCategoryModal"; import OpearteCourseCategoryModal from '../modal/OpearteCourseCategoryModal'
import AidToolService from "@/domains/aid-tool-domain/AidToolService"; import AidToolService from '@/domains/aid-tool-domain/AidToolService'
import User from "@/common/js/user"; import User from '@/common/js/user'
import { import { Tree, Input, Space, Button, Menu, Dropdown, message, Modal } from 'antd'
Tree, import ShowTips from '@/components/ShowTips'
Input, const { DirectoryTree } = Tree
Space, const { Search } = Input
Button, const { confirm } = Modal
Menu,
Dropdown,
message,
Modal,
} from "antd";
import ShowTips from "@/components/ShowTips";
const { DirectoryTree } = Tree;
const { Search } = Input;
const { confirm } = Modal;
class CourseCategoryManage extends Component { class CourseCategoryManage extends Component {
constructor(props) { constructor(props) {
super(props); super(props)
this.state = { this.state = {
operateCourseCategoryModal: null, //新增或编辑分类模态框 operateCourseCategoryModal: null, //新增或编辑分类模态框
treeData: [], treeData: [],
originTreeData: [], originTreeData: [],
treeMap: {}, treeMap: {},
selectedKeys: ["null"], selectedKeys: ['null'],
autoExpandParent: true, autoExpandParent: true
}; }
} }
componentDidMount() { componentDidMount() {
this.queryCategoryTree("init"); this.queryCategoryTree('init')
} }
getWholeTree = () => { getWholeTree = () => {
let query = { let query = {
bizType: "QUESTION", bizType: 'QUESTION',
count: false, count: false,
source: 0, source: 0,
userId: User.getStoreUserId(), userId: User.getStoreUserId(),
tenantId: User.getStoreId(), tenantId: User.getStoreId()
}; }
AidToolService.queryCategoryTree(query).then((res) => { AidToolService.queryCategoryTree(query).then((res) => {
const { categoryList = [] } = res.result; const { categoryList = [] } = res.result
this.setState({ originTreeData: categoryList }, () => { this.setState({ originTreeData: categoryList }, () => {
let map = {}; let map = {}
let topItem = []; let topItem = []
categoryList.forEach((item) => { categoryList.forEach((item) => {
topItem.push(item); topItem.push(item)
}); })
this.setState({ this.setState({
treeMap: Object.assign(this.getTreeMap(categoryList, map), { treeMap: Object.assign(this.getTreeMap(categoryList, map), {
0: { 0: {
sonCategoryList: topItem, sonCategoryList: topItem
}, }
}), })
}); })
}); })
}); })
}; }
// 查询分类树 // 查询分类树
queryCategoryTree = (operateType, categoryName) => { queryCategoryTree = (operateType, categoryName) => {
this.getWholeTree(); this.getWholeTree()
this.setState({ categoryName }); this.setState({ categoryName })
let query = { let query = {
bizType: "QUESTION", bizType: 'QUESTION',
count: false, count: false,
source: 0, source: 0,
categoryName, categoryName,
userId: User.getStoreUserId(), userId: User.getStoreUserId(),
tenantId: User.getStoreId(), tenantId: User.getStoreId()
}; }
AidToolService.queryCategoryTree(query).then((res) => { AidToolService.queryCategoryTree(query).then((res) => {
const { categoryList = [] } = res.result; const { categoryList = [] } = res.result
let str = "未分类"; let str = '未分类'
if (categoryName) { if (categoryName) {
this.setState({ autoExpandParent: true }); this.setState({ autoExpandParent: true })
if (str.indexOf(categoryName) < 0) { if (str.indexOf(categoryName) < 0) {
this.setState({ this.setState({
treeData: this.renderTreeNodes(categoryList, categoryName), treeData: this.renderTreeNodes(categoryList, categoryName)
}); })
let nodeId = []; let nodeId = []
Object.keys(this.state.treeMap).forEach((item) => { Object.keys(this.state.treeMap).forEach((item) => {
nodeId.push(item); nodeId.push(item)
}); })
this.setState({ expandedKeys: nodeId }); this.setState({ expandedKeys: nodeId })
} else { } else {
const defaultNode = { const defaultNode = {
id: "null", id: 'null',
categoryName: "未分类", categoryName: '未分类',
categoryCount: 0, categoryCount: 0,
parentId: "0", parentId: '0',
categoryLevel: 0, categoryLevel: 0
}; }
categoryList.unshift(defaultNode); categoryList.unshift(defaultNode)
this.setState({ this.setState({
treeData: this.renderTreeNodes(categoryList, categoryName), treeData: this.renderTreeNodes(categoryList, categoryName)
}); })
let nodeId = []; let nodeId = []
Object.keys(this.state.treeMap).forEach((item) => { Object.keys(this.state.treeMap).forEach((item) => {
nodeId.push(item); nodeId.push(item)
}); })
if (operateType === "init") { if (operateType === 'init') {
this.setState({ expandedKeys: nodeId }); this.setState({ expandedKeys: nodeId })
} }
} }
} else { } else {
this.setState({ autoExpandParent: false }); this.setState({ autoExpandParent: false })
const defaultNode = { const defaultNode = {
id: "null", id: 'null',
categoryName: "未分类", categoryName: '未分类',
categoryCount: 0, categoryCount: 0,
parentId: "0", parentId: '0',
categoryLevel: 0, categoryLevel: 0
}; }
categoryList.unshift(defaultNode); categoryList.unshift(defaultNode)
this.setState({ treeData: this.renderTreeNodes(categoryList, categoryName) }); this.setState({ treeData: this.renderTreeNodes(categoryList, categoryName) })
if (operateType === "init") { if (operateType === 'init') {
this.setState({ expandedKeys: [] }); this.setState({ expandedKeys: [] })
} }
} }
}); })
}; }
// 树节点渲染-内容处理 // 树节点渲染-内容处理
renderTreeNodes = (data, value) => { renderTreeNodes = (data, value) => {
let newTreeData = data.map((item) => { let newTreeData = data.map((item) => {
item.title = item.categoryName; item.title = item.categoryName
item.key = item.id; item.key = item.id
item.title = ( item.title = (
<div <div
style={{ style={{
opacity: opacity: !value || (value && item.categoryName.indexOf(value) > -1) ? 1 : 0.5
!value || (value && item.categoryName.indexOf(value) > -1)
? 1
: 0.5,
}} }}
className="node-title-div" className='node-title-div'
onMouseOver={(e) => { onMouseOver={(e) => {
let mouseNodeOpts = e.currentTarget.getElementsByTagName("div")[0]; let mouseNodeOpts = e.currentTarget.getElementsByTagName('div')[0]
if (mouseNodeOpts) { if (mouseNodeOpts) {
mouseNodeOpts.style.visibility = "visible"; mouseNodeOpts.style.visibility = 'visible'
} }
}} }}
onMouseOut={(e) => { onMouseOut={(e) => {
let mouseNodeOpts = e.currentTarget.getElementsByTagName("div")[0]; let mouseNodeOpts = e.currentTarget.getElementsByTagName('div')[0]
if (mouseNodeOpts) { if (mouseNodeOpts) {
mouseNodeOpts.style.visibility = "hidden"; mouseNodeOpts.style.visibility = 'hidden'
} }
}} }}>
>
<span>{item.categoryName}</span> <span>{item.categoryName}</span>
{item.categoryName !== "未分类" && ( {item.categoryName !== '未分类' && (
<Space className="title-opts" size={16}> <Space className='title-opts' size={16}>
<span <span
onClick={() => { onClick={() => {
let nodesCount = 0; let nodesCount = 0
const { originTreeData } = this.state; const { originTreeData } = this.state
console.log("orororo", originTreeData); console.log('orororo', originTreeData)
if ( if (
(item.categoryLevel === 0 && originTreeData.length >= 29) || (item.categoryLevel === 0 && originTreeData.length >= 29) ||
(item.categoryLevel > 0 && (item.categoryLevel > 0 && this.getRelatedNodes(item.parentId).length >= 30)
this.getRelatedNodes(item.parentId).length >= 30)
) { ) {
return message.info("最多只能添加30个分类"); return message.info('最多只能添加30个分类')
} }
this.newEditCourseCategory( this.newEditCourseCategory('newEqualLevelCategory', 'equal', 'new', item)
"newEqualLevelCategory", }}>
"equal", <span className='icon iconfont' style={{ color: '#BFBFBF' }}>
"new", &#xe7f5;{' '}
item
);
}}
>
<span className="icon iconfont" style={{ color: "#BFBFBF" }}>
&#xe7f5;{" "}
</span> </span>
<span>同级</span> <span>同级</span>
</span> </span>
{item.categoryLevel < 4 && ( {item.categoryLevel < 4 && (
<span <span
onClick={() => { onClick={() => {
if ( if (this.getRelatedNodes(item.id) && this.getRelatedNodes(item.id).length >= 30) {
this.getRelatedNodes(item.id) && message.info('最多只能添加30个子分类')
this.getRelatedNodes(item.id).length >= 30 return
) { }
message.info("最多只能添加30个子分类"); this.newEditCourseCategory('newChildLevelCategory', 'child', 'new', item)
return; }}>
} <span className='icon iconfont' style={{ color: '#BFBFBF' }}>
this.newEditCourseCategory( &#xe7f8;{' '}
"newChildLevelCategory",
"child",
"new",
item
);
}}
>
<span className="icon iconfont" style={{ color: "#BFBFBF" }}>
&#xe7f8;{" "}
</span> </span>
<span>子级</span> <span>子级</span>
</span> </span>
)} )}
<Dropdown overlay={this.initDropMenu(item)}> <Dropdown overlay={this.initDropMenu(item)}>
<span> <span>
<span className="icon iconfont" style={{ color: "#BFBFBF" }}> <span className='icon iconfont' style={{ color: '#BFBFBF' }}>
&#xe7f7;{" "} &#xe7f7;{' '}
</span> </span>
<span>更多</span> <span>更多</span>
</span> </span>
...@@ -224,77 +195,71 @@ class CourseCategoryManage extends Component { ...@@ -224,77 +195,71 @@ class CourseCategoryManage extends Component {
</Space> </Space>
)} )}
</div> </div>
); )
item.icon = item.icon =
item.categoryName === "未分类" ? ( item.categoryName === '未分类' ? (
<img <img
style={{ style={{
width: "24px", width: '24px',
height: "24px", height: '24px',
opacity: opacity: !value || (value && item.categoryName.indexOf(value) > -1) ? 1 : 0.5
!value || (value && item.categoryName.indexOf(value) > -1)
? 1
: 0.5,
}} }}
src="https://image.xiaomaiketang.com/xm/defaultCategory.png" src='https://image.xiaomaiketang.com/xm/defaultCategory.png'
alt="" alt=''
/> />
) : ( ) : (
<img <img
style={{ style={{
width: "24px", width: '24px',
height: "24px", height: '24px',
opacity: opacity: !value || (value && item.categoryName.indexOf(value) > -1) ? 1 : 0.5
!value || (value && item.categoryName.indexOf(value) > -1)
? 1
: 0.5,
}} }}
src="https://image.xiaomaiketang.com/xm/hasCategory.png" src='https://image.xiaomaiketang.com/xm/hasCategory.png'
alt="" alt=''
/> />
); )
if (item.sonCategoryList) { if (item.sonCategoryList) {
item.children = this.renderTreeNodes(item.sonCategoryList, value); item.children = this.renderTreeNodes(item.sonCategoryList, value)
}
return item
})
return newTreeData
} }
return item;
});
return newTreeData;
};
// 树结构平铺 // 树结构平铺
getTreeMap = (data, map) => { getTreeMap = (data, map) => {
data.forEach((item) => { data.forEach((item) => {
map[item.id] = item; map[item.id] = item
if (item.sonCategoryList && item.sonCategoryList.length > 0) { if (item.sonCategoryList && item.sonCategoryList.length > 0) {
this.getTreeMap(item.sonCategoryList, map); this.getTreeMap(item.sonCategoryList, map)
} }
}); })
return map; return map
}; }
// 新增或编辑分类 // 新增或编辑分类
newEditCourseCategory = (categoryType, addLevelType, type, node) => { newEditCourseCategory = (categoryType, addLevelType, type, node) => {
let title = ""; let title = ''
let label = ""; let label = ''
switch (categoryType) { switch (categoryType) {
case "newEqualLevelCategory": case 'newEqualLevelCategory':
title = "新增分类"; title = '新增分类'
label = "分类名称"; label = '分类名称'
break; break
case "newChildLevelCategory": case 'newChildLevelCategory':
title = "新增子分类"; title = '新增子分类'
label = "子分类名称"; label = '子分类名称'
break; break
case "editEqualLevelCategory": case 'editEqualLevelCategory':
title = "编辑分类"; title = '编辑分类'
label = "分类名称"; label = '分类名称'
break; break
case "editChildLevelCategory": case 'editChildLevelCategory':
title = "编辑子分类"; title = '编辑子分类'
label = "子分类名称"; label = '子分类名称'
break; break
} }
const m = ( const m = (
<OpearteCourseCategoryModal <OpearteCourseCategoryModal
...@@ -304,336 +269,273 @@ class CourseCategoryManage extends Component { ...@@ -304,336 +269,273 @@ class CourseCategoryManage extends Component {
title={title} title={title}
label={label} label={label}
close={() => { close={() => {
this.queryCategoryTree("remain", this.state.categoryName); this.queryCategoryTree('remain', this.state.categoryName)
this.setState({ this.setState({
operateCourseCategoryModal: null, operateCourseCategoryModal: null
}); })
}} }}
/> />
); )
this.setState({ operateCourseCategoryModal: m }); this.setState({ operateCourseCategoryModal: m })
}; }
// 删除分类 // 删除分类
delCategory = (item) => { delCategory = (item) => {
return confirm({ return confirm({
title: "确认删除该分类吗?", title: '确认删除该分类吗?',
content: "删除后,分类下的所有内容将自动转入“未分类”中。", content: '删除后,分类下的所有内容将自动转入“未分类”中。',
icon: ( icon: <span className='icon iconfont default-confirm-icon'>&#xe839; </span>,
<span className="icon iconfont default-confirm-icon">&#xe839; </span> okText: '删除',
), okType: 'danger',
okText: "删除", cancelText: '取消',
okType: "danger",
cancelText: "取消",
onOk: () => { onOk: () => {
let params = { let params = {
categoryId: item.id, categoryId: item.id,
source: 0, source: 0,
tenantId: User.getStoreId(), tenantId: User.getStoreId(),
userId: User.getStoreUserId(), userId: User.getStoreUserId()
}; }
AidToolService.delCategory(params).then((res) => { AidToolService.delCategory(params).then((res) => {
if (res.success) { if (res.success) {
message.success("删除分类成功"); message.success('删除分类成功')
this.queryCategoryTree("remain", this.state.categoryName); this.queryCategoryTree('remain', this.state.categoryName)
}
})
}
})
} }
});
},
});
};
// 更多操作-【重命名 删除】 // 更多操作-【重命名 删除】
initDropMenu = (item) => { initDropMenu = (item) => {
return ( return (
<Menu> <Menu>
<Menu.Item key="0"> <Menu.Item key='0'>
<span <span
onClick={() => { onClick={() => {
let categoryType = let categoryType = item.categoryLevel === 0 ? 'editEqualLevelCategory' : 'editChildLevelCategory'
item.categoryLevel === 0 this.newEditCourseCategory(categoryType, 'equal', 'edit', item)
? "editEqualLevelCategory" }}>
: "editChildLevelCategory";
this.newEditCourseCategory(categoryType, "equal", "edit", item);
}}
>
重命名 重命名
</span> </span>
</Menu.Item> </Menu.Item>
<Menu.Item key="1"> <Menu.Item key='1'>
<span <span
onClick={() => { onClick={() => {
this.delCategory(item); this.delCategory(item)
}} }}>
>
删除 删除
</span> </span>
</Menu.Item> </Menu.Item>
</Menu> </Menu>
); )
}; }
// 获取相关节点 // 获取相关节点
getRelatedNodes = (parentId) => { getRelatedNodes = (parentId) => {
return this.state.treeMap[parentId] return this.state.treeMap[parentId] ? this.state.treeMap[parentId].sonCategoryList : []
? this.state.treeMap[parentId].sonCategoryList }
: [];
};
// 获取拖拽目标父节点层级 // 获取拖拽目标父节点层级
getParentDragNodesLevel = (dragNode) => { getParentDragNodesLevel = (dragNode) => {
if (!dragNode) { if (!dragNode) {
return []; return []
} }
let dragNodes = []; let dragNodes = []
dragNodes.push(dragNode.id); dragNodes.push(dragNode.id)
if (dragNode.parentId != 0) { if (dragNode.parentId != 0) {
dragNodes = dragNodes.concat( dragNodes = dragNodes.concat(this.getParentDragNodesLevel(this.state.treeMap[dragNode.parentId]))
this.getParentDragNodesLevel(this.state.treeMap[dragNode.parentId]) }
); return dragNodes
} }
return dragNodes;
};
// 获取拖拽节点层级 // 获取拖拽节点层级
getDragNodesLevel = (dragNode) => { getDragNodesLevel = (dragNode) => {
let dragNodes = []; let dragNodes = []
if (dragNode.sonCategoryList && dragNode.sonCategoryList.length > 0) { if (dragNode.sonCategoryList && dragNode.sonCategoryList.length > 0) {
dragNode.sonCategoryList.forEach((item) => { dragNode.sonCategoryList.forEach((item) => {
dragNodes.push(item.categoryLevel); dragNodes.push(item.categoryLevel)
if (item.sonCategoryList && item.sonCategoryList.length > 0) { if (item.sonCategoryList && item.sonCategoryList.length > 0) {
dragNodes = dragNodes.concat(this.getDragNodesLevel(item)); dragNodes = dragNodes.concat(this.getDragNodesLevel(item))
} }
}); })
}
return [...new Set(dragNodes)]
} }
return [...new Set(dragNodes)];
};
// 拖拽 // 拖拽
onDrop = (info) => { onDrop = (info) => {
if (this.state.categoryName) { if (this.state.categoryName) {
return; return
} }
// 未分类不可以拖拽 // 未分类不可以拖拽
if ( if (info.dragNode.categoryName === '未分类' && info.dragNode.categoryLevel === 0) return message.info('未分类”为默认分类暂不支持移动')
info.dragNode.categoryName === "未分类" &&
info.dragNode.categoryLevel === 0
)
return message.info("未分类”为默认分类暂不支持移动");
// 不允许其他节点拖拽到未分类之前 // 不允许其他节点拖拽到未分类之前
if ( if (info.node.categoryName === '未分类' && info.dropToGap && info.dropPosition === -1) return
info.node.categoryName === "未分类" &&
info.dropToGap &&
info.dropPosition === -1
)
return;
let targetParentId = info.dropToGap ? info.node.parentId : info.node.id; let targetParentId = info.dropToGap ? info.node.parentId : info.node.id
let relatedNodes = this.getRelatedNodes(targetParentId); let relatedNodes = this.getRelatedNodes(targetParentId)
if ( if (!((info.dropToGap && info.node.parentId === info.dragNode.parentId) || (!info.dropToGap && info.node.id === info.dragNode.parentId))) {
!(
(info.dropToGap && info.node.parentId === info.dragNode.parentId) ||
(!info.dropToGap && info.node.id === info.dragNode.parentId)
)
) {
if (this.state.treeMap[targetParentId].categoryLevel === 4) { if (this.state.treeMap[targetParentId].categoryLevel === 4) {
return message.info("最多支持5级分类"); return message.info('最多支持5级分类')
} else { } else {
let nodesArr = this.getDragNodesLevel( let nodesArr = this.getDragNodesLevel(this.state.treeMap[info.dragNode.id])
this.state.treeMap[info.dragNode.id] let parentArr = this.getParentDragNodesLevel(this.state.treeMap[targetParentId])
);
let parentArr = this.getParentDragNodesLevel(
this.state.treeMap[targetParentId]
);
if (nodesArr.length + parentArr.length > 4) { if (nodesArr.length + parentArr.length > 4) {
console.log(nodesArr.length, parentArr.length); console.log(nodesArr.length, parentArr.length)
return message.info("最多支持5级分类"); return message.info('最多支持5级分类')
} }
} }
if (relatedNodes && relatedNodes.length >= 30) { if (relatedNodes && relatedNodes.length >= 30) {
return message.info("最多只能添加30个分类"); return message.info('最多只能添加30个分类')
} }
} }
const dropKey = info.node.key; const dropKey = info.node.key
const dragKey = info.dragNode.key; const dragKey = info.dragNode.key
const dropPos = info.node.pos.split("-"); const dropPos = info.node.pos.split('-')
const dropPosition = const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1])
info.dropPosition - Number(dropPos[dropPos.length - 1]);
const loop = (data, key, callback) => { const loop = (data, key, callback) => {
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
if (data[i].key === key) { if (data[i].key === key) {
return callback(data[i], i, data); return callback(data[i], i, data)
} }
if (data[i].sonCategoryList) { if (data[i].sonCategoryList) {
loop(data[i].sonCategoryList, key, callback); loop(data[i].sonCategoryList, key, callback)
}
} }
} }
}; const data = [...this.state.treeData]
const data = [...this.state.treeData];
let getSuf = function (name, originCategoryName, sufIndex) { let getSuf = function (name, originCategoryName, sufIndex) {
if (relatedNodes && relatedNodes.length > 0) { if (relatedNodes && relatedNodes.length > 0) {
let sameNameNodes = []; let sameNameNodes = []
relatedNodes.forEach((item) => { relatedNodes.forEach((item) => {
if (item.id === info.dragNode.id) return true; if (item.id === info.dragNode.id) return true
if (item.categoryName === name) { if (item.categoryName === name) {
sameNameNodes.push(item); sameNameNodes.push(item)
} }
}); })
if (sameNameNodes.length > 0) { if (sameNameNodes.length > 0) {
sufIndex++; sufIndex++
return getSuf( return getSuf(originCategoryName + `(${sufIndex})`, originCategoryName, sufIndex)
originCategoryName + `(${sufIndex})`, }
originCategoryName,
sufIndex
);
} }
return sufIndex
} }
return sufIndex;
};
let dragObj; let dragObj
loop(data, dragKey, (item, index, arr) => { loop(data, dragKey, (item, index, arr) => {
arr.splice(index, 1); arr.splice(index, 1)
item.parentId = targetParentId; item.parentId = targetParentId
if (item.originCategoryName) { if (item.originCategoryName) {
item.categoryName = item.originCategoryName; item.categoryName = item.originCategoryName
} else { } else {
item.originCategoryName = item.categoryName; item.originCategoryName = item.categoryName
} }
info.dragNode.categoryName = item.originCategoryName; info.dragNode.categoryName = item.originCategoryName
let sufIndex = getSuf( let sufIndex = getSuf(info.dragNode.categoryName, item.originCategoryName, 0)
info.dragNode.categoryName, item.categoryName = item.categoryName + (sufIndex ? `(${sufIndex})` : '')
item.originCategoryName, item.categoryName = item.originCategoryName + (sufIndex ? `(${sufIndex})` : '')
0 dragObj = item
); })
item.categoryName = item.categoryName + (sufIndex ? `(${sufIndex})` : "");
item.categoryName =
item.originCategoryName + (sufIndex ? `(${sufIndex})` : "");
dragObj = item;
});
if (!info.dropToGap) { if (!info.dropToGap) {
loop(data, dropKey, (item) => { loop(data, dropKey, (item) => {
item.sonCategoryList = item.sonCategoryList || []; item.sonCategoryList = item.sonCategoryList || []
item.sonCategoryList.unshift(dragObj); item.sonCategoryList.unshift(dragObj)
}); })
} else if ( } else if ((info.node.props.sonCategoryList || []).length > 0 && info.node.props.expanded && dropPosition === 1) {
(info.node.props.sonCategoryList || []).length > 0 &&
info.node.props.expanded &&
dropPosition === 1
) {
loop(data, dropKey, (item) => { loop(data, dropKey, (item) => {
item.sonCategoryList = item.children || []; item.sonCategoryList = item.children || []
item.sonCategoryList.unshift(dragObj); item.sonCategoryList.unshift(dragObj)
}); })
} else { } else {
let ar; let ar
let i; let i
loop(data, dropKey, (item, index, arr) => { loop(data, dropKey, (item, index, arr) => {
ar = arr; ar = arr
i = index; i = index
}); })
if (dropPosition === -1) { if (dropPosition === -1) {
ar.splice(i, 0, dragObj); ar.splice(i, 0, dragObj)
} else { } else {
ar.splice(i + 1, 0, dragObj); ar.splice(i + 1, 0, dragObj)
} }
} }
data.shift(); data.shift()
let newTreeData = this.renderTreeNodes(this.handleLoop(data, 0)); let newTreeData = this.renderTreeNodes(this.handleLoop(data, 0))
this.setState({ treeData: newTreeData }); this.setState({ treeData: newTreeData })
let params = { let params = {
categoryList: newTreeData, categoryList: newTreeData,
source: 0, source: 0,
tenantId: User.getStoreId(), tenantId: User.getStoreId(),
userId: User.getStoreUserId(), userId: User.getStoreUserId()
}; }
AidToolService.editCategoryTree(params).then((res) => { AidToolService.editCategoryTree(params).then((res) => {
this.queryCategoryTree("remain"); this.queryCategoryTree('remain')
}); })
}; }
handleLoop = (data, level) => { handleLoop = (data, level) => {
data.map((item, index) => { data.map((item, index) => {
item.sort = index; item.sort = index
item.categoryLevel = level; item.categoryLevel = level
if (item.sonCategoryList) { if (item.sonCategoryList) {
item.children = this.handleLoop(item.sonCategoryList, level + 1); item.children = this.handleLoop(item.sonCategoryList, level + 1)
item.sonCategoryList = this.handleLoop(item.sonCategoryList, level + 1); item.sonCategoryList = this.handleLoop(item.sonCategoryList, level + 1)
}
return item
})
return data
} }
return item;
});
return data;
};
// 树状展开事件 // 树状展开事件
onExpand = (expandedKeys) => { onExpand = (expandedKeys) => {
this.setState({ expandedKeys }); this.setState({ expandedKeys })
}; }
// 树状选中事件 // 树状选中事件
onSelect = (selectedKeys) => { onSelect = (selectedKeys) => {
this.setState({ selectedKeys }); this.setState({ selectedKeys })
}; }
render() { render() {
const { const { treeData, originTreeData, expandedKeys, selectedKeys, autoExpandParent, operateCourseCategoryModal } = this.state
treeData,
originTreeData,
expandedKeys,
selectedKeys,
autoExpandParent,
operateCourseCategoryModal,
} = this.state;
return ( return (
<div className="page course-category-manage"> <div className='page course-category-manage'>
{["aid", "knowledge"].includes(getParameterByName("from")) ? ( {['aid', 'knowledge'].includes(getParameterByName('from')) ? (
<Breadcrumbs <Breadcrumbs navList='课程分类' goBack={() => window.RCHistory.goBack()} />
navList="课程分类"
goBack={() =>
window.RCHistory.goBack()
}
/>
) : ( ) : (
<div className="content-header">课程分类</div> <div className='content-header'>课程分类</div>
)} )}
<div className="box"> <div className='box'>
<div className="search-condition"> <div className='search-condition'>
<span className="search-label">搜索名称:</span> <span className='search-label'>搜索名称:</span>
<Search <Search
placeholder="请输入名称" placeholder='请输入名称'
style={{ width: "300px" }} style={{ width: '300px' }}
onSearch={(value) => this.queryCategoryTree("init", value)} onSearch={(value) => this.queryCategoryTree('init', value)}
className="search-input" className='search-input'
enterButton={<span className="icon iconfont">&#xe832;</span>} enterButton={<span className='icon iconfont'>&#xe832;</span>}
/> />
</div> </div>
<Button <Button
type="primary" type='primary'
onClick={() => { onClick={() => {
if (originTreeData.length >= 29) { if (originTreeData.length >= 29) {
message.info("最多只能添加30个分类"); message.info('最多只能添加30个分类')
return; return
} }
this.newEditCourseCategory( this.newEditCourseCategory('newEqualLevelCategory', 'equal', 'new')
"newEqualLevelCategory", }}>
"equal",
"new"
);
}}
>
新增一级分类 新增一级分类
</Button> </Button>
<div <div className='show-tips' style={{ marginTop: '12px', width: '900px' }}>
className="show-tips" <ShowTips message='为方便管理,该分类用于课程、培训计划、题库、知识库等模块,改动将同步各模块更新' />
style={{ marginTop: "12px", width: "900px" }}
>
<ShowTips message="为方便管理,该分类用于课程、培训计划、题库、知识库等模块,改动将同步各模块更新" />
</div> </div>
<div className="course-category-tree"> <div className='course-category-tree'>
<DirectoryTree <DirectoryTree
expandedKeys={expandedKeys} expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent} autoExpandParent={autoExpandParent}
...@@ -643,14 +545,13 @@ class CourseCategoryManage extends Component { ...@@ -643,14 +545,13 @@ class CourseCategoryManage extends Component {
draggable draggable
blockNode blockNode
onDrop={this.onDrop} onDrop={this.onDrop}
treeData={treeData} treeData={treeData}></DirectoryTree>
></DirectoryTree>
</div> </div>
</div> </div>
{operateCourseCategoryModal} {operateCourseCategoryModal}
</div> </div>
); )
} }
} }
export default CourseCategoryManage; export default CourseCategoryManage
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment